Exemple #1
0
  @Override
  protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)
      throws Exception {
    // wait for prefix
    if (buffer.readableBytes() < 4) {
      return null;
    }

    int length = buffer.getInt(buffer.readerIndex());
    // wait for the complete event
    if (buffer.readableBytes() < length + 4) {
      return null;
    }

    // skip package length header
    buffer.skipBytes(4);
    // decode
    int typeLength = buffer.readInt();
    String type = buffer.toString(buffer.readerIndex(), typeLength, "UTF-8");
    int eventLength = length - typeLength;
    byte[] eventBytes = new byte[eventLength];
    buffer.skipBytes(typeLength);
    buffer.readBytes(eventBytes);
    return new Event(type, eventBytes);
  }
  @Override
  protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg)
      throws Exception {

    ChannelBuffer buf = (ChannelBuffer) msg;

    prefix = buf.toString(buf.readerIndex(), 4, CHARSET);
    buf.skipBytes(prefix.length()); // prefix @NTC by default
    serverId = buf.readUnsignedInt();
    deviceUniqueId = buf.readUnsignedInt();
    int length = buf.readUnsignedShort();
    buf.skipBytes(2); // header and data XOR checksum

    if (length == 0) {
      return null; // keep alive message
    }

    String type = buf.toString(buf.readerIndex(), 3, CHARSET);
    buf.skipBytes(type.length());

    switch (type) {
      case "*>T":
        return processSingle(channel, buf);
      case "*>A":
        return processArray(channel, buf);
      case "*>S":
        return processHandshake(channel, buf);
      default:
        Log.warning(new UnsupportedOperationException(type));
        break;
    }

    return null;
  }
  /**
   * Returns Linked list of optional tlvs.
   *
   * @param cb of channel buffer.
   * @return list of optional tlvs
   * @throws PcepParseException when unsupported tlv is received
   */
  protected static LinkedList<PcepValueType> parseOptionalTlv(ChannelBuffer cb)
      throws PcepParseException {

    LinkedList<PcepValueType> llOutOptionalTlv;

    llOutOptionalTlv = new LinkedList<>();

    while (MINIMUM_COMMON_HEADER_LENGTH <= cb.readableBytes()) {

      PcepValueType tlv = null;
      short hType = cb.readShort();
      short hLength = cb.readShort();
      int iValue = 0;

      switch (hType) {
        case StatefulIPv4LspIdentifiersTlv.TYPE:
          tlv = StatefulIPv4LspIdentifiersTlv.read(cb);
          break;
        case StatefulLspErrorCodeTlv.TYPE:
          iValue = cb.readInt();
          tlv = new StatefulLspErrorCodeTlv(iValue);
          break;
        case StatefulRsvpErrorSpecTlv.TYPE:
          tlv = StatefulRsvpErrorSpecTlv.read(cb);
          break;
        case SymbolicPathNameTlv.TYPE:
          tlv = SymbolicPathNameTlv.read(cb, hLength);
          break;
        case StatefulLspDbVerTlv.TYPE:
          tlv = StatefulLspDbVerTlv.read(cb);
          break;
        default:
          // Skip the unknown TLV.
          cb.skipBytes(hLength);
          tlv = null;
          log.info("Received unsupported TLV type :" + hType + " in LSP object.");
      }
      // Check for the padding
      int pad = hLength % 4;
      if (0 < pad) {
        pad = 4 - pad;
        if (pad <= cb.readableBytes()) {
          cb.skipBytes(pad);
        }
      }

      if (tlv != null) {
        llOutOptionalTlv.add(tlv);
      }
    }

    if (0 < cb.readableBytes()) {

      throw new PcepParseException("Optional Tlv parsing error. Extra bytes received.");
    }
    return llOutOptionalTlv;
  }
 @Override
 protected Object decode(
     ChannelHandlerContext chtx, Channel chan, ChannelBuffer in, AuthenticationStage state)
     throws Exception {
   switch (state) {
     case VALIDATION:
       int bytesLeft = readableBytes(in);
       if (bytesLeft >= 3) {
         int type = in.readUnsignedByte();
         int size = in.readUnsignedShort();
         if (size != readableBytes(in)) {
           throw new Exception("Mismatched login packet size.");
         }
         int version = in.readInt();
         if (version != 614) {
           throw new Exception("Incorrect revision read");
         }
         if (type == 16 || type == 18) {
           checkpoint(AuthenticationStage.DETAILS);
         }
       }
       break;
     case DETAILS:
       in.readUnsignedByte();
       int mode = in.readUnsignedByte();
       in.readUnsignedShort();
       in.readUnsignedShort();
       in.readUnsignedByte();
       in.skipBytes(24);
       readRS2String(in); // macaddress!
       in.readInt();
       int size = in.readUnsignedByte();
       in.skipBytes(size);
       in.skipBytes(6 + (33 * 4) + 8 + 2 + 14);
       if (in.readUnsignedByte() != 10) {
         throw new Exception("Invalid RSA header.");
       }
       in.readLong();
       in.readLong();
       long l = in.readLong();
       String name = longToString(l);
       String password = readRS2String(in);
       int left = readableBytes(in);
       in.skipBytes(left);
       return new LoginRequest(chan, chtx, name, password, mode);
   }
   return null;
 }
 private void decodeEventData(int event, ChannelBuffer buf) {
   switch (event) {
     case 2:
     case 40:
       buf.readUnsignedByte();
       break;
     case 9:
       buf.readUnsignedMedium();
       break;
     case 31:
     case 32:
       buf.readUnsignedShort();
       break;
     case 38:
       buf.skipBytes(4 * 9);
       break;
     case 113:
       buf.readUnsignedInt();
       buf.readUnsignedByte();
       break;
     case 121:
     case 142:
       buf.readLong();
       break;
     case 130:
       buf.readUnsignedInt(); // incorrect
       break;
     default:
       break;
   }
 }
    @Override
    public OFActionSetField readFrom(ChannelBuffer bb) throws OFParseError {
      int start = bb.readerIndex();
      // fixed value property type == 25
      short type = bb.readShort();
      if (type != (short) 0x19)
        throw new OFParseError("Wrong type: Expected=OFActionType.SET_FIELD(25), got=" + type);
      int length = U16.f(bb.readShort());
      if (length < MINIMUM_LENGTH)
        throw new OFParseError(
            "Wrong length: Expected to be >= " + MINIMUM_LENGTH + ", was: " + length);
      if (bb.readableBytes() + (bb.readerIndex() - start) < length) {
        // Buffer does not have all data yet
        bb.readerIndex(start);
        return null;
      }
      if (logger.isTraceEnabled()) logger.trace("readFrom - length={}", length);
      OFOxm<?> field = OFOxmVer12.READER.readFrom(bb);
      // align message to 8 bytes (length contains aligned value)
      bb.skipBytes(length - (bb.readerIndex() - start));

      OFActionSetFieldVer12 actionSetFieldVer12 = new OFActionSetFieldVer12(field);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", actionSetFieldVer12);
      return actionSetFieldVer12;
    }
  @Override
  protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf)
      throws Exception {

    char marker = (char) buf.getByte(buf.readerIndex());

    while (marker != '*' && marker != '$' && buf.readableBytes() > 0) {
      buf.skipBytes(1);
      if (buf.readableBytes() > 0) {
        marker = (char) buf.getByte(buf.readerIndex());
      }
    }

    if (marker == '*') {

      // Return text message
      int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '#');
      if (index != -1) {
        return buf.readBytes(index + 1 - buf.readerIndex());
      }

    } else if (marker == '$' && buf.readableBytes() >= MESSAGE_LENGTH) {

      // Return binary message
      return buf.readBytes(MESSAGE_LENGTH);
    }

    return null;
  }
  /**
   * Returns linked list of sub objects.
   *
   * @param cb of type channel buffer
   * @return linked list of sub objects
   * @throws PcepParseException while parsing subobjects from channel buffer
   */
  protected static LinkedList<PcepValueType> parseSubObjects(ChannelBuffer cb)
      throws PcepParseException {

    LinkedList<PcepValueType> llSubObjects = new LinkedList<PcepValueType>();

    while (0 < cb.readableBytes()) {

      // check the Type of the Subobjects.
      byte yType = cb.readByte();
      yType = (byte) (yType & (YTYPE_SHIFT_VALUE));
      byte hLength = cb.readByte();

      PcepValueType subObj;
      switch (yType) {
        case IPv4SubObject.TYPE:
          subObj = IPv4SubObject.read(cb);
          break;

        default:
          throw new PcepParseException("Invalid sub object. Type: " + (int) yType);
      }

      // Check for the padding
      int pad = hLength % 4;
      if (0 < pad) {
        pad = 4 - pad;
        if (pad <= cb.readableBytes()) {
          cb.skipBytes(pad);
        }
      }
      llSubObjects.add(subObj);
    }
    return llSubObjects;
  }
    @Override
    public OFMatchV3 readFrom(ChannelBuffer bb) throws OFParseError {
      int start = bb.readerIndex();
      // fixed value property type == 0x1
      short type = bb.readShort();
      if (type != (short) 0x1) throw new OFParseError("Wrong type: Expected=0x1(0x1), got=" + type);
      int length = U16.f(bb.readShort());
      if (length < MINIMUM_LENGTH)
        throw new OFParseError(
            "Wrong length: Expected to be >= " + MINIMUM_LENGTH + ", was: " + length);
      if (bb.readableBytes() + (bb.readerIndex() - start) < length) {
        // Buffer does not have all data yet
        bb.readerIndex(start);
        return null;
      }
      if (logger.isTraceEnabled()) logger.trace("readFrom - length={}", length);
      OFOxmList oxmList =
          OFOxmList.readFrom(bb, length - (bb.readerIndex() - start), OFOxmVer14.READER);
      // align message to 8 bytes (length does not contain alignment)
      bb.skipBytes(((length + 7) / 8 * 8) - length);

      OFMatchV3Ver14 matchV3Ver14 = new OFMatchV3Ver14(oxmList);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", matchV3Ver14);
      return matchV3Ver14;
    }
  /**
   * Handles a received {@link MBeanServerConnection} invocation
   *
   * @param channel The channel the request was received on
   * @param remoteAddress The remote address of the caller
   * @param buffer THe buffer received
   */
  public static void handleJMXRequest(
      Channel channel, SocketAddress remoteAddress, ChannelBuffer buffer) {
    buffer.resetReaderIndex();
    /* The request write */
    //		cb.writeByte(OpCode.JMX_REQUEST.op());  // 1
    //		cb.writeBytes(domainInfoData);   // domain data
    //		cb.writeInt(reqId);					// 4
    //		cb.writeByte(methodToKey.get(method)); // 1
    //		cb.writeInt(sargs.length);  			// 4
    //		cb.writeBytes(sargs);		           // sargs.length
    Object result = null;
    MBeanServerConnection server = null;
    buffer.skipBytes(1);
    byte domainIndicator = buffer.readByte();
    if (domainIndicator == 0) {
      server = JMXHelper.getHeliosMBeanServer();
    } else {
      byte[] domainBytes = new byte[domainIndicator];
      buffer.readBytes(domainBytes);
      String domain = new String(domainBytes);
      server = JMXHelper.getLocalMBeanServer(true, domain);
      if (server == null) {
        result = new SmallException("Failed to locate MBeanServer for domain [" + domain + "]");
      }
    }
    int reqId = buffer.readInt();
    byte methodId = buffer.readByte();
    if (result == null) {
      int payloadSize = buffer.readInt();
      byte[] payload = new byte[payloadSize];
      buffer.readBytes(payload);
      Object[] params = getInput(payload);
      Method targetMethod = null;
      try {
        targetMethod = keyToMethod.get(methodId);
        if (targetMethod == null) {
          result =
              new SmallException(
                  "Failed to handle MBeanServerConnection invocation because method Op Code ["
                      + methodId
                      + "] was not recognized");
        } else {
          if ("addNotificationListener".equals(targetMethod.getName())
              && !targetMethod.getParameterTypes()[1].equals(ObjectName.class)) {

          } else if ("removeNotificationListener".equals(targetMethod.getName())
              && !targetMethod.getParameterTypes()[1].equals(ObjectName.class)) {

          } else {
            result = targetMethod.invoke(server, params);
          }
        }
      } catch (Throwable t) {
        SimpleLogger.warn("Failed to invoke [", targetMethod, "]", t);
        result = new SmallException(t.toString());
      }
    }
    writeJMXResponse(reqId, methodId, channel, remoteAddress, result);
  }
  @Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
    if (handshakeComplete) {
      super.messageReceived(ctx, e);
    } else {
      if (e.getMessage() instanceof ChannelBuffer) {
        ChannelBuffer newBuffer = (ChannelBuffer) e.getMessage();
        buffered = ChannelBuffers.copiedBuffer(buffered, newBuffer);

        if (buffered.readableBytes() < 8) {
          return;
        }
        int payloadLength = buffered.getInt(0);
        int revision = buffered.getInt(4);

        boolean handshakeSuccessful = false;

        if (revision == 1 || revision == -1) {
          if (buffered.readableBytes() < payloadLength + 4) {
            return;
          }
          buffered.skipBytes(8);

          if (revision == 1) {
            handshakeSuccessful = handleRevision1Response(ctx, payloadLength);
          } else {
            handshakeSuccessful = handleGenericResponse(ctx, payloadLength);
          }
        } else {
          handshakeSuccessful = handleUnknownRevisionResponse(ctx);
        }

        if (!handshakeSuccessful) {
          ctx.getChannel().close();
        }

        if (keepAliveInterval.millis() > 0) {
          ctx.getPipeline()
              .addBefore(
                  ctx.getName(),
                  "found-connection-keep-alive",
                  new ConnectionKeepAliveHandler(scheduler, keepAliveInterval));
        }

        handshakeComplete = true;

        ChannelBuffer remaining = buffered.slice();
        if (remaining.readableBytes() > 0) {
          ctx.sendUpstream(
              new UpstreamMessageEvent(
                  ctx.getChannel(), remaining, ctx.getChannel().getRemoteAddress()));
        }

        ctx.getPipeline().remove(this);
      }
    }
  }
  /**
   * Reads the channel buffer and returns object of NodeAttributesTlv.
   *
   * @param c input channel buffer
   * @param hLength length
   * @return object of NodeAttributesTlv
   * @throws PcepParseException if mandatory fields are missing
   */
  public static PcepValueType read(ChannelBuffer c, short hLength) throws PcepParseException {

    // Node Descriptor Sub-TLVs (variable)
    List<PcepValueType> llNodeAttributesSubTLVs = new LinkedList<>();

    ChannelBuffer tempCb = c.readBytes(hLength);

    while (TLV_HEADER_LENGTH <= tempCb.readableBytes()) {
      PcepValueType tlv;
      short hType = tempCb.readShort();
      int iValue = 0;
      short length = tempCb.readShort();
      switch (hType) {
        case NodeFlagBitsSubTlv.TYPE:
          byte cValue = tempCb.readByte();
          tlv = new NodeFlagBitsSubTlv(cValue);
          break;
        case OpaqueNodePropertiesSubTlv.TYPE:
          tlv = OpaqueNodePropertiesSubTlv.read(tempCb, length);
          break;
        case NodeNameSubTlv.TYPE:
          tlv = NodeNameSubTlv.read(tempCb, length);
          break;
        case IsisAreaIdentifierSubTlv.TYPE:
          tlv = IsisAreaIdentifierSubTlv.read(tempCb, length);
          break;
        case IPv4RouterIdOfLocalNodeSubTlv.TYPE:
          iValue = tempCb.readInt();
          tlv = new IPv4RouterIdOfLocalNodeSubTlv(iValue);
          break;
        case IPv6RouterIdofLocalNodeSubTlv.TYPE:
          byte[] ipv6Value = new byte[IPv6RouterIdofLocalNodeSubTlv.VALUE_LENGTH];
          tempCb.readBytes(ipv6Value, 0, IPv6RouterIdofLocalNodeSubTlv.VALUE_LENGTH);
          tlv = new IPv6RouterIdofLocalNodeSubTlv(ipv6Value);
          break;
        default:
          throw new PcepParseException("Unsupported Sub TLV type :" + hType);
      }

      // Check for the padding
      int pad = length % 4;
      if (0 < pad) {
        pad = 4 - pad;
        if (pad <= tempCb.readableBytes()) {
          tempCb.skipBytes(pad);
        }
      }

      llNodeAttributesSubTLVs.add(tlv);
    }

    if (0 < tempCb.readableBytes()) {

      throw new PcepParseException("Sub Tlv parsing error. Extra bytes received.");
    }
    return new NodeAttributesTlv(llNodeAttributesSubTLVs);
  }
