blob: 47f2cac34d6a3a3015afa17a15249e8eb0fbe49d [file] [log] [blame]
/*
*
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file defines macros and objects commonly used for the
* processing of Weave messages.
*
*/
#ifndef _WEAVE_MESSAGE_H
#define _WEAVE_MESSAGE_H
#include <Weave/Core/WeaveEncoding.h>
#include <Weave/Core/WeaveError.h>
#include <Weave/Core/WeaveTLV.h>
#include <Weave/Support/NLDLLUtil.h>
#include <SystemLayer/SystemPacketBuffer.h>
/*
* these macros are the guts of the packing and parsing stuff and they're used
* everywhere.
*
* here are the writers
* parameters:
* - PTR, a pointer into a buffer of type uint8_t
* - VAL, a value to write
*/
#define WRITEBYTE(PTR, VAL) \
do { \
*(PTR)++ = (uint8_t)(VAL); \
} while (0)
#define WRITE16(PTR, VAL) \
do { \
WRITEBYTE((PTR), ((VAL) >> 0)); \
WRITEBYTE((PTR), ((VAL) >> 8)); \
} while (0)
#define WRITE32(PTR, VAL) \
do { \
WRITEBYTE((PTR), ((VAL) >> 0)); \
WRITEBYTE((PTR), ((VAL) >> 8)); \
WRITEBYTE((PTR), ((VAL) >> 16)); \
WRITEBYTE((PTR), ((VAL) >> 24)); \
} while (0)
/*
* and the readers
* parameter: PTR, a pointer into a buffer of type uint8_t
* value: the value read form the buffer
*/
#define READBYTE(PTR) (*(uint8_t *)(PTR)++)
/*
* parameters:
* - PTR, a pointer into a buffer of type uint8_t
* - DEST, where to put what's read from *p
*/
#define READ16(PTR, DEST) \
do { \
uint16_t __byte0 = (uint16_t)READBYTE(PTR); \
uint16_t __byte1 = (uint16_t)READBYTE(PTR); \
DEST = __byte0 + (__byte1 << 8); \
} while (0)
#define READ32(PTR, DEST) \
do { \
uint16_t __byte0 = (uint16_t)READBYTE(PTR); \
uint16_t __byte1 = (uint16_t)READBYTE(PTR); \
uint16_t __byte2 = (uint16_t)READBYTE(PTR); \
uint16_t __byte3 = (uint16_t)READBYTE(PTR); \
DEST = __byte0 + (__byte1 << 8) + (__byte2 << 16) + (__byte3 << 24); \
} while (0)
/*
* the message iterator class allows packet handling to operate in
* a regular manner, do a bit of work, check the result, get out if
* it's not good and so on. this results in a bunch of boilerplate
* code, which is captured here.
*/
#define TRY(OPERATION) \
do { \
WEAVE_ERROR e = (OPERATION); \
if ( e != WEAVE_NO_ERROR) return e; \
} while (0)
#define RESCUE(ERR,OPERATION,OUT) \
do { \
ERR = (OPERATION); \
if (ERR != WEAVE_NO_ERROR) goto OUT; \
} while (0)
namespace nl {
namespace Weave {
namespace Profiles {
/**
* @class RetainedPacketBuffer
*
* @brief
* This is a base class that serves as a convenience object for
* automatically reference counting a System::PacketBuffer.
*
*/
class NL_DLL_EXPORT RetainedPacketBuffer
{
public:
// Con/destructors
RetainedPacketBuffer(void);
RetainedPacketBuffer(const RetainedPacketBuffer &aRetainedPacketBuffer);
~RetainedPacketBuffer(void);
RetainedPacketBuffer &operator =(const RetainedPacketBuffer &aRetainedPacketBuffer);
virtual bool IsRetaining(void) const;
void Retain(System::PacketBuffer *aBuffer);
virtual void Release(void);
inline System::PacketBuffer *GetBuffer(void) { return (mBuffer); }
protected:
System::PacketBuffer *mBuffer; //<! A pointer to the retained packet
//<! buffer.
};
/*
* in order to use message buffers sensibly, we define this iterator,
* which can be used to keep track of boundaries and so on.
*/
class NL_DLL_EXPORT MessageIterator : public RetainedPacketBuffer
{
public:
// constructor
MessageIterator(System::PacketBuffer*);
// reading and writing
WEAVE_ERROR readByte(uint8_t*);
WEAVE_ERROR read16(uint16_t*);
WEAVE_ERROR read32(uint32_t*);
WEAVE_ERROR read64(uint64_t*);
WEAVE_ERROR readString(uint16_t, char*);
WEAVE_ERROR readBytes(uint16_t, uint8_t*);
WEAVE_ERROR writeByte(uint8_t);
WEAVE_ERROR write16(uint16_t);
WEAVE_ERROR write32(uint32_t);
WEAVE_ERROR write64(uint64_t);
WEAVE_ERROR writeString(uint16_t, char*);
WEAVE_ERROR writeBytes(uint16_t, uint8_t*);
// standard iterator operations
MessageIterator& operator ++(void);
MessageIterator& operator +(uint16_t);
MessageIterator& operator -(uint16_t);
bool operator ==(const MessageIterator&);
bool operator !=(const MessageIterator&);
uint8_t& operator *(void);
void append(void);
// size checking
bool hasData(uint16_t);
bool hasRoom(uint16_t);
// finishing
void finishWriting(void);
// data members
uint8_t *thePoint;
};
/*
* here's how we handle strings in weave. this class has an 8-bit
* and a 16-bit variant.
*/
class NL_DLL_EXPORT ReferencedString : public RetainedPacketBuffer
{
public:
// constructor
ReferencedString(void);
// initializers
WEAVE_ERROR init(uint16_t, char*, System::PacketBuffer*);
WEAVE_ERROR init(uint16_t, char*);
WEAVE_ERROR init(uint8_t, char*, System::PacketBuffer*);
WEAVE_ERROR init(uint8_t, char*);
// pack and parse
WEAVE_ERROR pack(MessageIterator&);
static WEAVE_ERROR parse(MessageIterator&, ReferencedString&);
// comparison
bool operator ==(const ReferencedString&) const;
// print string generation (for testing)
char *printString(void);
//data members
uint16_t theLength;
char *theString;
bool isShort;
};
/*
* similarly, we need to be able to represent a big old blob
* of TLV data.
*/
class NL_DLL_EXPORT ReferencedTLVData : public RetainedPacketBuffer
{
public:
/*
* under certain circumstances, e.g. when we don't want to blow out the
* stack by writing some big thing into it in preparation for sending
* a message with a referenced extent in it, we want to only write the
* bits AFTER we've obtained the outgoing buffer. we do that using one
* of these.
*
* NOTE!!! the handler set up below does NOT return an error and, in
* the case where one is supplied, the pack method will not return an
* error either. this means that the NHL-supplied handler MUST handler
* all errors that arise from the formatting of TLV.
*
* parameters:
* - TLVWriter&, a TLV writer to use to write things out
* - void*, a state object known to the application
*/
typedef void (*TLVWriteCallback)(TLV::TLVWriter &aWriter, void *aAppState);
// constructor
ReferencedTLVData(void);
// initializers
WEAVE_ERROR init(System::PacketBuffer*);
WEAVE_ERROR init(MessageIterator&);
WEAVE_ERROR init(uint16_t, uint16_t, uint8_t*);
WEAVE_ERROR init(TLVWriteCallback, void*);
/*
* ReferencedTLVData needs to override the free() and isFree()
* methods because "freedom", in this case, is more than nothing
* left to lose.
*/
void free(void);
bool isFree(void);
/**
* Check if a ReferencedTLVData object has anything in it.
*
* There are two possible ways such an object could "have"
* something. Either it could have 0 length OR it could have no
* write callback.
*
* @return true if the data set has 0 length or there's no write
* callback in hand, false otherwise.
*/
inline bool isEmpty(void)
{
return (theLength == 0 && theWriteCallback == NULL);
};
// packing and parsing
/**
* Pack a ReferencedTLVData object directly into an inet buffer.
*
* @param [in] PacketBuffer *buff, the buffer to fill.
*
* @return a WEAVE_ERROR reflecting the success of the underlying
* pack call.
*/
inline WEAVE_ERROR pack(System::PacketBuffer *buff)
{
MessageIterator i(buff);
return pack(i);
};
WEAVE_ERROR pack(MessageIterator&);
/**
* Return the data length assuming that the object has been packed
* into a buffer.
*
* @return the integer length of the packed data.
*/
inline uint16_t packedLength(void)
{
return theLength;
};
/**
* Parse a ReferencedTLVData object out of an inet buffer
* (assuming it just contains TLV).
*
* @param [in] PacketBuffer *buff, the buffer to read from.
*
* @param [out] ReferencedTLVData &aTarget, a ReferencedTLVData
* object to "fill" with the result.
*
* @return a WEAVE_ERROR reflecting the success of the underlying
* parse call.
*/
static inline WEAVE_ERROR parse(System::PacketBuffer *buff, ReferencedTLVData &aTarget)
{
MessageIterator i(buff);
return parse(i, aTarget);
};
static WEAVE_ERROR parse(MessageIterator&, ReferencedTLVData&);
// comparison
bool operator ==(const ReferencedTLVData&) const;
// data members
uint16_t theLength;
uint16_t theMaxLength;
uint8_t *theData;
private:
TLVWriteCallback theWriteCallback;
void *theAppState;
};
}; // Profiles
}; // Weave
}; // nl
#endif // _WEAVE_MESSAGE_H