Exemple #13
0
  /**
   * Returns Linked list of PCEP Value Type.
   *
   * @param cb of channel buffer
   * @return Linked list of PCEP Value Type
   * @throws PcepParseException if mandatory fields are missing
   */
  protected static LinkedList<PcepValueType> parseOptionalTlv(ChannelBuffer cb)
      throws PcepParseException {

    LinkedList<PcepValueType> llOutOptionalTlv;

    llOutOptionalTlv = new LinkedList<PcepValueType>();

    while (MINIMUM_TLV_HEADER_LENGTH <= cb.readableBytes()) {

      PcepValueType tlv;
      short hType = cb.readShort();
      short hLength = cb.readShort();
      long lValue = 0;

      switch (hType) {
        case RoutingUniverseTlv.TYPE:
          lValue = cb.readLong();
          tlv = new RoutingUniverseTlv(lValue);
          break;
        case LocalTENodeDescriptorsTlv.TYPE:
          tlv = LocalTENodeDescriptorsTlv.read(cb, hLength);
          break;
        case RemoteTENodeDescriptorsTlv.TYPE:
          tlv = RemoteTENodeDescriptorsTlv.read(cb, hLength);
          break;
        case TELinkDescriptorsTlv.TYPE:
          tlv = TELinkDescriptorsTlv.read(cb, hLength);
          break;
        case TENodeAttributesTlv.TYPE:
          tlv = TENodeAttributesTlv.read(cb, hLength);
          break;
        case TELinkAttributesTlv.TYPE:
          tlv = TELinkAttributesTlv.read(cb, hLength);
          break;
        default:
          throw new PcepParseException("Unsupported TLV type :" + hType);
      }

      // Check for the padding
      int pad = hLength % 4;
      if (0 < pad) {
        pad = 4 - pad;
        if (pad <= cb.readableBytes()) {
          cb.skipBytes(pad);
        }
      }

      llOutOptionalTlv.add(tlv);
    }

    if (0 < cb.readableBytes()) {

      throw new PcepParseException("Optional Tlv parsing error. Extra bytes received.");
    }
    return llOutOptionalTlv;
  }
    @Override
    public OFGroupFeaturesStatsReply readFrom(ChannelBuffer bb) throws OFParseError {
      int start = bb.readerIndex();
      // fixed value property version == 3
      byte version = bb.readByte();
      if (version != (byte) 0x3)
        throw new OFParseError("Wrong version: Expected=OFVersion.OF_12(3), got=" + version);
      // fixed value property type == 19
      byte type = bb.readByte();
      if (type != (byte) 0x13)
        throw new OFParseError("Wrong type: Expected=OFType.STATS_REPLY(19), got=" + type);
      int length = U16.f(bb.readShort());
      if (length != 56) throw new OFParseError("Wrong length: Expected=56(56), got=" + length);
      if (bb.readableBytes() + (bb.readerIndex() - start) < length) {
        // Buffer does not have all data yet
        bb.readerIndex(start);
        return null;
      }
      if (logger.isTraceEnabled()) logger.trace("readFrom - length={}", length);
      long xid = U32.f(bb.readInt());
      // fixed value property statsType == 8
      short statsType = bb.readShort();
      if (statsType != (short) 0x8)
        throw new OFParseError(
            "Wrong statsType: Expected=OFStatsType.GROUP_FEATURES(8), got=" + statsType);
      Set<OFStatsReplyFlags> flags = OFStatsReplyFlagsSerializerVer12.readFrom(bb);
      // pad: 4 bytes
      bb.skipBytes(4);
      long types = U32.f(bb.readInt());
      long capabilities = U32.f(bb.readInt());
      long maxGroupsAll = U32.f(bb.readInt());
      long maxGroupsSelect = U32.f(bb.readInt());
      long maxGroupsIndirect = U32.f(bb.readInt());
      long maxGroupsFf = U32.f(bb.readInt());
      long actionsAll = U32.f(bb.readInt());
      long actionsSelect = U32.f(bb.readInt());
      long actionsIndirect = U32.f(bb.readInt());
      long actionsFf = U32.f(bb.readInt());

      OFGroupFeaturesStatsReplyVer12 groupFeaturesStatsReplyVer12 =
          new OFGroupFeaturesStatsReplyVer12(
              xid,
              flags,
              types,
              capabilities,
              maxGroupsAll,
              maxGroupsSelect,
              maxGroupsIndirect,
              maxGroupsFf,
              actionsAll,
              actionsSelect,
              actionsIndirect,
              actionsFf);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", groupFeaturesStatsReplyVer12);
      return groupFeaturesStatsReplyVer12;
    }
Exemple #15
0
 /**
  * Read a PeerAddress from a Netty buffer. I did not want to include ChannelBuffer in the class
  * PeerAddress
  *
  * @param buffer The Netty buffer
  * @return A PeerAddress created from the buffer (deserialized)
  */
 private static PeerAddress readPeerAddress(final ChannelBuffer buffer) {
   if (buffer.readableBytes() < 21) return null;
   Number160 id = readID(buffer);
   // peek
   int type = buffer.getUnsignedByte(buffer.readerIndex());
   // now we know the length
   int len = PeerAddress.expectedSocketLength(type);
   if (buffer.readableBytes() < len) return null;
   PeerAddress peerAddress =
       new PeerAddress(id, buffer.array(), buffer.arrayOffset() + buffer.readerIndex());
   buffer.skipBytes(len);
   return peerAddress;
 }
 /**
  * @return the next ChannelBuffer to send as a HttpChunk and modifying currentBuffer accordingly
  */
 private ChannelBuffer fillChannelBuffer() {
   int length = currentBuffer.readableBytes();
   if (length > HttpPostBodyUtil.chunkSize) {
     ChannelBuffer slice =
         currentBuffer.slice(currentBuffer.readerIndex(), HttpPostBodyUtil.chunkSize);
     currentBuffer.skipBytes(HttpPostBodyUtil.chunkSize);
     return slice;
   } else {
     // to continue
     ChannelBuffer slice = currentBuffer;
     currentBuffer = null;
     return slice;
   }
 }
    @Override
    public OFBsnGentableBucketStatsReply readFrom(ChannelBuffer bb) throws OFParseError {
      int start = bb.readerIndex();
      // fixed value property version == 4
      byte version = bb.readByte();
      if (version != (byte) 0x4)
        throw new OFParseError("Wrong version: Expected=OFVersion.OF_13(4), got=" + version);
      // fixed value property type == 19
      byte type = bb.readByte();
      if (type != (byte) 0x13)
        throw new OFParseError("Wrong type: Expected=OFType.STATS_REPLY(19), got=" + type);
      int length = U16.f(bb.readShort());
      if (length < MINIMUM_LENGTH)
        throw new OFParseError(
            "Wrong length: Expected to be >= " + MINIMUM_LENGTH + ", was: " + length);
      if (bb.readableBytes() + (bb.readerIndex() - start) < length) {
        // Buffer does not have all data yet
        bb.readerIndex(start);
        return null;
      }
      if (logger.isTraceEnabled()) logger.trace("readFrom - length={}", length);
      long xid = U32.f(bb.readInt());
      // fixed value property statsType == 65535
      short statsType = bb.readShort();
      if (statsType != (short) 0xffff)
        throw new OFParseError(
            "Wrong statsType: Expected=OFStatsType.EXPERIMENTER(65535), got=" + statsType);
      Set<OFStatsReplyFlags> flags = OFStatsReplyFlagsSerializerVer13.readFrom(bb);
      // pad: 4 bytes
      bb.skipBytes(4);
      // fixed value property experimenter == 0x5c16c7L
      int experimenter = bb.readInt();
      if (experimenter != 0x5c16c7)
        throw new OFParseError(
            "Wrong experimenter: Expected=0x5c16c7L(0x5c16c7L), got=" + experimenter);
      // fixed value property subtype == 0x5L
      int subtype = bb.readInt();
      if (subtype != 0x5)
        throw new OFParseError("Wrong subtype: Expected=0x5L(0x5L), got=" + subtype);
      List<OFBsnGentableBucketStatsEntry> entries =
          ChannelUtils.readList(
              bb, length - (bb.readerIndex() - start), OFBsnGentableBucketStatsEntryVer13.READER);

      OFBsnGentableBucketStatsReplyVer13 bsnGentableBucketStatsReplyVer13 =
          new OFBsnGentableBucketStatsReplyVer13(xid, flags, entries);
      if (logger.isTraceEnabled())
        logger.trace("readFrom - read={}", bsnGentableBucketStatsReplyVer13);
      return bsnGentableBucketStatsReplyVer13;
    }
    @Override
    public OFBsnImageDescStatsReply readFrom(ChannelBuffer bb) throws OFParseError {
      int start = bb.readerIndex();
      // fixed value property version == 5
      byte version = bb.readByte();
      if (version != (byte) 0x5)
        throw new OFParseError("Wrong version: Expected=OFVersion.OF_14(5), got=" + version);
      // fixed value property type == 19
      byte type = bb.readByte();
      if (type != (byte) 0x13)
        throw new OFParseError("Wrong type: Expected=OFType.STATS_REPLY(19), got=" + type);
      int length = U16.f(bb.readShort());
      if (length != 536) throw new OFParseError("Wrong length: Expected=536(536), got=" + length);
      if (bb.readableBytes() + (bb.readerIndex() - start) < length) {
        // Buffer does not have all data yet
        bb.readerIndex(start);
        return null;
      }
      if (logger.isTraceEnabled()) logger.trace("readFrom - length={}", length);
      long xid = U32.f(bb.readInt());
      // fixed value property statsType == 65535
      short statsType = bb.readShort();
      if (statsType != (short) 0xffff)
        throw new OFParseError(
            "Wrong statsType: Expected=OFStatsType.EXPERIMENTER(65535), got=" + statsType);
      Set<OFStatsReplyFlags> flags = OFStatsReplyFlagsSerializerVer14.readFrom(bb);
      // pad: 4 bytes
      bb.skipBytes(4);
      // fixed value property experimenter == 0x5c16c7L
      int experimenter = bb.readInt();
      if (experimenter != 0x5c16c7)
        throw new OFParseError(
            "Wrong experimenter: Expected=0x5c16c7L(0x5c16c7L), got=" + experimenter);
      // fixed value property subtype == 0xeL
      int subtype = bb.readInt();
      if (subtype != 0xe)
        throw new OFParseError("Wrong subtype: Expected=0xeL(0xeL), got=" + subtype);
      String imageChecksum = ChannelUtils.readFixedLengthString(bb, 256);
      String startupConfigChecksum = ChannelUtils.readFixedLengthString(bb, 256);

      OFBsnImageDescStatsReplyVer14 bsnImageDescStatsReplyVer14 =
          new OFBsnImageDescStatsReplyVer14(xid, flags, imageChecksum, startupConfigChecksum);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", bsnImageDescStatsReplyVer14);
      return bsnImageDescStatsReplyVer14;
    }
    @Override
    public OFBsnGentableDescStatsRequest readFrom(ChannelBuffer bb) throws OFParseError {
      int start = bb.readerIndex();
      // fixed value property version == 4
      byte version = bb.readByte();
      if (version != (byte) 0x4)
        throw new OFParseError("Wrong version: Expected=OFVersion.OF_13(4), got=" + version);
      // fixed value property type == 18
      byte type = bb.readByte();
      if (type != (byte) 0x12)
        throw new OFParseError("Wrong type: Expected=OFType.STATS_REQUEST(18), got=" + type);
      int length = U16.f(bb.readShort());
      if (length != 24) throw new OFParseError("Wrong length: Expected=24(24), got=" + length);
      if (bb.readableBytes() + (bb.readerIndex() - start) < length) {
        // Buffer does not have all data yet
        bb.readerIndex(start);
        return null;
      }
      if (logger.isTraceEnabled()) logger.trace("readFrom - length={}", length);
      long xid = U32.f(bb.readInt());
      // fixed value property statsType == 65535
      short statsType = bb.readShort();
      if (statsType != (short) 0xffff)
        throw new OFParseError(
            "Wrong statsType: Expected=OFStatsType.EXPERIMENTER(65535), got=" + statsType);
      Set<OFStatsRequestFlags> flags = OFStatsRequestFlagsSerializerVer13.readFrom(bb);
      // pad: 4 bytes
      bb.skipBytes(4);
      // fixed value property experimenter == 0x5c16c7L
      int experimenter = bb.readInt();
      if (experimenter != 0x5c16c7)
        throw new OFParseError(
            "Wrong experimenter: Expected=0x5c16c7L(0x5c16c7L), got=" + experimenter);
      // fixed value property subtype == 0x4L
      int subtype = bb.readInt();
      if (subtype != 0x4)
        throw new OFParseError("Wrong subtype: Expected=0x4L(0x4L), got=" + subtype);

      OFBsnGentableDescStatsRequestVer13 bsnGentableDescStatsRequestVer13 =
          new OFBsnGentableDescStatsRequestVer13(xid, flags);
      if (logger.isTraceEnabled())
        logger.trace("readFrom - read={}", bsnGentableDescStatsRequestVer13);
      return bsnGentableDescStatsRequestVer13;
    }
 /**
  * @param headerLength
  * @param middleLength
  * @param endLength
  * @param buf
  * @return the new EndTransferPacket from buffer
  * @throws OpenR66ProtocolPacketException
  */
 public static EndTransferPacket createFromBuffer(
     int headerLength, int middleLength, int endLength, ChannelBuffer buf)
     throws OpenR66ProtocolPacketException {
   if (headerLength - 1 != 1) {
     throw new OpenR66ProtocolPacketException("Not enough data");
   }
   if (middleLength != 1) {
     throw new OpenR66ProtocolPacketException("Not enough data");
   }
   final byte bheader = buf.readByte();
   byte valid = buf.readByte();
   String optional;
   if (endLength > 0) {
     optional = buf.toString(buf.readerIndex(), endLength, Charset.defaultCharset());
     buf.skipBytes(endLength);
     return new EndTransferPacket(bheader, valid, optional);
   }
   return new EndTransferPacket(bheader, valid);
 }
    @Override
    public OFBsnPduTxRequest readFrom(ChannelBuffer bb) throws OFParseError {
      int start = bb.readerIndex();
      // fixed value property version == 1
      byte version = bb.readByte();
      if (version != (byte) 0x1)
        throw new OFParseError("Wrong version: Expected=OFVersion.OF_10(1), got=" + version);
      // fixed value property type == 4
      byte type = bb.readByte();
      if (type != (byte) 0x4)
        throw new OFParseError("Wrong type: Expected=OFType.EXPERIMENTER(4), got=" + type);
      int length = U16.f(bb.readShort());
      if (length < MINIMUM_LENGTH)
        throw new OFParseError(
            "Wrong length: Expected to be >= " + MINIMUM_LENGTH + ", was: " + length);
      if (bb.readableBytes() + (bb.readerIndex() - start) < length) {
        // Buffer does not have all data yet
        bb.readerIndex(start);
        return null;
      }
      if (logger.isTraceEnabled()) logger.trace("readFrom - length={}", length);
      long xid = U32.f(bb.readInt());
      // fixed value property experimenter == 0x5c16c7L
      int experimenter = bb.readInt();
      if (experimenter != 0x5c16c7)
        throw new OFParseError(
            "Wrong experimenter: Expected=0x5c16c7L(0x5c16c7L), got=" + experimenter);
      // fixed value property subtype == 0x1fL
      int subtype = bb.readInt();
      if (subtype != 0x1f)
        throw new OFParseError("Wrong subtype: Expected=0x1fL(0x1fL), got=" + subtype);
      long txIntervalMs = U32.f(bb.readInt());
      OFPort portNo = OFPort.read2Bytes(bb);
      short slotNum = U8.f(bb.readByte());
      // pad: 3 bytes
      bb.skipBytes(3);
      byte[] data = ChannelUtils.readBytes(bb, length - (bb.readerIndex() - start));

      OFBsnPduTxRequestVer10 bsnPduTxRequestVer10 =
          new OFBsnPduTxRequestVer10(xid, txIntervalMs, portNo, slotNum, data);
      if (logger.isTraceEnabled()) logger.trace("readFrom - read={}", bsnPduTxRequestVer10);
      return bsnPduTxRequestVer10;
    }
  @Override
  protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf)
      throws Exception {

    ChannelBuffer result = (ChannelBuffer) super.decode(ctx, channel, buf);

    if (result != null) {

      int index = result.indexOf(result.readerIndex(), result.writerIndex(), (byte) '$');
      if (index == -1) {
        return result;
      } else {
        result.skipBytes(index);
        return result.readBytes(result.readableBytes());
      }
    }

    return null;
  }
 @Override
 public OFBsnStatsRequest<?> readFrom(ChannelBuffer bb) throws OFParseError {
   if (bb.readableBytes() < MINIMUM_LENGTH) return null;
   int start = bb.readerIndex();
   // fixed value property version == 2
   byte version = bb.readByte();
   if (version != (byte) 0x2)
     throw new OFParseError("Wrong version: Expected=OFVersion.OF_11(2), got=" + version);
   // fixed value property type == 18
   byte type = bb.readByte();
   if (type != (byte) 0x12)
     throw new OFParseError("Wrong type: Expected=OFType.STATS_REQUEST(18), got=" + type);
   int length = U16.f(bb.readShort());
   if (length < MINIMUM_LENGTH)
     throw new OFParseError(
         "Wrong length: Expected to be >= " + MINIMUM_LENGTH + ", was: " + length);
   U32.f(bb.readInt());
   // fixed value property statsType == 65535
   short statsType = bb.readShort();
   if (statsType != (short) 0xffff)
     throw new OFParseError(
         "Wrong statsType: Expected=OFStatsType.EXPERIMENTER(65535), got=" + statsType);
   OFStatsRequestFlagsSerializerVer11.readFrom(bb);
   // pad: 4 bytes
   bb.skipBytes(4);
   // fixed value property experimenter == 0x5c16c7L
   int experimenter = bb.readInt();
   if (experimenter != 0x5c16c7)
     throw new OFParseError(
         "Wrong experimenter: Expected=0x5c16c7L(0x5c16c7L), got=" + experimenter);
   int subtype = bb.readInt();
   bb.readerIndex(start);
   switch (subtype) {
     default:
       throw new OFParseError(
           "Unknown value for discriminator subtype of class OFBsnStatsRequestVer11: "
               + subtype);
   }
 }
  @Override
  protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf)
      throws Exception {

    // Check minimum length
    if (buf.readableBytes() < 10) {
      return null;
    }

    // Trim end line
    if (buf.getUnsignedShort(buf.readerIndex()) == 0x0d0a) {
      buf.skipBytes(2);
    }

    // Read message
    int length =
        Integer.parseInt(buf.toString(buf.readerIndex() + 2, 2, Charset.defaultCharset()), 16);
    if (length <= buf.readableBytes()) {
      return buf.readBytes(length);
    }

    return null;
  }
    @Override
    public OFBsnVlanCounterStatsEntry readFrom(ChannelBuffer bb) throws OFParseError {
      int start = bb.readerIndex();
      int length = U16.f(bb.readShort());
      if (length < MINIMUM_LENGTH)
        throw new OFParseError(
            "Wrong length: Expected to be >= " + MINIMUM_LENGTH + ", was: " + length);
      if (bb.readableBytes() + (bb.readerIndex() - start) < length) {
        // Buffer does not have all data yet
        bb.readerIndex(start);
        return null;
      }
      if (logger.isTraceEnabled()) logger.trace("readFrom - length={}", length);
      int vlanVid = U16.f(bb.readShort());
      // pad: 4 bytes
      bb.skipBytes(4);
      List<U64> values = ChannelUtils.readList(bb, length - (bb.readerIndex() - start), U64.READER);

      OFBsnVlanCounterStatsEntryVer13 bsnVlanCounterStatsEntryVer13 =
          new OFBsnVlanCounterStatsEntryVer13(vlanVid, values);
      if (logger.isTraceEnabled())
        logger.trace("readFrom - read={}", bsnVlanCounterStatsEntryVer13);
      return bsnVlanCounterStatsEntryVer13;
    }
  @Override
  protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg)
      throws Exception {

    ChannelBuffer buf = (ChannelBuffer) msg;
    int type = buf.readUnsignedShort();
    buf.readUnsignedShort(); // length

    if (type == MSG_IDENT || type == MSG_IDENT_FULL) {

      buf.readUnsignedInt(); // id
      int length = buf.readUnsignedShort();
      buf.skipBytes(length);
      length = buf.readUnsignedShort();
      buf.skipBytes(length);
      length = buf.readUnsignedShort();
      String imei = buf.readBytes(length).toString(Charset.defaultCharset());
      identify(imei, channel, remoteAddress);

    } else if (hasDeviceId() && (type == MSG_POINT || type == MSG_ALARM || type == MSG_LOGMSG)) {

      List<Position> positions = new LinkedList<>();

      int recordCount = 1;
      if (type == MSG_LOGMSG) {
        recordCount = buf.readUnsignedShort();
      }

      for (int j = 0; j < recordCount; j++) {
        Position position = new Position();
        position.setProtocol(getProtocolName());
        position.setDeviceId(getDeviceId());

        if (type == MSG_LOGMSG) {
          position.set(Event.KEY_ARCHIVE, true);
          int subtype = buf.readUnsignedShort();
          if (subtype == MSG_ALARM) {
            position.set(Event.KEY_ALARM, true);
          }
          if (buf.readUnsignedShort() > buf.readableBytes()) {
            lastIndex += 1;
            break; // workaround for device bug
          }
          lastIndex = buf.readUnsignedInt();
          position.set(Event.KEY_INDEX, lastIndex);
        } else {
          newIndex = buf.readUnsignedInt();
        }

        position.setTime(new Date(buf.readUnsignedInt() * 1000));
        position.setLatitude(buf.readInt() * 180.0 / 0x7FFFFFFF);
        position.setLongitude(buf.readInt() * 180.0 / 0x7FFFFFFF);
        position.setSpeed(buf.readUnsignedInt() * 0.01);
        position.setCourse(buf.readUnsignedShort() * 0.01);
        position.setAltitude(buf.readUnsignedShort() * 0.01);

        int satellites = buf.readUnsignedByte();
        position.setValid(satellites >= 3);
        position.set(Event.KEY_SATELLITES, satellites);

        position.set(Event.KEY_GSM, buf.readUnsignedByte());
        position.set(Event.KEY_ODOMETER, buf.readUnsignedInt());

        long extraFlags = buf.readLong();

        if (BitUtil.check(extraFlags, 0)) {
          int count = buf.readUnsignedShort();
          for (int i = 1; i <= count; i++) {
            position.set(Event.PREFIX_ADC + i, buf.readUnsignedShort());
          }
        }

        if (BitUtil.check(extraFlags, 1)) {
          int size = buf.readUnsignedShort();
          position.set("can", buf.toString(buf.readerIndex(), size, Charset.defaultCharset()));
          buf.skipBytes(size);
        }

        if (BitUtil.check(extraFlags, 2)) {
          position.set("passenger", ChannelBuffers.hexDump(buf.readBytes(buf.readUnsignedShort())));
        }

        if (type == MSG_ALARM) {
          position.set(Event.KEY_ALARM, true);
          byte[] response = {(byte) 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
          channel.write(ChannelBuffers.wrappedBuffer(response));
        }

        buf.readUnsignedInt(); // crc

        positions.add(position);
      }

      requestArchive(channel);

      return positions;
    }

    return null;
  }
Exemple #27
0
  @Override
  protected Object decode(final ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)
      throws Exception {

    if (buffer.readableBytes() < 5) {
      return null;
    }

    int packetLength = 0;

    // SSLv3 or TLS - Check ContentType
    boolean tls;
    switch (buffer.getUnsignedByte(buffer.readerIndex())) {
      case 20: // change_cipher_spec
      case 21: // alert
      case 22: // handshake
      case 23: // application_data
        tls = true;
        break;
      default:
        // SSLv2 or bad data
        tls = false;
    }

    if (tls) {
      // SSLv3 or TLS - Check ProtocolVersion
      int majorVersion = buffer.getUnsignedByte(buffer.readerIndex() + 1);
      if (majorVersion >= 3 && majorVersion < 10) {
        // SSLv3 or TLS
        packetLength = (buffer.getShort(buffer.readerIndex() + 3) & 0xFFFF) + 5;
        if (packetLength <= 5) {
          // Neither SSLv2 or TLSv1 (i.e. SSLv2 or bad data)
          tls = false;
        }
      } else {
        // Neither SSLv2 or TLSv1 (i.e. SSLv2 or bad data)
        tls = false;
      }
    }

    if (!tls) {
      // SSLv2 or bad data - Check the version
      boolean sslv2 = true;
      int headerLength = (buffer.getUnsignedByte(buffer.readerIndex()) & 0x80) != 0 ? 2 : 3;
      int majorVersion = buffer.getUnsignedByte(buffer.readerIndex() + headerLength + 1);
      if (majorVersion >= 2 && majorVersion < 10) {
        // SSLv2
        if (headerLength == 2) {
          packetLength = (buffer.getShort(buffer.readerIndex()) & 0x7FFF) + 2;
        } else {
          packetLength = (buffer.getShort(buffer.readerIndex()) & 0x3FFF) + 3;
        }
        if (packetLength <= headerLength) {
          sslv2 = false;
        }
      } else {
        sslv2 = false;
      }

      if (!sslv2) {
        // Bad data - discard the buffer and raise an exception.
        SSLException e =
            new SSLException("not an SSL/TLS record: " + ChannelBuffers.hexDump(buffer));
        buffer.skipBytes(buffer.readableBytes());
        throw e;
      }
    }

    assert packetLength > 0;

    if (buffer.readableBytes() < packetLength) {
      return null;
    }

    // We advance the buffer's readerIndex before calling unwrap() because
    // unwrap() can trigger FrameDecoder call decode(), this method, recursively.
    // The recursive call results in decoding the same packet twice if
    // the readerIndex is advanced *after* decode().
    //
    // Here's an example:
    // 1) An SSL packet is received from the wire.
    // 2) SslHandler.decode() deciphers the packet and calls the user code.
    // 3) The user closes the channel in the same thread.
    // 4) The same thread triggers a channelDisconnected() event.
    // 5) FrameDecoder.cleanup() is called, and it calls SslHandler.decode().
    // 6) SslHandler.decode() will feed the same packet with what was
    //    deciphered at the step 2 again if the readerIndex was not advanced
    //    before calling the user code.
    final int packetOffset = buffer.readerIndex();
    buffer.skipBytes(packetLength);
    return unwrap(ctx, channel, buffer, packetOffset, packetLength);
  }
  @Override
  protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)
      throws Exception {
    MemcachedRestRequest request = this.request;
    if (request == null) {
      buffer.markReaderIndex();

      if (buffer.readableBytes() < 1) {
        return null;
      }
      short magic = buffer.readUnsignedByte();
      if (magic == 0x80) {
        if (buffer.readableBytes() < 23) return null;
        short opcode = buffer.readUnsignedByte();
        short keyLength = buffer.readShort();
        short extraLength = buffer.readUnsignedByte();
        short dataType = buffer.readUnsignedByte(); // unused
        short reserved = buffer.readShort(); // unused
        int totalBodyLength = buffer.readInt();
        int opaque = buffer.readInt();
        long cas = buffer.readLong();

        // we want the whole of totalBodyLength; otherwise, keep waiting.
        if (buffer.readableBytes() < totalBodyLength) {
          buffer.resetReaderIndex();
          return null;
        }

        buffer.skipBytes(extraLength); // get extras, can be empty

        if (keyLength != 0) {
          byte[] key = new byte[keyLength];
          buffer.readBytes(key);
          String uri = Unicode.fromBytes(key);
          if (opcode == 0x00) { // GET
            request = new MemcachedRestRequest(RestRequest.Method.GET, uri, key, -1, true);
            request.setOpaque(opaque);
            return request;
          } else if (opcode == 0x04) { // DELETE
            request = new MemcachedRestRequest(RestRequest.Method.DELETE, uri, key, -1, true);
            request.setOpaque(opaque);
            return request;
          } else if (opcode == 0x01) { // SET
            // the remainder of the message -- that is, totalLength - (keyLength + extraLength)
            // should be the payload
            int size = totalBodyLength - keyLength - extraLength;
            request = new MemcachedRestRequest(RestRequest.Method.POST, uri, key, size, true);
            request.setOpaque(opaque);
            byte[] data = new byte[size];
            buffer.readBytes(data, 0, size);
            request.setData(data);
            return request;
          }
        } else if (opcode == 0x07) { // QUIT
          channel.disconnect();
        }
      } else {
        buffer.resetReaderIndex(); // reset to get to the first byte
        // need to read a header
        boolean done = false;
        StringBuffer sb = this.sb;
        int readableBytes = buffer.readableBytes();
        for (int i = 0; i < readableBytes; i++) {
          byte next = buffer.readByte();
          if (next == CR) {
            next = buffer.readByte();
            if (next == LF) {
              done = true;
              break;
            }
          } else if (next == LF) {
            done = true;
            break;
          } else {
            sb.append((char) next);
          }
        }
        if (!done) {
          buffer.resetReaderIndex();
          return null;
        }

        String[] args = lineSplit.split(sb);
        // we read the text, clear it
        sb.setLength(0);

        String cmd = args[0];
        String uri = args[1];
        if ("get".equals(cmd)) {
          request = new MemcachedRestRequest(RestRequest.Method.GET, uri, null, -1, false);
          if (args.length > 3) {
            request.setData(Unicode.fromStringAsBytes(args[2]));
          }
          return request;
        } else if ("delete".equals(cmd)) {
          request = new MemcachedRestRequest(RestRequest.Method.DELETE, uri, null, -1, false);
          //                if (args.length > 3) {
          //                    request.setData(Unicode.fromStringAsBytes(args[2]));
          //                }
          return request;
        } else if ("set".equals(cmd)) {
          this.request =
              new MemcachedRestRequest(
                  RestRequest.Method.POST, uri, null, Integer.parseInt(args[4]), false);
          buffer.markReaderIndex();
        } else if ("quit".equals(cmd)) {
          channel.disconnect();
        }
      }
    } else {
      if (buffer.readableBytes() < (request.getDataSize() + 2)) {
        return null;
      }
      byte[] data = new byte[request.getDataSize()];
      buffer.readBytes(data, 0, data.length);
      byte next = buffer.readByte();
      if (next == CR) {
        next = buffer.readByte();
        if (next == LF) {
          request.setData(data);
          // reset
          this.request = null;
          return request;
        } else {
          this.request = null;
          throw new StreamCorruptedException("Expecting \r\n after data block");
        }
      } else {
        this.request = null;
        throw new StreamCorruptedException("Expecting \r\n after data block");
      }
    }
    return null;
  }
  @Override
  protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg)
      throws Exception {

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.skipBytes(4); // system code
    int type = buf.readUnsignedByte();
    long deviceUniqueId = buf.readUnsignedInt();

    if (type != MSG_CLIENT_SERIAL) {
      buf.readUnsignedShort(); // communication control
    }
    byte packetNumber = buf.readByte();

    // Send reply
    sendReply(channel, deviceUniqueId, packetNumber);

    // Parse location
    if (type == MSG_CLIENT_STATUS) {
      Position position = new Position();
      position.setProtocol(getProtocolName());

      // Device identifier
      if (!identify(String.valueOf(deviceUniqueId), channel)) {
        return null;
      }
      position.setDeviceId(getDeviceId());

      buf.readUnsignedByte(); // hardware version
      buf.readUnsignedByte(); // software version
      buf.readUnsignedByte(); // protocol version

      // Status
      position.set(Event.KEY_STATUS, buf.getUnsignedByte(buf.readerIndex()) & 0x0f);

      int operator = (buf.readUnsignedByte() & 0xf0) << 4;
      operator += buf.readUnsignedByte();

      buf.readUnsignedByte(); // reason data
      buf.readUnsignedByte(); // reason
      buf.readUnsignedByte(); // mode
      buf.readUnsignedInt(); // IO

      operator <<= 8;
      operator += buf.readUnsignedByte();
      position.set("operator", operator);

      buf.readUnsignedInt(); // ADC
      buf.readUnsignedMedium(); // Odometer
      buf.skipBytes(6); // multi-purpose data

      buf.readUnsignedShort(); // gps fix
      buf.readUnsignedByte(); // location status
      buf.readUnsignedByte(); // mode 1
      buf.readUnsignedByte(); // mode 2

      position.setValid(buf.readUnsignedByte() >= 3); // satellites

      // Location data
      position.setLongitude(buf.readInt() / Math.PI * 180 / 100000000);
      position.setLatitude(buf.readInt() / Math.PI * 180 / 100000000.0);
      position.setAltitude(buf.readInt() * 0.01);
      position.setSpeed(UnitsConverter.knotsFromMps(buf.readInt() * 0.01));
      position.setCourse(buf.readUnsignedShort() / Math.PI * 180.0 / 1000.0);

      // Time
      Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
      time.clear();
      time.set(Calendar.SECOND, buf.readUnsignedByte());
      time.set(Calendar.MINUTE, buf.readUnsignedByte());
      time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
      time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
      time.set(Calendar.MONTH, buf.readUnsignedByte() - 1);
      time.set(Calendar.YEAR, buf.readUnsignedShort());
      position.setTime(time.getTime());
      return position;
    }

    return null;
  }
  @Override
  protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg)
      throws Exception {

    ChannelBuffer buf = (ChannelBuffer) msg;

    buf.skipBytes(2); // header
    int type = buf.readUnsignedByte();
    buf.readUnsignedShort(); // size

    if (type == MSG_ON_DEMAND
        || type == MSG_POSITION_UPLOAD
        || type == MSG_POSITION_REUPLOAD
        || type == MSG_ALARM
        || type == MSG_REPLY
        || type == MSG_PERIPHERAL) {

      // Create new position
      Position position = new Position();
      position.setProtocol(getProtocolName());

      // Device identification
      if (!identify(readSerialNumber(buf), channel)) {
        return null;
      }
      position.setDeviceId(getDeviceId());

      // Date and time
      Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
      time.clear();
      time.set(Calendar.YEAR, 2000 + ChannelBufferTools.readHexInteger(buf, 2));
      time.set(Calendar.MONTH, ChannelBufferTools.readHexInteger(buf, 2) - 1);
      time.set(Calendar.DAY_OF_MONTH, ChannelBufferTools.readHexInteger(buf, 2));
      time.set(Calendar.HOUR_OF_DAY, ChannelBufferTools.readHexInteger(buf, 2));
      time.set(Calendar.MINUTE, ChannelBufferTools.readHexInteger(buf, 2));
      time.set(Calendar.SECOND, ChannelBufferTools.readHexInteger(buf, 2));
      position.setTime(time.getTime());

      // Location
      position.setLatitude(ChannelBufferTools.readCoordinate(buf));
      position.setLongitude(ChannelBufferTools.readCoordinate(buf));
      position.setSpeed(UnitsConverter.knotsFromKph(ChannelBufferTools.readHexInteger(buf, 4)));
      position.setCourse(ChannelBufferTools.readHexInteger(buf, 4));

      // Flags
      int flags = buf.readUnsignedByte();
      position.setValid((flags & 0x80) != 0);

      if (type == MSG_ALARM) {

        buf.skipBytes(2);

      } else {

        // Odometer
        position.set(Event.KEY_ODOMETER, buf.readUnsignedMedium());

        // Status
        buf.skipBytes(4);

        // Other
        buf.skipBytes(8);
      }

      // TODO: parse extra data
      return position;
    } else if (type == MSG_LOGIN && channel != null) {

      buf.skipBytes(4); // serial number
      buf.readByte(); // reserved

      ChannelBuffer response = ChannelBuffers.dynamicBuffer();
      response.writeByte(0x29);
      response.writeByte(0x29); // header
      response.writeByte(MSG_CONFIRMATION);
      response.writeShort(5); // size
      response.writeByte(buf.readUnsignedByte());
      response.writeByte(type);
      response.writeByte(0); // reserved
      response.writeByte(Crc.xorChecksum(response.toByteBuffer()));
      response.writeByte(0x0D); // ending
      channel.write(response);
    }

    return null;
  }