This is CoAP library with a focus on simplicity. It offers minimal CoAP PDU construction and decoding to and from byte buffers.

Fork of cantcoap by Ashley Mills

Committer:
ericliang
Date:
Wed Aug 12 02:39:14 2015 +0000
Revision:
2:1544f4758e0a
Parent:
1:5eec2844ad47
commit code

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ashleymills 0:3d62a105fd34 1 /*
ashleymills 0:3d62a105fd34 2 Copyright (c) 2013, Ashley Mills.
ashleymills 0:3d62a105fd34 3 All rights reserved.
ashleymills 0:3d62a105fd34 4
ashleymills 0:3d62a105fd34 5 Redistribution and use in source and binary forms, with or without
ashleymills 0:3d62a105fd34 6 modification, are permitted provided that the following conditions are met:
ashleymills 0:3d62a105fd34 7
ashleymills 0:3d62a105fd34 8 1. Redistributions of source code must retain the above copyright notice, this
ashleymills 0:3d62a105fd34 9 list of conditions and the following disclaimer.
ashleymills 0:3d62a105fd34 10 2. Redistributions in binary form must reproduce the above copyright notice,
ashleymills 0:3d62a105fd34 11 this list of conditions and the following disclaimer in the documentation
ashleymills 0:3d62a105fd34 12 and/or other materials provided with the distribution.
ashleymills 0:3d62a105fd34 13
ashleymills 0:3d62a105fd34 14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ashleymills 0:3d62a105fd34 15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
ashleymills 0:3d62a105fd34 16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
ashleymills 0:3d62a105fd34 17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ashleymills 0:3d62a105fd34 18 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
ashleymills 0:3d62a105fd34 19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
ashleymills 0:3d62a105fd34 20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ashleymills 0:3d62a105fd34 21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
ashleymills 0:3d62a105fd34 22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
ashleymills 0:3d62a105fd34 23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ashleymills 0:3d62a105fd34 24 */
ashleymills 0:3d62a105fd34 25
ashleymills 0:3d62a105fd34 26 // version, 2 bits
ashleymills 0:3d62a105fd34 27 // type, 2 bits
ashleymills 0:3d62a105fd34 28 // 00 Confirmable
ashleymills 0:3d62a105fd34 29 // 01 Non-confirmable
ashleymills 0:3d62a105fd34 30 // 10 Acknowledgement
ashleymills 0:3d62a105fd34 31 // 11 Reset
ashleymills 0:3d62a105fd34 32
ashleymills 0:3d62a105fd34 33 // token length, 4 bits
ashleymills 0:3d62a105fd34 34 // length of token in bytes (only 0 to 8 bytes allowed)
ashleymills 0:3d62a105fd34 35 #include <stdio.h>
ashleymills 0:3d62a105fd34 36 #include <stdlib.h>
ashleymills 0:3d62a105fd34 37 #include <stdint.h>
ashleymills 0:3d62a105fd34 38 #include <string.h>
ashleymills 1:5eec2844ad47 39 #include <inet.h>
ashleymills 0:3d62a105fd34 40 #include "cantcoap.h"
ashleymills 1:5eec2844ad47 41
ashleymills 1:5eec2844ad47 42 // for debugging output you need https://mbed.org/users/donatien/code/DebugLib/
ericliang 2:1544f4758e0a 43 #define __DEBUG__ 0 // INFO
ashleymills 1:5eec2844ad47 44 #ifndef __MODULE__
ashleymills 1:5eec2844ad47 45 #define __MODULE__ "cantcoap.cpp"
ashleymills 1:5eec2844ad47 46 #endif
ericliang 2:1544f4758e0a 47
ericliang 2:1544f4758e0a 48
ericliang 2:1544f4758e0a 49 //#include "dbg.h"
ashleymills 1:5eec2844ad47 50 // some extra debug stuff
ashleymills 1:5eec2844ad47 51 #if __DEBUG__ > 0
ashleymills 1:5eec2844ad47 52 #define INFOX(...) do { fprintf(stderr,__VA_ARGS__); } while(0)
ashleymills 1:5eec2844ad47 53 #define INFOLX(...) do { fprintf(stderr,"[INFO] %s:%d ",__MODULE__,__LINE__); fprintf(stderr,__VA_ARGS__); } while(0)
ashleymills 1:5eec2844ad47 54 #define DBGLX(...) do { fprintf(stderr,"[DBG] %s:%d ",__MODULE__,__LINE__); fprintf(stderr,__VA_ARGS__); } while(0)
ashleymills 1:5eec2844ad47 55 #define DBG_PDU() do { printBin(); } while(0)
ashleymills 0:3d62a105fd34 56 #else
ashleymills 1:5eec2844ad47 57 #define INFOX(...) do{} while(0)
ashleymills 1:5eec2844ad47 58 #define INFOLX(...) do{} while(0)
ashleymills 1:5eec2844ad47 59 #define DBGLX(...) do{} while(0)
ashleymills 1:5eec2844ad47 60 #define DBG_PDU() do{} while(0)
ashleymills 0:3d62a105fd34 61 #endif
ashleymills 0:3d62a105fd34 62
ericliang 2:1544f4758e0a 63 #define DBG(...) do{} while(0)
ericliang 2:1544f4758e0a 64 #define DBGX(...) do{} while(0)
ericliang 2:1544f4758e0a 65 #define INFO(...) do{} while(0)
ashleymills 0:3d62a105fd34 66 /// Memory-managed constructor. Buffer for PDU is dynamically sized and allocated by the object.
ashleymills 0:3d62a105fd34 67 /**
ashleymills 0:3d62a105fd34 68 * When using this constructor, the CoapPDU class will allocate space for the PDU.
ashleymills 0:3d62a105fd34 69 * Contrast this with the parameterized constructors, which allow the use of an external buffer.
ashleymills 0:3d62a105fd34 70 *
ashleymills 0:3d62a105fd34 71 * Note, the PDU container and space can be reused by issuing a CoapPDU::reset(). If the new PDU exceeds the
ashleymills 0:3d62a105fd34 72 * space of the previously allocated memory, then further memory will be dynamically allocated.
ashleymills 0:3d62a105fd34 73 *
ashleymills 0:3d62a105fd34 74 * Deleting the object will free the Object container and all dynamically allocated memory.
ashleymills 0:3d62a105fd34 75 *
ashleymills 0:3d62a105fd34 76 * \note It would have been nice to use something like UDP_CORK or MSG_MORE, to allow separate buffers
ashleymills 0:3d62a105fd34 77 * for token, options, and payload but these FLAGS aren't implemented for UDP in LwIP so stuck with one buffer for now.
ashleymills 0:3d62a105fd34 78 *
ashleymills 0:3d62a105fd34 79 * CoAP version defaults to 1.
ashleymills 0:3d62a105fd34 80 *
ashleymills 0:3d62a105fd34 81 * \sa CoapPDU::CoapPDU(uint8_t *pdu, int pduLength), CoapPDU::CoapPDU::(uint8_t *buffer, int bufferLength, int pduLength),
ashleymills 0:3d62a105fd34 82 * CoapPDU:CoapPDU()~
ashleymills 0:3d62a105fd34 83 *
ashleymills 0:3d62a105fd34 84 */
ashleymills 0:3d62a105fd34 85 CoapPDU::CoapPDU() {
ashleymills 0:3d62a105fd34 86 // pdu
ashleymills 0:3d62a105fd34 87 _pdu = (uint8_t*)calloc(4,sizeof(uint8_t));
ashleymills 0:3d62a105fd34 88 _pduLength = 4;
ashleymills 0:3d62a105fd34 89 _bufferLength = _pduLength;
ashleymills 0:3d62a105fd34 90
ashleymills 0:3d62a105fd34 91 //options
ashleymills 0:3d62a105fd34 92 _numOptions = 0;
ashleymills 0:3d62a105fd34 93 _maxAddedOptionNumber = 0;
ashleymills 0:3d62a105fd34 94
ashleymills 0:3d62a105fd34 95 // payload
ashleymills 0:3d62a105fd34 96 _payloadPointer = NULL;
ashleymills 0:3d62a105fd34 97 _payloadLength = 0;
ashleymills 0:3d62a105fd34 98
ashleymills 0:3d62a105fd34 99 _constructedFromBuffer = 0;
ashleymills 0:3d62a105fd34 100
ashleymills 0:3d62a105fd34 101 setVersion(1);
ashleymills 0:3d62a105fd34 102 }
ashleymills 0:3d62a105fd34 103
ashleymills 0:3d62a105fd34 104 /// Construct a PDU using an external buffer. No copy of the buffer is made.
ashleymills 0:3d62a105fd34 105 /**
ashleymills 0:3d62a105fd34 106 * This constructor is normally used where a PDU has been received over the network, and it's length is known.
ashleymills 0:3d62a105fd34 107 * In this case the CoapPDU object is probably going to be used as a temporary container to access member values.
ashleymills 0:3d62a105fd34 108 *
ashleymills 0:3d62a105fd34 109 * It is assumed that \b pduLength is the length of the actual CoAP PDU, and consequently the buffer will also be this size,
ashleymills 0:3d62a105fd34 110 * contrast this with CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength) which allows the buffer to
ashleymills 0:3d62a105fd34 111 * be larger than the PDU.
ashleymills 0:3d62a105fd34 112 *
ashleymills 0:3d62a105fd34 113 * A PDU constructed in this manner must be validated with CoapPDU::validate() before the member variables will be accessible.
ashleymills 0:3d62a105fd34 114 *
ashleymills 0:3d62a105fd34 115 * \warning The validation call parses the PDU structure to set some internal parameters. If you do
ashleymills 0:3d62a105fd34 116 * not validate the PDU, then the behaviour of member access functions will be undefined.
ashleymills 0:3d62a105fd34 117 *
ashleymills 0:3d62a105fd34 118 * The buffer can be reused by issuing a CoapPDU::reset() but the class will not change the size of the buffer. If the
ashleymills 0:3d62a105fd34 119 * newly constructed PDU exceeds the size of the buffer, the function called (for example CoapPDU::addOption) will fail.
ashleymills 0:3d62a105fd34 120 *
ashleymills 0:3d62a105fd34 121 * Deleting this object will only delete the Object container and will not delete the PDU buffer.
ashleymills 0:3d62a105fd34 122 *
ashleymills 0:3d62a105fd34 123 * @param pdu A pointer to an array of bytes which comprise the CoAP PDU
ashleymills 0:3d62a105fd34 124 * @param pduLength The length of the CoAP PDU pointed to by \b pdu
ashleymills 0:3d62a105fd34 125
ashleymills 0:3d62a105fd34 126 * \sa CoapPDU::CoapPDU(), CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)
ashleymills 0:3d62a105fd34 127 */
ashleymills 0:3d62a105fd34 128 CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) {
ashleymills 1:5eec2844ad47 129 int bufferLength = pduLength;
ashleymills 1:5eec2844ad47 130 // sanity
ashleymills 1:5eec2844ad47 131 if(pduLength<4&&pduLength!=0) {
ashleymills 1:5eec2844ad47 132 DBG("PDU cannot have a length less than 4");
ashleymills 1:5eec2844ad47 133 }
ashleymills 1:5eec2844ad47 134
ashleymills 0:3d62a105fd34 135 // pdu
ashleymills 0:3d62a105fd34 136 _pdu = pdu;
ashleymills 1:5eec2844ad47 137 _bufferLength = bufferLength;
ashleymills 1:5eec2844ad47 138 if(pduLength==0) {
ashleymills 1:5eec2844ad47 139 // this is actually a fresh pdu, header always exists
ashleymills 1:5eec2844ad47 140 _pduLength = 4;
ashleymills 1:5eec2844ad47 141 // make sure header is zeroed
ashleymills 1:5eec2844ad47 142 _pdu[0] = 0x00; _pdu[1] = 0x00; _pdu[2] = 0x00; _pdu[3] = 0x00;
ashleymills 1:5eec2844ad47 143 setVersion(1);
ashleymills 1:5eec2844ad47 144 } else {
ashleymills 1:5eec2844ad47 145 _pduLength = pduLength;
ashleymills 1:5eec2844ad47 146 }
ashleymills 1:5eec2844ad47 147
ashleymills 0:3d62a105fd34 148 _constructedFromBuffer = 1;
ashleymills 0:3d62a105fd34 149
ashleymills 0:3d62a105fd34 150 // options
ashleymills 0:3d62a105fd34 151 _numOptions = 0;
ashleymills 0:3d62a105fd34 152 _maxAddedOptionNumber = 0;
ashleymills 0:3d62a105fd34 153
ashleymills 0:3d62a105fd34 154 // payload
ashleymills 0:3d62a105fd34 155 _payloadPointer = NULL;
ashleymills 0:3d62a105fd34 156 _payloadLength = 0;
ashleymills 0:3d62a105fd34 157 }
ashleymills 0:3d62a105fd34 158
ashleymills 0:3d62a105fd34 159 /// Construct object from external buffer that may be larger than actual PDU.
ashleymills 0:3d62a105fd34 160 /**
ashleymills 0:3d62a105fd34 161 * This differs from CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) in that the buffer may be larger
ashleymills 0:3d62a105fd34 162 * than the actual CoAP PDU contained int the buffer. This is typically used when a large buffer is reused
ashleymills 0:3d62a105fd34 163 * multiple times. Note that \b pduLength can be 0.
ashleymills 0:3d62a105fd34 164 *
ashleymills 0:3d62a105fd34 165 * If an actual CoAP PDU is passed in the buffer, \b pduLength should match its length. CoapPDU::validate() must
ashleymills 0:3d62a105fd34 166 * be called to initiate the object before member functions can be used.
ashleymills 0:3d62a105fd34 167 *
ashleymills 0:3d62a105fd34 168 * A PDU constructed in this manner must be validated with CoapPDU::validate() before the member variables will be accessible.
ashleymills 0:3d62a105fd34 169 *
ashleymills 0:3d62a105fd34 170 * \warning The validation call parses the PDU structure to set some internal parameters. If you do
ashleymills 0:3d62a105fd34 171 * not validate the PDU, then the behaviour of member access functions will be undefined.
ashleymills 0:3d62a105fd34 172 *
ashleymills 0:3d62a105fd34 173 * The buffer can be reused by issuing a CoapPDU::reset() but the class will not change the size of the buffer. If the
ashleymills 0:3d62a105fd34 174 * newly constructed PDU exceeds the size of the buffer, the function called (for example CoapPDU::addOption) will fail.
ashleymills 0:3d62a105fd34 175 *
ashleymills 0:3d62a105fd34 176 * Deleting this object will only delete the Object container and will not delete the PDU buffer.
ashleymills 0:3d62a105fd34 177 *
ashleymills 0:3d62a105fd34 178 * \param buffer A buffer which either contains a CoAP PDU or is intended to be used to construct one.
ashleymills 0:3d62a105fd34 179 * \param bufferLength The length of the buffer
ashleymills 0:3d62a105fd34 180 * \param pduLength If the buffer contains a CoAP PDU, this specifies the length of the PDU within the buffer.
ashleymills 0:3d62a105fd34 181 *
ashleymills 0:3d62a105fd34 182 * \sa CoapPDU::CoapPDU(), CoapPDU::CoapPDU(uint8_t *pdu, int pduLength)
ashleymills 0:3d62a105fd34 183 */
ashleymills 0:3d62a105fd34 184 CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength) {
ashleymills 0:3d62a105fd34 185 // sanity
ashleymills 0:3d62a105fd34 186 if(pduLength<4&&pduLength!=0) {
ashleymills 0:3d62a105fd34 187 DBG("PDU cannot have a length less than 4");
ashleymills 0:3d62a105fd34 188 }
ashleymills 0:3d62a105fd34 189
ashleymills 0:3d62a105fd34 190 // pdu
ashleymills 0:3d62a105fd34 191 _pdu = buffer;
ashleymills 0:3d62a105fd34 192 _bufferLength = bufferLength;
ashleymills 0:3d62a105fd34 193 if(pduLength==0) {
ashleymills 0:3d62a105fd34 194 // this is actually a fresh pdu, header always exists
ashleymills 0:3d62a105fd34 195 _pduLength = 4;
ashleymills 0:3d62a105fd34 196 // make sure header is zeroed
ashleymills 0:3d62a105fd34 197 _pdu[0] = 0x00; _pdu[1] = 0x00; _pdu[2] = 0x00; _pdu[3] = 0x00;
ashleymills 0:3d62a105fd34 198 setVersion(1);
ashleymills 0:3d62a105fd34 199 } else {
ashleymills 0:3d62a105fd34 200 _pduLength = pduLength;
ashleymills 0:3d62a105fd34 201 }
ashleymills 0:3d62a105fd34 202
ashleymills 0:3d62a105fd34 203 _constructedFromBuffer = 1;
ashleymills 0:3d62a105fd34 204
ashleymills 0:3d62a105fd34 205 // options
ashleymills 0:3d62a105fd34 206 _numOptions = 0;
ashleymills 0:3d62a105fd34 207 _maxAddedOptionNumber = 0;
ashleymills 0:3d62a105fd34 208
ashleymills 0:3d62a105fd34 209 // payload
ashleymills 0:3d62a105fd34 210 _payloadPointer = NULL;
ashleymills 0:3d62a105fd34 211 _payloadLength = 0;
ashleymills 0:3d62a105fd34 212 }
ashleymills 0:3d62a105fd34 213
ashleymills 0:3d62a105fd34 214 /// Reset CoapPDU container so it can be reused to build a new PDU.
ashleymills 0:3d62a105fd34 215 /**
ashleymills 0:3d62a105fd34 216 * This resets the CoapPDU container, setting the pdu length, option count, etc back to zero. The
ashleymills 0:3d62a105fd34 217 * PDU can then be populated as if it were newly constructed.
ashleymills 0:3d62a105fd34 218 *
ashleymills 0:3d62a105fd34 219 * Note that the space available will depend on how the CoapPDU was originally constructed:
ashleymills 0:3d62a105fd34 220 * -# CoapPDU::CoapPDU()
ashleymills 0:3d62a105fd34 221 *
ashleymills 0:3d62a105fd34 222 * Available space initially be \b _pduLength. But further space will be allocated as needed on demand,
ashleymills 0:3d62a105fd34 223 * limited only by the OS/environment.
ashleymills 0:3d62a105fd34 224 *
ashleymills 0:3d62a105fd34 225 * -# CoapPDU::CoapPDU(uint8_t *pdu, int pduLength)
ashleymills 0:3d62a105fd34 226 *
ashleymills 0:3d62a105fd34 227 * Space is limited by the variable \b pduLength. The PDU cannot exceed \b pduLength bytes.
ashleymills 0:3d62a105fd34 228 *
ashleymills 0:3d62a105fd34 229 * -# CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)
ashleymills 0:3d62a105fd34 230 *
ashleymills 0:3d62a105fd34 231 * Space is limited by the variable \b bufferLength. The PDU cannot exceed \b bufferLength bytes.
ashleymills 0:3d62a105fd34 232 *
ashleymills 0:3d62a105fd34 233 * \return 0 on success, 1 on failure.
ashleymills 0:3d62a105fd34 234 */
ashleymills 0:3d62a105fd34 235 int CoapPDU::reset() {
ashleymills 0:3d62a105fd34 236 // pdu
ashleymills 0:3d62a105fd34 237 memset(_pdu,0x00,_bufferLength);
ashleymills 0:3d62a105fd34 238 // packet always has at least a header
ashleymills 0:3d62a105fd34 239 _pduLength = 4;
ashleymills 0:3d62a105fd34 240
ashleymills 0:3d62a105fd34 241 // options
ashleymills 0:3d62a105fd34 242 _numOptions = 0;
ashleymills 0:3d62a105fd34 243 _maxAddedOptionNumber = 0;
ashleymills 0:3d62a105fd34 244 // payload
ashleymills 0:3d62a105fd34 245 _payloadPointer = NULL;
ashleymills 0:3d62a105fd34 246 _payloadLength = 0;
ashleymills 0:3d62a105fd34 247 return 0;
ashleymills 0:3d62a105fd34 248 }
ashleymills 0:3d62a105fd34 249
ashleymills 0:3d62a105fd34 250 /// Validates a PDU constructed using an external buffer.
ashleymills 0:3d62a105fd34 251 /**
ashleymills 0:3d62a105fd34 252 * When a CoapPDU is constructed using an external buffer, the programmer must call this function to
ashleymills 0:3d62a105fd34 253 * check that the received PDU is a valid CoAP PDU.
ashleymills 0:3d62a105fd34 254 *
ashleymills 0:3d62a105fd34 255 * \warning The validation call parses the PDU structure to set some internal parameters. If you do
ashleymills 0:3d62a105fd34 256 * not validate the PDU, then the behaviour of member access functions will be undefined.
ashleymills 0:3d62a105fd34 257 *
ashleymills 0:3d62a105fd34 258 * \return 1 if the PDU validates correctly, 0 if not. XXX maybe add some error codes
ashleymills 0:3d62a105fd34 259 */
ashleymills 0:3d62a105fd34 260 int CoapPDU::validate() {
ashleymills 0:3d62a105fd34 261 if(_pduLength<4) {
ashleymills 0:3d62a105fd34 262 DBG("PDU has to be a minimum of 4 bytes. This: %d bytes",_pduLength);
ashleymills 0:3d62a105fd34 263 return 0;
ashleymills 0:3d62a105fd34 264 }
ashleymills 0:3d62a105fd34 265
ashleymills 0:3d62a105fd34 266 // check header
ashleymills 0:3d62a105fd34 267 // 0 1 2 3
ashleymills 0:3d62a105fd34 268 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
ashleymills 0:3d62a105fd34 269 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ashleymills 0:3d62a105fd34 270 // |Ver| T | TKL | Code | Message ID |
ashleymills 0:3d62a105fd34 271 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ashleymills 0:3d62a105fd34 272 // | Token (if any, TKL bytes) ...
ashleymills 0:3d62a105fd34 273 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ashleymills 0:3d62a105fd34 274 // | Options (if any) ...
ashleymills 0:3d62a105fd34 275 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ashleymills 0:3d62a105fd34 276 // |1 1 1 1 1 1 1 1| Payload (if any) ...
ashleymills 0:3d62a105fd34 277 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ashleymills 0:3d62a105fd34 278
ashleymills 0:3d62a105fd34 279 DBG("Version: %d",getVersion());
ashleymills 0:3d62a105fd34 280 DBG("Type: %d",getType());
ashleymills 0:3d62a105fd34 281
ashleymills 0:3d62a105fd34 282 // token length must be between 0 and 8
ashleymills 0:3d62a105fd34 283 int tokenLength = getTokenLength();
ashleymills 0:3d62a105fd34 284 if(tokenLength<0||tokenLength>8) {
ashleymills 0:3d62a105fd34 285 DBG("Invalid token length: %d",tokenLength);
ashleymills 0:3d62a105fd34 286 return 0;
ashleymills 0:3d62a105fd34 287 }
ashleymills 0:3d62a105fd34 288 DBG("Token length: %d",tokenLength);
ashleymills 0:3d62a105fd34 289 // check total length
ashleymills 0:3d62a105fd34 290 if((COAP_HDR_SIZE+tokenLength)>_pduLength) {
ashleymills 0:3d62a105fd34 291 DBG("Token length would make pdu longer than actual length.");
ashleymills 0:3d62a105fd34 292 return 0;
ashleymills 0:3d62a105fd34 293 }
ashleymills 0:3d62a105fd34 294
ashleymills 0:3d62a105fd34 295 // check that code is valid
ashleymills 0:3d62a105fd34 296 CoapPDU::Code code = getCode();
ashleymills 0:3d62a105fd34 297 if(code<COAP_EMPTY ||
ashleymills 0:3d62a105fd34 298 (code>COAP_DELETE&&code<COAP_CREATED) ||
ashleymills 0:3d62a105fd34 299 (code>COAP_CONTENT&&code<COAP_BAD_REQUEST) ||
ashleymills 0:3d62a105fd34 300 (code>COAP_NOT_ACCEPTABLE&&code<COAP_PRECONDITION_FAILED) ||
ashleymills 0:3d62a105fd34 301 (code==0x8E) ||
ashleymills 0:3d62a105fd34 302 (code>COAP_UNSUPPORTED_CONTENT_FORMAT&&code<COAP_INTERNAL_SERVER_ERROR) ||
ashleymills 0:3d62a105fd34 303 (code>COAP_PROXYING_NOT_SUPPORTED) ) {
ashleymills 0:3d62a105fd34 304 DBG("Invalid CoAP code: %d",code);
ashleymills 0:3d62a105fd34 305 return 0;
ashleymills 0:3d62a105fd34 306 }
ashleymills 0:3d62a105fd34 307 DBG("CoAP code: %d",code);
ashleymills 0:3d62a105fd34 308
ashleymills 0:3d62a105fd34 309 // token can be anything so nothing to check
ashleymills 0:3d62a105fd34 310
ashleymills 0:3d62a105fd34 311 // check that options all make sense
ashleymills 0:3d62a105fd34 312 uint16_t optionDelta =0, optionNumber = 0, optionValueLength = 0;
ashleymills 0:3d62a105fd34 313 int totalLength = 0;
ashleymills 0:3d62a105fd34 314
ashleymills 0:3d62a105fd34 315 // first option occurs after token
ashleymills 0:3d62a105fd34 316 int optionPos = COAP_HDR_SIZE + getTokenLength();
ashleymills 0:3d62a105fd34 317
ashleymills 0:3d62a105fd34 318 // may be 0 options
ashleymills 0:3d62a105fd34 319 if(optionPos==_pduLength) {
ashleymills 0:3d62a105fd34 320 DBG("No options. No payload.");
ashleymills 0:3d62a105fd34 321 _numOptions = 0;
ashleymills 0:3d62a105fd34 322 _payloadLength = 0;
ashleymills 0:3d62a105fd34 323 return 1;
ashleymills 0:3d62a105fd34 324 }
ashleymills 0:3d62a105fd34 325
ashleymills 0:3d62a105fd34 326 int bytesRemaining = _pduLength-optionPos;
ashleymills 0:3d62a105fd34 327 int numOptions = 0;
ashleymills 0:3d62a105fd34 328 uint8_t upperNibble = 0x00, lowerNibble = 0x00;
ashleymills 0:3d62a105fd34 329
ashleymills 0:3d62a105fd34 330 // walk over options and record information
ashleymills 0:3d62a105fd34 331 while(1) {
ashleymills 0:3d62a105fd34 332 // check for payload marker
ashleymills 0:3d62a105fd34 333 if(bytesRemaining>0) {
ashleymills 0:3d62a105fd34 334 uint8_t optionHeader = _pdu[optionPos];
ashleymills 0:3d62a105fd34 335 if(optionHeader==0xFF) {
ashleymills 0:3d62a105fd34 336 // payload
ashleymills 0:3d62a105fd34 337 if(bytesRemaining>1) {
ashleymills 0:3d62a105fd34 338 _payloadPointer = &_pdu[optionPos+1];
ashleymills 0:3d62a105fd34 339 _payloadLength = (bytesRemaining-1);
ashleymills 0:3d62a105fd34 340 _numOptions = numOptions;
ashleymills 0:3d62a105fd34 341 DBG("Payload found, length: %d",_payloadLength);
ashleymills 0:3d62a105fd34 342 return 1;
ashleymills 0:3d62a105fd34 343 }
ashleymills 0:3d62a105fd34 344 // payload marker but no payload
ashleymills 0:3d62a105fd34 345 _payloadPointer = NULL;
ashleymills 0:3d62a105fd34 346 _payloadLength = 0;
ashleymills 0:3d62a105fd34 347 DBG("Payload marker but no payload.");
ashleymills 0:3d62a105fd34 348 return 0;
ashleymills 0:3d62a105fd34 349 }
ashleymills 0:3d62a105fd34 350
ashleymills 0:3d62a105fd34 351 // check that option delta and option length are valid values
ashleymills 0:3d62a105fd34 352 upperNibble = (optionHeader & 0xF0) >> 4;
ashleymills 0:3d62a105fd34 353 lowerNibble = (optionHeader & 0x0F);
ashleymills 0:3d62a105fd34 354 if(upperNibble==0x0F||lowerNibble==0x0F) {
ashleymills 0:3d62a105fd34 355 DBG("Expected option header or payload marker, got: 0x%x%x",upperNibble,lowerNibble);
ashleymills 0:3d62a105fd34 356 return 0;
ashleymills 0:3d62a105fd34 357 }
ashleymills 0:3d62a105fd34 358 DBG("Option header byte appears sane: 0x%x%x",upperNibble,lowerNibble);
ashleymills 0:3d62a105fd34 359 } else {
ashleymills 0:3d62a105fd34 360 DBG("No more data. No payload.");
ashleymills 0:3d62a105fd34 361 _payloadPointer = NULL;
ashleymills 0:3d62a105fd34 362 _payloadLength = 0;
ashleymills 0:3d62a105fd34 363 _numOptions = numOptions;
ashleymills 0:3d62a105fd34 364 return 1;
ashleymills 0:3d62a105fd34 365 }
ashleymills 0:3d62a105fd34 366
ashleymills 0:3d62a105fd34 367 // skip over option header byte
ashleymills 0:3d62a105fd34 368 bytesRemaining--;
ashleymills 0:3d62a105fd34 369
ashleymills 0:3d62a105fd34 370 // check that there is enough space for the extended delta and length bytes (if any)
ashleymills 0:3d62a105fd34 371 int headerBytesNeeded = computeExtraBytes(upperNibble);
ashleymills 0:3d62a105fd34 372 DBG("%d extra bytes needed for extended delta",headerBytesNeeded);
ashleymills 0:3d62a105fd34 373 if(headerBytesNeeded>bytesRemaining) {
ashleymills 0:3d62a105fd34 374 DBG("Not enough space for extended option delta, needed %d, have %d.",headerBytesNeeded,bytesRemaining);
ashleymills 0:3d62a105fd34 375 return 0;
ashleymills 0:3d62a105fd34 376 }
ashleymills 0:3d62a105fd34 377 headerBytesNeeded += computeExtraBytes(lowerNibble);
ashleymills 0:3d62a105fd34 378 if(headerBytesNeeded>bytesRemaining) {
ashleymills 0:3d62a105fd34 379 DBG("Not enough space for extended option length, needed %d, have %d.",
ashleymills 0:3d62a105fd34 380 (headerBytesNeeded-computeExtraBytes(upperNibble)),bytesRemaining);
ashleymills 0:3d62a105fd34 381 return 0;
ashleymills 0:3d62a105fd34 382 }
ashleymills 0:3d62a105fd34 383 DBG("Enough space for extended delta and length: %d, continuing.",headerBytesNeeded);
ashleymills 0:3d62a105fd34 384
ashleymills 0:3d62a105fd34 385 // extract option details
ashleymills 0:3d62a105fd34 386 optionDelta = getOptionDelta(&_pdu[optionPos]);
ashleymills 0:3d62a105fd34 387 optionNumber += optionDelta;
ashleymills 0:3d62a105fd34 388 optionValueLength = getOptionValueLength(&_pdu[optionPos]);
ashleymills 0:3d62a105fd34 389 DBG("Got option: %d with length %d",optionNumber,optionValueLength);
ashleymills 0:3d62a105fd34 390 // compute total length
ashleymills 0:3d62a105fd34 391 totalLength = 1; // mandatory header
ashleymills 0:3d62a105fd34 392 totalLength += computeExtraBytes(optionDelta);
ashleymills 0:3d62a105fd34 393 totalLength += computeExtraBytes(optionValueLength);
ashleymills 0:3d62a105fd34 394 totalLength += optionValueLength;
ashleymills 0:3d62a105fd34 395 // check there is enough space
ashleymills 0:3d62a105fd34 396 if(optionPos+totalLength>_pduLength) {
ashleymills 0:3d62a105fd34 397 DBG("Not enough space for option payload, needed %d, have %d.",(totalLength-headerBytesNeeded-1),_pduLength-optionPos);
ashleymills 0:3d62a105fd34 398 return 0;
ashleymills 0:3d62a105fd34 399 }
ashleymills 0:3d62a105fd34 400 DBG("Enough space for option payload: %d %d",optionValueLength,(totalLength-headerBytesNeeded-1));
ashleymills 0:3d62a105fd34 401
ashleymills 0:3d62a105fd34 402 // recompute bytesRemaining
ashleymills 0:3d62a105fd34 403 bytesRemaining -= totalLength;
ashleymills 0:3d62a105fd34 404 bytesRemaining++; // correct for previous --
ashleymills 0:3d62a105fd34 405
ashleymills 0:3d62a105fd34 406 // move to next option
ashleymills 0:3d62a105fd34 407 optionPos += totalLength;
ashleymills 0:3d62a105fd34 408
ashleymills 0:3d62a105fd34 409 // inc number of options XXX
ashleymills 0:3d62a105fd34 410 numOptions++;
ashleymills 0:3d62a105fd34 411 }
ashleymills 0:3d62a105fd34 412
ashleymills 0:3d62a105fd34 413 return 1;
ashleymills 0:3d62a105fd34 414 }
ashleymills 0:3d62a105fd34 415
ashleymills 0:3d62a105fd34 416 /// Destructor. Does not free buffer if constructor passed an external buffer.
ashleymills 0:3d62a105fd34 417 /**
ashleymills 0:3d62a105fd34 418 * The destructor acts differently, depending on how the object was initially constructed (from buffer or not):
ashleymills 0:3d62a105fd34 419 *
ashleymills 0:3d62a105fd34 420 * -# CoapPDU::CoapPDU()
ashleymills 0:3d62a105fd34 421 *
ashleymills 0:3d62a105fd34 422 * Complete object is destroyed.
ashleymills 0:3d62a105fd34 423 *
ashleymills 0:3d62a105fd34 424 * -# CoapPDU::CoapPDU(uint8_t *pdu, int pduLength)
ashleymills 0:3d62a105fd34 425 *
ashleymills 0:3d62a105fd34 426 * Only object container is destroyed. \b pdu is left intact.
ashleymills 0:3d62a105fd34 427 *
ashleymills 0:3d62a105fd34 428 * -# CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)
ashleymills 0:3d62a105fd34 429 *
ashleymills 0:3d62a105fd34 430 * Only object container is destroyed. \b pdu is left intact.
ashleymills 0:3d62a105fd34 431 *
ashleymills 0:3d62a105fd34 432 */
ashleymills 0:3d62a105fd34 433 CoapPDU::~CoapPDU() {
ashleymills 0:3d62a105fd34 434 if(!_constructedFromBuffer) {
ashleymills 0:3d62a105fd34 435 free(_pdu);
ashleymills 0:3d62a105fd34 436 }
ashleymills 0:3d62a105fd34 437 }
ashleymills 0:3d62a105fd34 438
ashleymills 0:3d62a105fd34 439 /// Returns a pointer to the internal buffer.
ashleymills 0:3d62a105fd34 440 uint8_t* CoapPDU::getPDUPointer() {
ashleymills 0:3d62a105fd34 441 return _pdu;
ashleymills 0:3d62a105fd34 442 }
ashleymills 0:3d62a105fd34 443
ashleymills 0:3d62a105fd34 444 /// Set the PDU length to the length specified.
ashleymills 0:3d62a105fd34 445 /**
ashleymills 0:3d62a105fd34 446 * This is used when re-using a PDU container before calling CoapPDU::validate() as it
ashleymills 0:3d62a105fd34 447 * is not possible to deduce the length of a PDU since the payload has no length marker.
ashleymills 0:3d62a105fd34 448 * \param len The length of the PDU
ashleymills 0:3d62a105fd34 449 */
ashleymills 0:3d62a105fd34 450 void CoapPDU::setPDULength(int len) {
ashleymills 0:3d62a105fd34 451 _pduLength = len;
ashleymills 0:3d62a105fd34 452 }
ashleymills 0:3d62a105fd34 453
ashleymills 1:5eec2844ad47 454 /// Shorthand function for setting a resource URI.
ashleymills 1:5eec2844ad47 455 /**
ashleymills 1:5eec2844ad47 456 * Calls CoapPDU::setURI(uri,strlen(uri).
ashleymills 1:5eec2844ad47 457 */
ashleymills 1:5eec2844ad47 458 int CoapPDU::setURI(char *uri) {
ashleymills 1:5eec2844ad47 459 return setURI(uri,strlen(uri));
ashleymills 1:5eec2844ad47 460 }
ashleymills 0:3d62a105fd34 461
ashleymills 0:3d62a105fd34 462 /// Shorthand function for setting a resource URI.
ashleymills 0:3d62a105fd34 463 /**
ashleymills 0:3d62a105fd34 464 * This will parse the supplied \b uri and construct enough URI_PATH CoAP options to encode it.
ashleymills 0:3d62a105fd34 465 * The options are added to the PDU.
ashleymills 0:3d62a105fd34 466 *
ashleymills 0:3d62a105fd34 467 * At present queries are not handled. TODO Implement queries.
ashleymills 0:3d62a105fd34 468 *
ashleymills 0:3d62a105fd34 469 * \note This uses an internal buffer of 16 bytes to manipulate strings. The internal buffer will be
ashleymills 0:3d62a105fd34 470 * expanded dynamically if necessary (path component longer than 16 bytes). The internal buffer will
ashleymills 0:3d62a105fd34 471 * be freed before the function returns.
ashleymills 0:3d62a105fd34 472 *
ashleymills 0:3d62a105fd34 473 * \param uri The uri to parse.
ashleymills 0:3d62a105fd34 474 * \param urilen The length of the uri to parse.
ashleymills 0:3d62a105fd34 475 *
ashleymills 0:3d62a105fd34 476 * \return 1 on success, 0 on failure.
ashleymills 0:3d62a105fd34 477 */
ashleymills 0:3d62a105fd34 478 int CoapPDU::setURI(char *uri, int urilen) {
ashleymills 0:3d62a105fd34 479 // only '/' and alphabetic chars allowed
ashleymills 0:3d62a105fd34 480 // very simple splitting done
ashleymills 0:3d62a105fd34 481
ashleymills 0:3d62a105fd34 482 // sanitation
ashleymills 0:3d62a105fd34 483 if(urilen<=0||uri==NULL) {
ashleymills 0:3d62a105fd34 484 DBG("Null or zero-length uri passed.");
ashleymills 0:3d62a105fd34 485 return 1;
ashleymills 0:3d62a105fd34 486 }
ashleymills 0:3d62a105fd34 487
ashleymills 0:3d62a105fd34 488 // single character URI path (including '/' case)
ashleymills 0:3d62a105fd34 489 if(urilen==1) {
ashleymills 0:3d62a105fd34 490 addOption(COAP_OPTION_URI_PATH,1,(uint8_t*)uri);
ashleymills 0:3d62a105fd34 491 return 0;
ashleymills 0:3d62a105fd34 492 }
ashleymills 0:3d62a105fd34 493
ashleymills 0:3d62a105fd34 494 // local vars
ashleymills 0:3d62a105fd34 495 char *startP=uri,*endP=NULL;
ashleymills 0:3d62a105fd34 496 int oLen = 0;
ashleymills 0:3d62a105fd34 497 int bufSpace = 16;
ashleymills 0:3d62a105fd34 498 char *uriBuf = (char*)malloc(bufSpace*sizeof(char));
ashleymills 0:3d62a105fd34 499 if(uriBuf==NULL) {
ashleymills 0:3d62a105fd34 500 DBG("Error allocating temporary memory.");
ashleymills 0:3d62a105fd34 501 return 1;
ashleymills 0:3d62a105fd34 502 }
ashleymills 0:3d62a105fd34 503
ashleymills 0:3d62a105fd34 504 while(1) {
ashleymills 0:3d62a105fd34 505 // stop at end of string
ashleymills 0:3d62a105fd34 506 if(*startP==0x00||*(startP+1)==0x00) {
ashleymills 0:3d62a105fd34 507 break;
ashleymills 0:3d62a105fd34 508 }
ashleymills 0:3d62a105fd34 509
ashleymills 0:3d62a105fd34 510 // ignore leading slash
ashleymills 0:3d62a105fd34 511 if(*startP=='/') {
ashleymills 0:3d62a105fd34 512 DBG("Skipping leading slash");
ashleymills 0:3d62a105fd34 513 startP++;
ashleymills 0:3d62a105fd34 514 }
ashleymills 0:3d62a105fd34 515
ashleymills 0:3d62a105fd34 516 // find next split point
ashleymills 0:3d62a105fd34 517 endP = strchr(startP,'/');
ashleymills 0:3d62a105fd34 518
ashleymills 0:3d62a105fd34 519 // might not be another slash
ashleymills 0:3d62a105fd34 520 if(endP==NULL) {
ashleymills 0:3d62a105fd34 521 DBG("Ending out of slash");
ashleymills 0:3d62a105fd34 522 endP = uri+urilen;
ashleymills 0:3d62a105fd34 523 }
ashleymills 0:3d62a105fd34 524
ashleymills 0:3d62a105fd34 525 // get length of segment
ashleymills 0:3d62a105fd34 526 oLen = endP-startP;
ashleymills 0:3d62a105fd34 527
ashleymills 0:3d62a105fd34 528 // copy sequence, make space if necessary
ashleymills 0:3d62a105fd34 529 if((oLen+1)>bufSpace) {
ashleymills 0:3d62a105fd34 530 char *newBuf = (char*)realloc(uriBuf,oLen+1);
ashleymills 0:3d62a105fd34 531 if(newBuf==NULL) {
ashleymills 0:3d62a105fd34 532 DBG("Error making space for temporary buffer");
ashleymills 0:3d62a105fd34 533 free(uriBuf);
ashleymills 0:3d62a105fd34 534 return 1;
ashleymills 0:3d62a105fd34 535 }
ashleymills 0:3d62a105fd34 536 uriBuf = newBuf;
ashleymills 0:3d62a105fd34 537 }
ashleymills 0:3d62a105fd34 538
ashleymills 0:3d62a105fd34 539 // copy into temporary buffer
ashleymills 0:3d62a105fd34 540 memcpy(uriBuf,startP,oLen);
ashleymills 0:3d62a105fd34 541 uriBuf[oLen] = 0x00;
ashleymills 0:3d62a105fd34 542 DBG("Adding URI_PATH %s",uriBuf);
ashleymills 0:3d62a105fd34 543 // add option
ashleymills 0:3d62a105fd34 544 if(addOption(COAP_OPTION_URI_PATH,oLen,(uint8_t*)uriBuf)!=0) {
ashleymills 0:3d62a105fd34 545 DBG("Error adding option");
ashleymills 0:3d62a105fd34 546 return 1;
ashleymills 0:3d62a105fd34 547 }
ashleymills 0:3d62a105fd34 548 startP = endP;
ashleymills 0:3d62a105fd34 549 }
ashleymills 0:3d62a105fd34 550
ashleymills 0:3d62a105fd34 551 // clean up
ashleymills 0:3d62a105fd34 552 free(uriBuf);
ashleymills 0:3d62a105fd34 553 return 0;
ashleymills 0:3d62a105fd34 554 }
ashleymills 1:5eec2844ad47 555 /// Shorthand for adding a URI QUERY to the option list.
ashleymills 1:5eec2844ad47 556 /**
ashleymills 1:5eec2844ad47 557 * Adds a new option to the CoAP PDU that encodes a URI_QUERY.
ashleymills 1:5eec2844ad47 558 *
ashleymills 1:5eec2844ad47 559 * \param query The uri query to encode.
ashleymills 1:5eec2844ad47 560 * \return 0 on success, 1 on failure.
ashleymills 1:5eec2844ad47 561 */
ashleymills 1:5eec2844ad47 562 int CoapPDU::addURIQuery(char *query) {
ashleymills 1:5eec2844ad47 563 return addOption(COAP_OPTION_URI_QUERY,strlen(query),(uint8_t*)query);
ashleymills 1:5eec2844ad47 564 }
ashleymills 0:3d62a105fd34 565
ashleymills 0:3d62a105fd34 566 /// Concatenates any URI_PATH elements into a single string.
ashleymills 0:3d62a105fd34 567 /**
ashleymills 0:3d62a105fd34 568 * Parses the PDU options and extracts all URI_PATH elements, concatenating them into a single string with slash separators.
ashleymills 1:5eec2844ad47 569 * The produced string will be null terminated.
ashleymills 0:3d62a105fd34 570 *
ashleymills 0:3d62a105fd34 571 * \param dst Buffer into which to copy the concatenated path elements.
ashleymills 0:3d62a105fd34 572 * \param dstlen Length of buffer.
ashleymills 0:3d62a105fd34 573 * \param outLen Pointer to integer, into which URI length will be placed.
ashleymills 0:3d62a105fd34 574 *
ashleymills 0:3d62a105fd34 575 * \return 0 on success, 1 on failure. \b outLen will contain the length of the concatenated elements.
ashleymills 0:3d62a105fd34 576 */
ashleymills 0:3d62a105fd34 577 int CoapPDU::getURI(char *dst, int dstlen, int *outLen) {
ashleymills 0:3d62a105fd34 578 if(outLen==NULL) {
ashleymills 0:3d62a105fd34 579 DBG("Output length pointer is NULL");
ashleymills 0:3d62a105fd34 580 return 1;
ashleymills 0:3d62a105fd34 581 }
ashleymills 0:3d62a105fd34 582
ashleymills 0:3d62a105fd34 583 if(dst==NULL) {
ashleymills 0:3d62a105fd34 584 DBG("NULL destination buffer");
ashleymills 0:3d62a105fd34 585 *outLen = 0;
ashleymills 0:3d62a105fd34 586 return 1;
ashleymills 0:3d62a105fd34 587 }
ashleymills 0:3d62a105fd34 588
ashleymills 0:3d62a105fd34 589 // check destination space
ashleymills 0:3d62a105fd34 590 if(dstlen<=0) {
ashleymills 0:3d62a105fd34 591 *dst = 0x00;
ashleymills 0:3d62a105fd34 592 *outLen = 0;
ashleymills 0:3d62a105fd34 593 DBG("Destination buffer too small (0)!");
ashleymills 0:3d62a105fd34 594 return 1;
ashleymills 0:3d62a105fd34 595 }
ashleymills 0:3d62a105fd34 596 // check option count
ashleymills 0:3d62a105fd34 597 if(_numOptions==0) {
ashleymills 0:3d62a105fd34 598 *dst = 0x00;
ashleymills 0:3d62a105fd34 599 *outLen = 0;
ashleymills 0:3d62a105fd34 600 return 0;
ashleymills 0:3d62a105fd34 601 }
ashleymills 0:3d62a105fd34 602 // get options
ashleymills 0:3d62a105fd34 603 CoapPDU::CoapOption *options = getOptions();
ashleymills 0:3d62a105fd34 604 if(options==NULL) {
ashleymills 0:3d62a105fd34 605 *dst = 0x00;
ashleymills 0:3d62a105fd34 606 *outLen = 0;
ashleymills 0:3d62a105fd34 607 return 0;
ashleymills 0:3d62a105fd34 608 }
ashleymills 0:3d62a105fd34 609 // iterate over options to construct URI
ashleymills 0:3d62a105fd34 610 CoapOption *o = NULL;
ashleymills 0:3d62a105fd34 611 int bytesLeft = dstlen-1; // space for 0x00
ashleymills 0:3d62a105fd34 612 int oLen = 0;
ashleymills 0:3d62a105fd34 613 // add slash at beggining
ashleymills 0:3d62a105fd34 614 if(bytesLeft>=1) {
ashleymills 0:3d62a105fd34 615 *dst = '/';
ashleymills 0:3d62a105fd34 616 dst++;
ashleymills 0:3d62a105fd34 617 bytesLeft--;
ashleymills 0:3d62a105fd34 618 } else {
ashleymills 0:3d62a105fd34 619 DBG("No space for initial slash needed 1, got %d",bytesLeft);
ashleymills 0:3d62a105fd34 620 return 1;
ashleymills 0:3d62a105fd34 621 }
ashleymills 0:3d62a105fd34 622 for(int i=0; i<_numOptions; i++) {
ashleymills 0:3d62a105fd34 623 o = &options[i];
ashleymills 0:3d62a105fd34 624 oLen = o->optionValueLength;
ashleymills 0:3d62a105fd34 625 if(o->optionNumber==COAP_OPTION_URI_PATH) {
ashleymills 0:3d62a105fd34 626 // check space
ashleymills 0:3d62a105fd34 627 if(oLen>bytesLeft) {
ashleymills 0:3d62a105fd34 628 DBG("Destination buffer too small, needed %d, got %d",oLen,bytesLeft);
ashleymills 0:3d62a105fd34 629 return 1;
ashleymills 0:3d62a105fd34 630 }
ashleymills 0:3d62a105fd34 631
ashleymills 0:3d62a105fd34 632 // case where single '/' exists
ashleymills 0:3d62a105fd34 633 if(oLen==1&&o->optionValuePointer[0]=='/') {
ashleymills 0:3d62a105fd34 634 *dst = 0x00;
ashleymills 0:3d62a105fd34 635 *outLen = 1;
ashleymills 0:3d62a105fd34 636 return 0;
ashleymills 0:3d62a105fd34 637 }
ashleymills 0:3d62a105fd34 638
ashleymills 0:3d62a105fd34 639 // copy URI path component
ashleymills 0:3d62a105fd34 640 memcpy(dst,o->optionValuePointer,oLen);
ashleymills 0:3d62a105fd34 641
ashleymills 0:3d62a105fd34 642 // adjust counters
ashleymills 0:3d62a105fd34 643 dst += oLen;
ashleymills 0:3d62a105fd34 644 bytesLeft -= oLen;
ashleymills 0:3d62a105fd34 645
ashleymills 0:3d62a105fd34 646 // add slash following (don't know at this point if another option is coming)
ashleymills 0:3d62a105fd34 647 if(bytesLeft>=1) {
ashleymills 0:3d62a105fd34 648 *dst = '/';
ashleymills 0:3d62a105fd34 649 dst++;
ashleymills 0:3d62a105fd34 650 bytesLeft--;
ashleymills 0:3d62a105fd34 651 } else {
ashleymills 0:3d62a105fd34 652 DBG("Ran out of space after processing option");
ashleymills 0:3d62a105fd34 653 return 1;
ashleymills 0:3d62a105fd34 654 }
ashleymills 0:3d62a105fd34 655 }
ashleymills 0:3d62a105fd34 656 }
ashleymills 0:3d62a105fd34 657
ashleymills 0:3d62a105fd34 658 // remove terminating slash
ashleymills 0:3d62a105fd34 659 dst--;
ashleymills 0:3d62a105fd34 660 bytesLeft++;
ashleymills 0:3d62a105fd34 661 // add null terminating byte (always space since reserved)
ashleymills 0:3d62a105fd34 662 *dst = 0x00;
ashleymills 0:3d62a105fd34 663 *outLen = (dstlen-1)-bytesLeft;
ashleymills 0:3d62a105fd34 664 return 0;
ashleymills 0:3d62a105fd34 665 }
ashleymills 0:3d62a105fd34 666
ashleymills 0:3d62a105fd34 667 /// Sets the CoAP version.
ashleymills 0:3d62a105fd34 668 /**
ashleymills 0:3d62a105fd34 669 * \param version CoAP version between 0 and 3.
ashleymills 0:3d62a105fd34 670 * \return 0 on success, 1 on failure.
ashleymills 0:3d62a105fd34 671 */
ashleymills 0:3d62a105fd34 672 int CoapPDU::setVersion(uint8_t version) {
ashleymills 0:3d62a105fd34 673 if(version>3) {
ashleymills 0:3d62a105fd34 674 return 0;
ashleymills 0:3d62a105fd34 675 }
ashleymills 0:3d62a105fd34 676
ashleymills 0:3d62a105fd34 677 _pdu[0] &= 0x3F;
ashleymills 0:3d62a105fd34 678 _pdu[0] |= (version << 6);
ashleymills 0:3d62a105fd34 679 return 1;
ashleymills 0:3d62a105fd34 680 }
ashleymills 0:3d62a105fd34 681
ashleymills 0:3d62a105fd34 682 /**
ashleymills 0:3d62a105fd34 683 * Gets the CoAP Version.
ashleymills 0:3d62a105fd34 684 * @return The CoAP version between 0 and 3.
ashleymills 0:3d62a105fd34 685 */
ashleymills 0:3d62a105fd34 686 uint8_t CoapPDU::getVersion() {
ashleymills 0:3d62a105fd34 687 return (_pdu[0]&0xC0)>>6;
ashleymills 0:3d62a105fd34 688 }
ashleymills 0:3d62a105fd34 689
ashleymills 0:3d62a105fd34 690 /**
ashleymills 0:3d62a105fd34 691 * Sets the type of this CoAP PDU.
ashleymills 0:3d62a105fd34 692 * \param mt The type, one of:
ashleymills 0:3d62a105fd34 693 * - COAP_CONFIRMABLE
ashleymills 0:3d62a105fd34 694 * - COAP_NON_CONFIRMABLE
ashleymills 0:3d62a105fd34 695 * - COAP_ACKNOWLEDGEMENT
ashleymills 0:3d62a105fd34 696 * - COAP_RESET.
ashleymills 0:3d62a105fd34 697 */
ashleymills 0:3d62a105fd34 698 void CoapPDU::setType(CoapPDU::Type mt) {
ashleymills 0:3d62a105fd34 699 _pdu[0] &= 0xCF;
ashleymills 0:3d62a105fd34 700 _pdu[0] |= mt;
ashleymills 0:3d62a105fd34 701 }
ashleymills 0:3d62a105fd34 702
ashleymills 0:3d62a105fd34 703 /// Returns the type of the PDU.
ashleymills 0:3d62a105fd34 704 CoapPDU::Type CoapPDU::getType() {
ashleymills 0:3d62a105fd34 705 return (CoapPDU::Type)(_pdu[0]&0x30);
ashleymills 0:3d62a105fd34 706 }
ashleymills 0:3d62a105fd34 707
ashleymills 0:3d62a105fd34 708
ashleymills 0:3d62a105fd34 709 /// Set the token length.
ashleymills 0:3d62a105fd34 710 /**
ashleymills 0:3d62a105fd34 711 * \param tokenLength The length of the token in bytes, between 0 and 8.
ashleymills 0:3d62a105fd34 712 * \return 0 on success, 1 on failure.
ashleymills 0:3d62a105fd34 713 */
ashleymills 0:3d62a105fd34 714 int CoapPDU::setTokenLength(uint8_t tokenLength) {
ashleymills 0:3d62a105fd34 715 if(tokenLength>8)
ashleymills 0:3d62a105fd34 716 return 1;
ashleymills 0:3d62a105fd34 717
ashleymills 0:3d62a105fd34 718 _pdu[0] &= 0xF0;
ashleymills 0:3d62a105fd34 719 _pdu[0] |= tokenLength;
ashleymills 0:3d62a105fd34 720 return 0;
ashleymills 0:3d62a105fd34 721 }
ashleymills 0:3d62a105fd34 722
ashleymills 0:3d62a105fd34 723 /// Returns the token length.
ashleymills 0:3d62a105fd34 724 int CoapPDU::getTokenLength() {
ashleymills 0:3d62a105fd34 725 return _pdu[0] & 0x0F;
ashleymills 0:3d62a105fd34 726 }
ashleymills 0:3d62a105fd34 727
ashleymills 0:3d62a105fd34 728 /// Returns a pointer to the PDU token.
ashleymills 0:3d62a105fd34 729 uint8_t* CoapPDU::getTokenPointer() {
ashleymills 0:3d62a105fd34 730 if(getTokenLength()==0) {
ashleymills 0:3d62a105fd34 731 return NULL;
ashleymills 0:3d62a105fd34 732 }
ashleymills 0:3d62a105fd34 733 return &_pdu[4];
ashleymills 0:3d62a105fd34 734 }
ashleymills 0:3d62a105fd34 735
ashleymills 0:3d62a105fd34 736 /// Set the PDU token to the supplied byte sequence.
ashleymills 0:3d62a105fd34 737 /**
ashleymills 0:3d62a105fd34 738 * This sets the PDU token to \b token and sets the token length to \b tokenLength.
ashleymills 0:3d62a105fd34 739 * \param token A sequence of bytes representing the token.
ashleymills 0:3d62a105fd34 740 * \param tokenLength The length of the byte sequence.
ashleymills 0:3d62a105fd34 741 * \return 0 on success, 1 on failure.
ashleymills 0:3d62a105fd34 742 */
ashleymills 0:3d62a105fd34 743 int CoapPDU::setToken(uint8_t *token, uint8_t tokenLength) {
ashleymills 0:3d62a105fd34 744 DBG("Setting token");
ashleymills 0:3d62a105fd34 745 if(token==NULL) {
ashleymills 0:3d62a105fd34 746 DBG("NULL pointer passed as token reference");
ashleymills 0:3d62a105fd34 747 return 1;
ashleymills 0:3d62a105fd34 748 }
ashleymills 0:3d62a105fd34 749
ashleymills 0:3d62a105fd34 750 if(tokenLength==0) {
ashleymills 0:3d62a105fd34 751 DBG("Token has zero length");
ashleymills 0:3d62a105fd34 752 return 1;
ashleymills 0:3d62a105fd34 753 }
ashleymills 0:3d62a105fd34 754
ashleymills 0:3d62a105fd34 755 // if tokenLength has not changed, just copy the new value
ashleymills 0:3d62a105fd34 756 uint8_t oldTokenLength = getTokenLength();
ashleymills 0:3d62a105fd34 757 if(tokenLength==oldTokenLength) {
ashleymills 0:3d62a105fd34 758 memcpy((void*)&_pdu[4],token,tokenLength);
ashleymills 0:3d62a105fd34 759 return 0;
ashleymills 0:3d62a105fd34 760 }
ashleymills 0:3d62a105fd34 761
ashleymills 0:3d62a105fd34 762 // otherwise compute new length of PDU
ashleymills 0:3d62a105fd34 763 uint8_t oldPDULength = _pduLength;
ashleymills 0:3d62a105fd34 764 _pduLength -= oldTokenLength;
ashleymills 0:3d62a105fd34 765 _pduLength += tokenLength;
ashleymills 0:3d62a105fd34 766
ashleymills 0:3d62a105fd34 767 // now, have to shift old memory around, but shift direction depends
ashleymills 0:3d62a105fd34 768 // whether pdu is now bigger or smaller
ashleymills 0:3d62a105fd34 769 if(_pduLength>oldPDULength) {
ashleymills 0:3d62a105fd34 770 // new PDU is bigger, need to allocate space for new PDU
ashleymills 0:3d62a105fd34 771 if(!_constructedFromBuffer) {
ashleymills 0:3d62a105fd34 772 uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);
ashleymills 0:3d62a105fd34 773 if(newMemory==NULL) {
ashleymills 0:3d62a105fd34 774 // malloc failed
ashleymills 0:3d62a105fd34 775 DBG("Failed to allocate memory for token");
ashleymills 0:3d62a105fd34 776 _pduLength = oldPDULength;
ashleymills 0:3d62a105fd34 777 return 1;
ashleymills 0:3d62a105fd34 778 }
ashleymills 0:3d62a105fd34 779 _pdu = newMemory;
ashleymills 0:3d62a105fd34 780 _bufferLength = _pduLength;
ashleymills 0:3d62a105fd34 781 } else {
ashleymills 0:3d62a105fd34 782 // constructed from buffer, check space
ashleymills 0:3d62a105fd34 783 if(_pduLength>_bufferLength) {
ashleymills 0:3d62a105fd34 784 DBG("Buffer too small to contain token, needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength);
ashleymills 0:3d62a105fd34 785 _pduLength = oldPDULength;
ashleymills 0:3d62a105fd34 786 return 1;
ashleymills 0:3d62a105fd34 787 }
ashleymills 0:3d62a105fd34 788 }
ashleymills 0:3d62a105fd34 789
ashleymills 0:3d62a105fd34 790 // and then shift everything after token up to end of new PDU
ashleymills 0:3d62a105fd34 791 // memory overlaps so do this manually so to avoid additional mallocs
ashleymills 0:3d62a105fd34 792 int shiftOffset = _pduLength-oldPDULength;
ashleymills 0:3d62a105fd34 793 int shiftAmount = _pduLength-tokenLength-COAP_HDR_SIZE; // everything after token
ashleymills 0:3d62a105fd34 794 shiftPDUUp(shiftOffset,shiftAmount);
ashleymills 0:3d62a105fd34 795
ashleymills 0:3d62a105fd34 796 // now copy the token into the new space and set official token length
ashleymills 0:3d62a105fd34 797 memcpy((void*)&_pdu[4],token,tokenLength);
ashleymills 0:3d62a105fd34 798 setTokenLength(tokenLength);
ashleymills 0:3d62a105fd34 799
ashleymills 0:3d62a105fd34 800 // and return success
ashleymills 0:3d62a105fd34 801 return 0;
ashleymills 0:3d62a105fd34 802 }
ashleymills 0:3d62a105fd34 803
ashleymills 0:3d62a105fd34 804 // new PDU is smaller, copy the new token value over the old one
ashleymills 0:3d62a105fd34 805 memcpy((void*)&_pdu[4],token,tokenLength);
ashleymills 0:3d62a105fd34 806 // and shift everything after the new token down
ashleymills 0:3d62a105fd34 807 int startLocation = COAP_HDR_SIZE+tokenLength;
ashleymills 0:3d62a105fd34 808 int shiftOffset = oldPDULength-_pduLength;
ashleymills 0:3d62a105fd34 809 int shiftAmount = oldPDULength-oldTokenLength-COAP_HDR_SIZE;
ashleymills 0:3d62a105fd34 810 shiftPDUDown(startLocation,shiftOffset,shiftAmount);
ashleymills 0:3d62a105fd34 811 // then reduce size of buffer
ashleymills 0:3d62a105fd34 812 if(!_constructedFromBuffer) {
ashleymills 0:3d62a105fd34 813 uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);
ashleymills 0:3d62a105fd34 814 if(newMemory==NULL) {
ashleymills 0:3d62a105fd34 815 // malloc failed, PDU in inconsistent state
ashleymills 0:3d62a105fd34 816 DBG("Failed to shrink PDU for new token. PDU probably broken");
ashleymills 0:3d62a105fd34 817 return 1;
ashleymills 0:3d62a105fd34 818 }
ashleymills 0:3d62a105fd34 819 _pdu = newMemory;
ashleymills 0:3d62a105fd34 820 _bufferLength = _pduLength;
ashleymills 0:3d62a105fd34 821 }
ashleymills 0:3d62a105fd34 822
ashleymills 0:3d62a105fd34 823 // and officially set the new tokenLength
ashleymills 0:3d62a105fd34 824 setTokenLength(tokenLength);
ashleymills 0:3d62a105fd34 825 return 0;
ashleymills 0:3d62a105fd34 826 }
ashleymills 0:3d62a105fd34 827
ashleymills 0:3d62a105fd34 828 /// Sets the CoAP response code
ashleymills 0:3d62a105fd34 829 void CoapPDU::setCode(CoapPDU::Code code) {
ashleymills 0:3d62a105fd34 830 _pdu[1] = code;
ashleymills 0:3d62a105fd34 831 // there is a limited set of response codes
ashleymills 0:3d62a105fd34 832 }
ashleymills 0:3d62a105fd34 833
ashleymills 0:3d62a105fd34 834 /// Gets the CoAP response code
ashleymills 0:3d62a105fd34 835 CoapPDU::Code CoapPDU::getCode() {
ashleymills 0:3d62a105fd34 836 return (CoapPDU::Code)_pdu[1];
ashleymills 0:3d62a105fd34 837 }
ashleymills 1:5eec2844ad47 838
ashleymills 1:5eec2844ad47 839
ashleymills 1:5eec2844ad47 840 /// Converts a http status code as an integer, to a CoAP code.
ashleymills 1:5eec2844ad47 841 /**
ashleymills 1:5eec2844ad47 842 * \param httpStatus the HTTP status code as an integer (e.g 200)
ashleymills 1:5eec2844ad47 843 * \return The correct corresponding CoapPDU::Code on success,
ashleymills 1:5eec2844ad47 844 * CoapPDU::COAP_UNDEFINED_CODE on failure.
ashleymills 1:5eec2844ad47 845 */
ashleymills 1:5eec2844ad47 846 CoapPDU::Code CoapPDU::httpStatusToCode(int httpStatus) {
ashleymills 1:5eec2844ad47 847 switch(httpStatus) {
ashleymills 1:5eec2844ad47 848 case 1:
ashleymills 1:5eec2844ad47 849 return CoapPDU::COAP_GET;
ashleymills 1:5eec2844ad47 850 case 2:
ashleymills 1:5eec2844ad47 851 return CoapPDU::COAP_POST;
ashleymills 1:5eec2844ad47 852 case 3:
ashleymills 1:5eec2844ad47 853 return CoapPDU::COAP_PUT;
ashleymills 1:5eec2844ad47 854 case 4:
ashleymills 1:5eec2844ad47 855 return CoapPDU::COAP_DELETE;
ashleymills 1:5eec2844ad47 856 case 201:
ashleymills 1:5eec2844ad47 857 return CoapPDU::COAP_CREATED;
ashleymills 1:5eec2844ad47 858 case 202:
ashleymills 1:5eec2844ad47 859 return CoapPDU::COAP_DELETED;
ashleymills 1:5eec2844ad47 860 case 203:
ashleymills 1:5eec2844ad47 861 return CoapPDU::COAP_VALID;
ashleymills 1:5eec2844ad47 862 case 204:
ashleymills 1:5eec2844ad47 863 return CoapPDU::COAP_CHANGED;
ashleymills 1:5eec2844ad47 864 case 205:
ashleymills 1:5eec2844ad47 865 return CoapPDU::COAP_CONTENT;
ashleymills 1:5eec2844ad47 866 case 400:
ashleymills 1:5eec2844ad47 867 return CoapPDU::COAP_BAD_REQUEST;
ashleymills 1:5eec2844ad47 868 case 401:
ashleymills 1:5eec2844ad47 869 return CoapPDU::COAP_UNAUTHORIZED;
ashleymills 1:5eec2844ad47 870 case 402:
ashleymills 1:5eec2844ad47 871 return CoapPDU::COAP_BAD_OPTION;
ashleymills 1:5eec2844ad47 872 case 403:
ashleymills 1:5eec2844ad47 873 return CoapPDU::COAP_FORBIDDEN;
ashleymills 1:5eec2844ad47 874 case 404:
ashleymills 1:5eec2844ad47 875 return CoapPDU::COAP_NOT_FOUND;
ashleymills 1:5eec2844ad47 876 case 405:
ashleymills 1:5eec2844ad47 877 return CoapPDU::COAP_METHOD_NOT_ALLOWED;
ashleymills 1:5eec2844ad47 878 case 406:
ashleymills 1:5eec2844ad47 879 return CoapPDU::COAP_NOT_ACCEPTABLE;
ashleymills 1:5eec2844ad47 880 case 412:
ashleymills 1:5eec2844ad47 881 return CoapPDU::COAP_PRECONDITION_FAILED;
ashleymills 1:5eec2844ad47 882 case 413:
ashleymills 1:5eec2844ad47 883 return CoapPDU::COAP_REQUEST_ENTITY_TOO_LARGE;
ashleymills 1:5eec2844ad47 884 case 415:
ashleymills 1:5eec2844ad47 885 return CoapPDU::COAP_UNSUPPORTED_CONTENT_FORMAT;
ashleymills 1:5eec2844ad47 886 case 500:
ashleymills 1:5eec2844ad47 887 return CoapPDU::COAP_INTERNAL_SERVER_ERROR;
ashleymills 1:5eec2844ad47 888 case 501:
ashleymills 1:5eec2844ad47 889 return CoapPDU::COAP_NOT_IMPLEMENTED;
ashleymills 1:5eec2844ad47 890 case 502:
ashleymills 1:5eec2844ad47 891 return CoapPDU::COAP_BAD_GATEWAY;
ashleymills 1:5eec2844ad47 892 case 503:
ashleymills 1:5eec2844ad47 893 return CoapPDU::COAP_SERVICE_UNAVAILABLE;
ashleymills 1:5eec2844ad47 894 case 504:
ashleymills 1:5eec2844ad47 895 return CoapPDU::COAP_GATEWAY_TIMEOUT;
ashleymills 1:5eec2844ad47 896 case 505:
ashleymills 1:5eec2844ad47 897 return CoapPDU::COAP_PROXYING_NOT_SUPPORTED;
ashleymills 1:5eec2844ad47 898 default:
ashleymills 1:5eec2844ad47 899 return CoapPDU::COAP_UNDEFINED_CODE;
ashleymills 1:5eec2844ad47 900 }
ashleymills 1:5eec2844ad47 901 }
ashleymills 1:5eec2844ad47 902
ashleymills 0:3d62a105fd34 903 /// Set messageID to the supplied value.
ashleymills 0:3d62a105fd34 904 /**
ashleymills 0:3d62a105fd34 905 * \param messageID A 16bit message id.
ashleymills 0:3d62a105fd34 906 * \return 0 on success, 1 on failure.
ashleymills 0:3d62a105fd34 907 */
ashleymills 0:3d62a105fd34 908 int CoapPDU::setMessageID(uint16_t messageID) {
ashleymills 0:3d62a105fd34 909 // message ID is stored in network byte order
ashleymills 0:3d62a105fd34 910 uint16_t networkOrder = htons(messageID);
ashleymills 0:3d62a105fd34 911 // bytes 2 and 3 hold the ID
ashleymills 0:3d62a105fd34 912 _pdu[2] &= 0x00;
ashleymills 0:3d62a105fd34 913 _pdu[2] |= (networkOrder >> 8); // MSB
ashleymills 0:3d62a105fd34 914 _pdu[3] &= 0x00;
ashleymills 0:3d62a105fd34 915 _pdu[3] |= (networkOrder & 0x00FF); // LSB
ashleymills 0:3d62a105fd34 916 return 0;
ashleymills 0:3d62a105fd34 917 }
ashleymills 0:3d62a105fd34 918
ashleymills 0:3d62a105fd34 919 /// Returns the 16 bit message ID of the PDU.
ashleymills 0:3d62a105fd34 920 uint16_t CoapPDU::getMessageID() {
ashleymills 0:3d62a105fd34 921 // mesasge ID is stored in network byteorder
ashleymills 0:3d62a105fd34 922 uint16_t networkOrder = 0x0000;
ashleymills 0:3d62a105fd34 923 networkOrder |= _pdu[2];
ashleymills 0:3d62a105fd34 924 networkOrder <<= 8;
ashleymills 0:3d62a105fd34 925 networkOrder |= _pdu[3];
ashleymills 0:3d62a105fd34 926 return ntohs(networkOrder);
ashleymills 0:3d62a105fd34 927 }
ashleymills 0:3d62a105fd34 928
ashleymills 0:3d62a105fd34 929 /// Returns the length of the PDU.
ashleymills 0:3d62a105fd34 930 int CoapPDU::getPDULength() {
ashleymills 0:3d62a105fd34 931 return _pduLength;
ashleymills 0:3d62a105fd34 932 }
ashleymills 0:3d62a105fd34 933
ashleymills 0:3d62a105fd34 934 /// Return the number of options that the PDU has.
ashleymills 0:3d62a105fd34 935 int CoapPDU::getNumOptions() {
ashleymills 0:3d62a105fd34 936 return _numOptions;
ashleymills 0:3d62a105fd34 937 }
ashleymills 0:3d62a105fd34 938
ashleymills 0:3d62a105fd34 939
ashleymills 0:3d62a105fd34 940 /**
ashleymills 0:3d62a105fd34 941 * This returns the options as a sequence of structs.
ashleymills 0:3d62a105fd34 942 */
ashleymills 0:3d62a105fd34 943 CoapPDU::CoapOption* CoapPDU::getOptions() {
ashleymills 0:3d62a105fd34 944 DBG("getOptions() called, %d options.",_numOptions);
ashleymills 0:3d62a105fd34 945
ashleymills 0:3d62a105fd34 946 uint16_t optionDelta =0, optionNumber = 0, optionValueLength = 0;
ashleymills 0:3d62a105fd34 947 int totalLength = 0;
ashleymills 0:3d62a105fd34 948
ashleymills 0:3d62a105fd34 949 if(_numOptions==0) {
ashleymills 0:3d62a105fd34 950 return NULL;
ashleymills 0:3d62a105fd34 951 }
ashleymills 0:3d62a105fd34 952
ashleymills 0:3d62a105fd34 953 // malloc space for options
ashleymills 0:3d62a105fd34 954 CoapOption *options = (CoapOption*)malloc(_numOptions*sizeof(CoapOption));
ashleymills 0:3d62a105fd34 955
ashleymills 0:3d62a105fd34 956 // first option occurs after token
ashleymills 0:3d62a105fd34 957 int optionPos = COAP_HDR_SIZE + getTokenLength();
ashleymills 0:3d62a105fd34 958
ashleymills 0:3d62a105fd34 959 // walk over options and record information
ashleymills 0:3d62a105fd34 960 for(int i=0; i<_numOptions; i++) {
ashleymills 0:3d62a105fd34 961 // extract option details
ashleymills 0:3d62a105fd34 962 optionDelta = getOptionDelta(&_pdu[optionPos]);
ashleymills 0:3d62a105fd34 963 optionNumber += optionDelta;
ashleymills 0:3d62a105fd34 964 optionValueLength = getOptionValueLength(&_pdu[optionPos]);
ashleymills 0:3d62a105fd34 965 // compute total length
ashleymills 0:3d62a105fd34 966 totalLength = 1; // mandatory header
ashleymills 0:3d62a105fd34 967 totalLength += computeExtraBytes(optionDelta);
ashleymills 0:3d62a105fd34 968 totalLength += computeExtraBytes(optionValueLength);
ashleymills 0:3d62a105fd34 969 totalLength += optionValueLength;
ashleymills 0:3d62a105fd34 970 // record option details
ashleymills 0:3d62a105fd34 971 options[i].optionNumber = optionNumber;
ashleymills 0:3d62a105fd34 972 options[i].optionDelta = optionDelta;
ashleymills 0:3d62a105fd34 973 options[i].optionValueLength = optionValueLength;
ashleymills 0:3d62a105fd34 974 options[i].totalLength = totalLength;
ashleymills 0:3d62a105fd34 975 options[i].optionPointer = &_pdu[optionPos];
ashleymills 0:3d62a105fd34 976 options[i].optionValuePointer = &_pdu[optionPos+totalLength-optionValueLength];
ashleymills 0:3d62a105fd34 977 // move to next option
ashleymills 0:3d62a105fd34 978 optionPos += totalLength;
ashleymills 0:3d62a105fd34 979 }
ashleymills 0:3d62a105fd34 980
ashleymills 0:3d62a105fd34 981 return options;
ashleymills 0:3d62a105fd34 982 }
ashleymills 0:3d62a105fd34 983
ashleymills 0:3d62a105fd34 984 /// Add an option to the PDU.
ashleymills 0:3d62a105fd34 985 /**
ashleymills 0:3d62a105fd34 986 * Unlike other implementations, options can be added in any order, and in-memory manipulation will be
ashleymills 0:3d62a105fd34 987 * performed to ensure the correct ordering of options (they use a delta encoding of option numbers).
ashleymills 0:3d62a105fd34 988 * Re-ordering memory like this incurs a small performance cost, so if you care about this, then you
ashleymills 0:3d62a105fd34 989 * might want to add options in ascending order of option number.
ashleymills 0:3d62a105fd34 990 * \param optionNumber The number of the option, see the enum CoapPDU::Option for shorthand notations.
ashleymills 0:3d62a105fd34 991 * \param optionLength The length of the option payload in bytes.
ashleymills 0:3d62a105fd34 992 * \param optionValue A pointer to the byte sequence that is the option payload (bytes will be copied).
ashleymills 0:3d62a105fd34 993 * \return 0 on success, 1 on failure.
ashleymills 0:3d62a105fd34 994 */
ashleymills 0:3d62a105fd34 995 int CoapPDU::addOption(uint16_t insertedOptionNumber, uint16_t optionValueLength, uint8_t *optionValue) {
ashleymills 0:3d62a105fd34 996 // this inserts the option in memory, and re-computes the deltas accordingly
ashleymills 0:3d62a105fd34 997 // prevOption <-- insertionPosition
ashleymills 0:3d62a105fd34 998 // nextOption
ashleymills 0:3d62a105fd34 999
ashleymills 0:3d62a105fd34 1000 // find insertion location and previous option number
ashleymills 0:3d62a105fd34 1001 uint16_t prevOptionNumber = 0; // option number of option before insertion point
ashleymills 0:3d62a105fd34 1002 int insertionPosition = findInsertionPosition(insertedOptionNumber,&prevOptionNumber);
ashleymills 0:3d62a105fd34 1003 DBG("inserting option at position %d, after option with number: %hu",insertionPosition,prevOptionNumber);
ashleymills 0:3d62a105fd34 1004
ashleymills 0:3d62a105fd34 1005 // compute option delta length
ashleymills 0:3d62a105fd34 1006 uint16_t optionDelta = insertedOptionNumber-prevOptionNumber;
ashleymills 0:3d62a105fd34 1007 uint8_t extraDeltaBytes = computeExtraBytes(optionDelta);
ashleymills 0:3d62a105fd34 1008
ashleymills 0:3d62a105fd34 1009 // compute option length length
ashleymills 0:3d62a105fd34 1010 uint16_t extraLengthBytes = computeExtraBytes(optionValueLength);
ashleymills 0:3d62a105fd34 1011
ashleymills 0:3d62a105fd34 1012 // compute total length of option
ashleymills 0:3d62a105fd34 1013 uint16_t optionLength = COAP_OPTION_HDR_BYTE + extraDeltaBytes + extraLengthBytes + optionValueLength;
ashleymills 0:3d62a105fd34 1014
ashleymills 0:3d62a105fd34 1015 // if this is at the end of the PDU, job is done, just malloc and insert
ashleymills 0:3d62a105fd34 1016 if(insertionPosition==_pduLength) {
ashleymills 0:3d62a105fd34 1017 DBG("Inserting at end of PDU");
ashleymills 0:3d62a105fd34 1018 // optionNumber must be biggest added
ashleymills 0:3d62a105fd34 1019 _maxAddedOptionNumber = insertedOptionNumber;
ashleymills 0:3d62a105fd34 1020
ashleymills 0:3d62a105fd34 1021 // set new PDU length and allocate space for extra option
ashleymills 0:3d62a105fd34 1022 int oldPDULength = _pduLength;
ashleymills 0:3d62a105fd34 1023 _pduLength += optionLength;
ashleymills 0:3d62a105fd34 1024 if(!_constructedFromBuffer) {
ashleymills 0:3d62a105fd34 1025 uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);
ashleymills 0:3d62a105fd34 1026 if(newMemory==NULL) {
ashleymills 0:3d62a105fd34 1027 DBG("Failed to allocate memory for option.");
ashleymills 0:3d62a105fd34 1028 _pduLength = oldPDULength;
ashleymills 0:3d62a105fd34 1029 // malloc failed
ashleymills 0:3d62a105fd34 1030 return 1;
ashleymills 0:3d62a105fd34 1031 }
ashleymills 0:3d62a105fd34 1032 _pdu = newMemory;
ashleymills 0:3d62a105fd34 1033 _bufferLength = _pduLength;
ashleymills 0:3d62a105fd34 1034 } else {
ashleymills 0:3d62a105fd34 1035 // constructed from buffer, check space
ashleymills 0:3d62a105fd34 1036 if(_pduLength>_bufferLength) {
ashleymills 0:3d62a105fd34 1037 DBG("Buffer too small for new option: needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength);
ashleymills 0:3d62a105fd34 1038 _pduLength = oldPDULength;
ashleymills 0:3d62a105fd34 1039 return 1;
ashleymills 0:3d62a105fd34 1040 }
ashleymills 0:3d62a105fd34 1041 }
ashleymills 0:3d62a105fd34 1042
ashleymills 0:3d62a105fd34 1043 // insert option at position
ashleymills 0:3d62a105fd34 1044 insertOption(insertionPosition,optionDelta,optionValueLength,optionValue);
ashleymills 0:3d62a105fd34 1045 _numOptions++;
ashleymills 0:3d62a105fd34 1046 return 0;
ashleymills 0:3d62a105fd34 1047 }
ashleymills 0:3d62a105fd34 1048 // XXX could do 0xFF pdu payload case for changing of dynamically allocated application space SDUs < yeah, if you're insane
ashleymills 0:3d62a105fd34 1049
ashleymills 0:3d62a105fd34 1050 // the next option might (probably) needs it's delta changing
ashleymills 0:3d62a105fd34 1051 // I want to take this into account when allocating space for the new
ashleymills 0:3d62a105fd34 1052 // option, to avoid having to do two mallocs, first get info about this option
ashleymills 0:3d62a105fd34 1053 int nextOptionDelta = getOptionDelta(&_pdu[insertionPosition]);
ashleymills 0:3d62a105fd34 1054 int nextOptionNumber = prevOptionNumber + nextOptionDelta;
ashleymills 0:3d62a105fd34 1055 int nextOptionDeltaBytes = computeExtraBytes(nextOptionDelta);
ashleymills 0:3d62a105fd34 1056 // recompute option delta, relative to inserted option
ashleymills 0:3d62a105fd34 1057 int newNextOptionDelta = nextOptionNumber-insertedOptionNumber;
ashleymills 0:3d62a105fd34 1058 int newNextOptionDeltaBytes = computeExtraBytes(newNextOptionDelta);
ashleymills 0:3d62a105fd34 1059 // determine adjustment
ashleymills 0:3d62a105fd34 1060 int optionDeltaAdjustment = newNextOptionDeltaBytes-nextOptionDeltaBytes;
ashleymills 0:3d62a105fd34 1061
ashleymills 0:3d62a105fd34 1062 // create space for new option, including adjustment space for option delta
ashleymills 0:3d62a105fd34 1063 DBG_PDU();
ashleymills 0:3d62a105fd34 1064 DBG("Creating space");
ashleymills 0:3d62a105fd34 1065 int mallocLength = optionLength+optionDeltaAdjustment;
ashleymills 0:3d62a105fd34 1066 int oldPDULength = _pduLength;
ashleymills 0:3d62a105fd34 1067 _pduLength += mallocLength;
ashleymills 0:3d62a105fd34 1068
ashleymills 0:3d62a105fd34 1069 if(!_constructedFromBuffer) {
ashleymills 0:3d62a105fd34 1070 uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);
ashleymills 0:3d62a105fd34 1071 if(newMemory==NULL) {
ashleymills 0:3d62a105fd34 1072 DBG("Failed to allocate memory for option");
ashleymills 0:3d62a105fd34 1073 _pduLength = oldPDULength;
ashleymills 0:3d62a105fd34 1074 return 1;
ashleymills 0:3d62a105fd34 1075 }
ashleymills 0:3d62a105fd34 1076 _pdu = newMemory;
ashleymills 0:3d62a105fd34 1077 _bufferLength = _pduLength;
ashleymills 0:3d62a105fd34 1078 } else {
ashleymills 0:3d62a105fd34 1079 // constructed from buffer, check space
ashleymills 0:3d62a105fd34 1080 if(_pduLength>_bufferLength) {
ashleymills 0:3d62a105fd34 1081 DBG("Buffer too small to contain option, needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength);
ashleymills 0:3d62a105fd34 1082 _pduLength = oldPDULength;
ashleymills 0:3d62a105fd34 1083 return 1;
ashleymills 0:3d62a105fd34 1084 }
ashleymills 0:3d62a105fd34 1085 }
ashleymills 0:3d62a105fd34 1086
ashleymills 0:3d62a105fd34 1087 // move remainder of PDU data up to create hole for new option
ashleymills 0:3d62a105fd34 1088 DBG_PDU();
ashleymills 0:3d62a105fd34 1089 DBG("Shifting PDU.");
ashleymills 0:3d62a105fd34 1090 shiftPDUUp(mallocLength,_pduLength-(insertionPosition+mallocLength));
ashleymills 0:3d62a105fd34 1091 DBG_PDU();
ashleymills 0:3d62a105fd34 1092
ashleymills 0:3d62a105fd34 1093 // adjust option delta bytes of following option
ashleymills 0:3d62a105fd34 1094 // move the option header to the correct position
ashleymills 0:3d62a105fd34 1095 int nextHeaderPos = insertionPosition+mallocLength;
ashleymills 0:3d62a105fd34 1096 _pdu[nextHeaderPos-optionDeltaAdjustment] = _pdu[nextHeaderPos];
ashleymills 0:3d62a105fd34 1097 nextHeaderPos -= optionDeltaAdjustment;
ashleymills 0:3d62a105fd34 1098 // and set the new value
ashleymills 0:3d62a105fd34 1099 setOptionDelta(nextHeaderPos, newNextOptionDelta);
ashleymills 0:3d62a105fd34 1100
ashleymills 0:3d62a105fd34 1101 // new option shorter
ashleymills 0:3d62a105fd34 1102 // p p n n x x x x x
ashleymills 0:3d62a105fd34 1103 // p p n n x x x x x -
ashleymills 0:3d62a105fd34 1104 // p p - n n x x x x x
ashleymills 0:3d62a105fd34 1105 // p p - - n x x x x x
ashleymills 0:3d62a105fd34 1106 // p p o o n x x x x x
ashleymills 0:3d62a105fd34 1107
ashleymills 0:3d62a105fd34 1108 // new option longer
ashleymills 0:3d62a105fd34 1109 // p p n n x x x x x
ashleymills 0:3d62a105fd34 1110 // p p n n x x x x x - - -
ashleymills 0:3d62a105fd34 1111 // p p - - - n n x x x x x
ashleymills 0:3d62a105fd34 1112 // p p - - n n n x x x x x
ashleymills 0:3d62a105fd34 1113 // p p o o n n n x x x x x
ashleymills 0:3d62a105fd34 1114
ashleymills 0:3d62a105fd34 1115 // note, it can only ever be shorter or the same since if an option was inserted the delta got smaller
ashleymills 0:3d62a105fd34 1116 // but I'll leave that little comment in, just to show that it would work even if the delta got bigger
ashleymills 0:3d62a105fd34 1117
ashleymills 0:3d62a105fd34 1118 // now insert the new option into the gap
ashleymills 0:3d62a105fd34 1119 DBGLX("Inserting new option...");
ashleymills 0:3d62a105fd34 1120 insertOption(insertionPosition,optionDelta,optionValueLength,optionValue);
ashleymills 0:3d62a105fd34 1121 DBGX("done\r\n");
ashleymills 0:3d62a105fd34 1122 DBG_PDU();
ashleymills 0:3d62a105fd34 1123
ashleymills 0:3d62a105fd34 1124 // done, mark it with B!
ashleymills 0:3d62a105fd34 1125 return 0;
ashleymills 0:3d62a105fd34 1126 }
ashleymills 0:3d62a105fd34 1127
ashleymills 0:3d62a105fd34 1128 /// Allocate space for a payload.
ashleymills 0:3d62a105fd34 1129 /**
ashleymills 0:3d62a105fd34 1130 * For dynamically constructed PDUs, this will allocate space for a payload in the object
ashleymills 0:3d62a105fd34 1131 * and return a pointer to it. If the PDU was constructed from a buffer, this doesn't
ashleymills 0:3d62a105fd34 1132 * malloc anything, it just changes the _pduLength and returns the payload pointer.
ashleymills 0:3d62a105fd34 1133 *
ashleymills 0:3d62a105fd34 1134 * \note The pointer returned points into the PDU buffer.
ashleymills 0:3d62a105fd34 1135 * \param len The length of the payload buffer to allocate.
ashleymills 0:3d62a105fd34 1136 * \return Either a pointer to the payload buffer, or NULL if there wasn't enough space / allocation failed.
ashleymills 0:3d62a105fd34 1137 */
ashleymills 0:3d62a105fd34 1138 uint8_t* CoapPDU::mallocPayload(int len) {
ashleymills 0:3d62a105fd34 1139 DBG("Entering mallocPayload");
ashleymills 0:3d62a105fd34 1140 // sanity checks
ashleymills 0:3d62a105fd34 1141 if(len==0) {
ashleymills 0:3d62a105fd34 1142 DBG("Cannot allocate a zero length payload");
ashleymills 0:3d62a105fd34 1143 return NULL;
ashleymills 0:3d62a105fd34 1144 }
ashleymills 0:3d62a105fd34 1145
ashleymills 0:3d62a105fd34 1146 // further sanity
ashleymills 0:3d62a105fd34 1147 if(len==_payloadLength) {
ashleymills 0:3d62a105fd34 1148 DBG("Space for payload of specified length already exists");
ashleymills 0:3d62a105fd34 1149 if(_payloadPointer==NULL) {
ashleymills 0:3d62a105fd34 1150 DBG("Garbage PDU. Payload length is %d, but existing _payloadPointer NULL",_payloadLength);
ashleymills 0:3d62a105fd34 1151 return NULL;
ashleymills 0:3d62a105fd34 1152 }
ashleymills 0:3d62a105fd34 1153 return _payloadPointer;
ashleymills 0:3d62a105fd34 1154 }
ashleymills 0:3d62a105fd34 1155
ashleymills 0:3d62a105fd34 1156 DBG("_bufferLength: %d, _pduLength: %d, _payloadLength: %d",_bufferLength,_pduLength,_payloadLength);
ashleymills 0:3d62a105fd34 1157
ashleymills 0:3d62a105fd34 1158 // might be making payload bigger (including bigger than 0) or smaller
ashleymills 0:3d62a105fd34 1159 int markerSpace = 1;
ashleymills 0:3d62a105fd34 1160 int payloadSpace = len;
ashleymills 0:3d62a105fd34 1161 // is this a resizing?
ashleymills 0:3d62a105fd34 1162 if(_payloadLength!=0) {
ashleymills 0:3d62a105fd34 1163 // marker already exists
ashleymills 0:3d62a105fd34 1164 markerSpace = 0;
ashleymills 0:3d62a105fd34 1165 // compute new payload length (can be negative if shrinking payload)
ashleymills 0:3d62a105fd34 1166 payloadSpace = len-_payloadLength;
ashleymills 0:3d62a105fd34 1167 }
ashleymills 0:3d62a105fd34 1168
ashleymills 0:3d62a105fd34 1169 // make space for payload (and payload marker if necessary)
ashleymills 0:3d62a105fd34 1170 int newLen = _pduLength+payloadSpace+markerSpace;
ashleymills 0:3d62a105fd34 1171 if(!_constructedFromBuffer) {
ashleymills 0:3d62a105fd34 1172 uint8_t* newPDU = (uint8_t*)realloc(_pdu,newLen);
ashleymills 0:3d62a105fd34 1173 if(newPDU==NULL) {
ashleymills 0:3d62a105fd34 1174 DBG("Cannot allocate (or shrink) space for payload");
ashleymills 0:3d62a105fd34 1175 return NULL;
ashleymills 0:3d62a105fd34 1176 }
ashleymills 0:3d62a105fd34 1177 _pdu = newPDU;
ashleymills 0:3d62a105fd34 1178 _bufferLength = newLen;
ashleymills 0:3d62a105fd34 1179 } else {
ashleymills 0:3d62a105fd34 1180 // constructed from buffer, check space
ashleymills 0:3d62a105fd34 1181 DBG("newLen: %d, _bufferLength: %d",newLen,_bufferLength);
ashleymills 0:3d62a105fd34 1182 if(newLen>_bufferLength) {
ashleymills 0:3d62a105fd34 1183 DBG("Buffer too small to contain desired payload, needed %d, got %d.",newLen-_pduLength,_bufferLength-_pduLength);
ashleymills 0:3d62a105fd34 1184 return NULL;
ashleymills 0:3d62a105fd34 1185 }
ashleymills 0:3d62a105fd34 1186 }
ashleymills 0:3d62a105fd34 1187
ashleymills 0:3d62a105fd34 1188 // deal with fresh allocation case separately
ashleymills 0:3d62a105fd34 1189 if(_payloadPointer==NULL) {
ashleymills 0:3d62a105fd34 1190 // set payload marker
ashleymills 0:3d62a105fd34 1191 _pdu[_pduLength] = 0xFF;
ashleymills 0:3d62a105fd34 1192 // payload at end of old PDU
ashleymills 0:3d62a105fd34 1193 _payloadPointer = &_pdu[_pduLength+1];
ashleymills 0:3d62a105fd34 1194 _pduLength = newLen;
ashleymills 0:3d62a105fd34 1195 _payloadLength = len;
ashleymills 0:3d62a105fd34 1196 return _payloadPointer;
ashleymills 0:3d62a105fd34 1197 }
ashleymills 0:3d62a105fd34 1198
ashleymills 0:3d62a105fd34 1199 // otherwise, just adjust length of PDU
ashleymills 0:3d62a105fd34 1200 _pduLength = newLen;
ashleymills 0:3d62a105fd34 1201 _payloadLength = len;
ashleymills 0:3d62a105fd34 1202 DBG("Leaving mallocPayload");
ashleymills 0:3d62a105fd34 1203 return _payloadPointer;
ashleymills 0:3d62a105fd34 1204 }
ashleymills 0:3d62a105fd34 1205
ashleymills 0:3d62a105fd34 1206 /// Set the payload to the byte sequence specified. Allocates memory in dynamic PDU if necessary.
ashleymills 0:3d62a105fd34 1207 /**
ashleymills 0:3d62a105fd34 1208 * This will set the payload to \b payload. It will allocate memory in the case where the PDU was
ashleymills 0:3d62a105fd34 1209 * constructed without an external buffer.
ashleymills 0:3d62a105fd34 1210 *
ashleymills 0:3d62a105fd34 1211 * This will fail either if the fixed buffer isn't big enough, or if memory could not be allocated
ashleymills 0:3d62a105fd34 1212 * in the non-external-buffer case.
ashleymills 0:3d62a105fd34 1213 *
ashleymills 0:3d62a105fd34 1214 * \param payload Pointer to payload byte sequence.
ashleymills 0:3d62a105fd34 1215 * \param len Length of payload byte sequence.
ashleymills 0:3d62a105fd34 1216 * \return 0 on success, 1 on failure.
ashleymills 0:3d62a105fd34 1217 */
ashleymills 0:3d62a105fd34 1218 int CoapPDU::setPayload(uint8_t *payload, int len) {
ashleymills 0:3d62a105fd34 1219 if(payload==NULL) {
ashleymills 0:3d62a105fd34 1220 DBG("NULL payload pointer.");
ashleymills 0:3d62a105fd34 1221 return 1;
ashleymills 0:3d62a105fd34 1222 }
ashleymills 0:3d62a105fd34 1223
ashleymills 0:3d62a105fd34 1224 uint8_t *payloadPointer = mallocPayload(len);
ashleymills 0:3d62a105fd34 1225 if(payloadPointer==NULL) {
ashleymills 0:3d62a105fd34 1226 DBG("Allocation of payload failed");
ashleymills 0:3d62a105fd34 1227 return 1;
ashleymills 0:3d62a105fd34 1228 }
ashleymills 0:3d62a105fd34 1229
ashleymills 0:3d62a105fd34 1230 // copy payload contents
ashleymills 0:3d62a105fd34 1231 memcpy(payloadPointer,payload,len);
ashleymills 0:3d62a105fd34 1232
ashleymills 0:3d62a105fd34 1233 return 0;
ashleymills 0:3d62a105fd34 1234 }
ashleymills 0:3d62a105fd34 1235
ashleymills 0:3d62a105fd34 1236 /// Returns a pointer to the payload buffer.
ashleymills 0:3d62a105fd34 1237 uint8_t* CoapPDU::getPayloadPointer() {
ashleymills 0:3d62a105fd34 1238 return _payloadPointer;
ashleymills 0:3d62a105fd34 1239 }
ashleymills 0:3d62a105fd34 1240
ashleymills 0:3d62a105fd34 1241 /// Gets the length of the payload buffer.
ashleymills 0:3d62a105fd34 1242 int CoapPDU::getPayloadLength() {
ashleymills 0:3d62a105fd34 1243 return _payloadLength;
ashleymills 0:3d62a105fd34 1244 }
ashleymills 0:3d62a105fd34 1245
ashleymills 0:3d62a105fd34 1246 /// Returns a pointer to a buffer which is a copy of the payload buffer (dynamically allocated).
ashleymills 0:3d62a105fd34 1247 uint8_t* CoapPDU::getPayloadCopy() {
ashleymills 0:3d62a105fd34 1248 if(_payloadLength==0) {
ashleymills 0:3d62a105fd34 1249 return NULL;
ashleymills 0:3d62a105fd34 1250 }
ashleymills 0:3d62a105fd34 1251
ashleymills 0:3d62a105fd34 1252 // malloc space for copy
ashleymills 0:3d62a105fd34 1253 uint8_t *payload = (uint8_t*)malloc(_payloadLength);
ashleymills 0:3d62a105fd34 1254 if(payload==NULL) {
ashleymills 0:3d62a105fd34 1255 DBG("Unable to allocate memory for payload");
ashleymills 0:3d62a105fd34 1256 return NULL;
ashleymills 0:3d62a105fd34 1257 }
ashleymills 0:3d62a105fd34 1258
ashleymills 0:3d62a105fd34 1259 // copy and return
ashleymills 0:3d62a105fd34 1260 memcpy(payload,_payloadPointer,_payloadLength);
ashleymills 0:3d62a105fd34 1261 return payload;
ashleymills 0:3d62a105fd34 1262 }
ashleymills 0:3d62a105fd34 1263
ashleymills 0:3d62a105fd34 1264 /// Shorthand for setting the content-format option.
ashleymills 0:3d62a105fd34 1265 /**
ashleymills 0:3d62a105fd34 1266 * Sets the content-format to the specified value (adds an option).
ashleymills 0:3d62a105fd34 1267 * \param format The content format, one of:
ashleymills 0:3d62a105fd34 1268 *
ashleymills 0:3d62a105fd34 1269 * - COAP_CONTENT_FORMAT_TEXT_PLAIN
ashleymills 0:3d62a105fd34 1270 * - COAP_CONTENT_FORMAT_APP_LINK
ashleymills 0:3d62a105fd34 1271 * - COAP_CONTENT_FORMAT_APP_XML
ashleymills 0:3d62a105fd34 1272 * - COAP_CONTENT_FORMAT_APP_OCTET
ashleymills 0:3d62a105fd34 1273 * - COAP_CONTENT_FORMAT_APP_EXI
ashleymills 0:3d62a105fd34 1274 * - COAP_CONTENT_FORMAT_APP_JSON
ashleymills 0:3d62a105fd34 1275 *
ashleymills 0:3d62a105fd34 1276 * \return 0 on success, 1 on failure.
ashleymills 0:3d62a105fd34 1277 */
ashleymills 0:3d62a105fd34 1278 int CoapPDU::setContentFormat(CoapPDU::ContentFormat format) {
ashleymills 0:3d62a105fd34 1279 if(format==0) {
ashleymills 0:3d62a105fd34 1280 // minimal representation means null option value
ashleymills 0:3d62a105fd34 1281 if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,0,NULL)!=0) {
ashleymills 0:3d62a105fd34 1282 DBG("Error setting content format");
ashleymills 0:3d62a105fd34 1283 return 1;
ashleymills 0:3d62a105fd34 1284 }
ashleymills 0:3d62a105fd34 1285 return 0;
ashleymills 0:3d62a105fd34 1286 }
ashleymills 0:3d62a105fd34 1287
ashleymills 0:3d62a105fd34 1288 uint8_t c[2];
ashleymills 0:3d62a105fd34 1289
ashleymills 0:3d62a105fd34 1290 // just use 1 byte if can do it
ashleymills 0:3d62a105fd34 1291 if(format<256) {
ashleymills 0:3d62a105fd34 1292 c[0] = format;
ashleymills 0:3d62a105fd34 1293 if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,1,c)!=0) {
ashleymills 0:3d62a105fd34 1294 DBG("Error setting content format");
ashleymills 0:3d62a105fd34 1295 return 1;
ashleymills 0:3d62a105fd34 1296 }
ashleymills 0:3d62a105fd34 1297 return 0;
ashleymills 0:3d62a105fd34 1298 }
ashleymills 0:3d62a105fd34 1299
ashleymills 0:3d62a105fd34 1300 uint16_t networkOrder = htons(format);
ashleymills 0:3d62a105fd34 1301 c[0] &= 0x00;
ashleymills 0:3d62a105fd34 1302 c[0] |= (networkOrder >> 8); // MSB
ashleymills 0:3d62a105fd34 1303 c[1] &= 0x00;
ashleymills 0:3d62a105fd34 1304 c[1] |= (networkOrder & 0x00FF); // LSB
ashleymills 0:3d62a105fd34 1305 if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,2,c)!=0) {
ashleymills 0:3d62a105fd34 1306 DBG("Error setting content format");
ashleymills 0:3d62a105fd34 1307 return 1;
ashleymills 0:3d62a105fd34 1308 }
ashleymills 0:3d62a105fd34 1309 return 0;
ashleymills 0:3d62a105fd34 1310 }
ashleymills 0:3d62a105fd34 1311
ashleymills 0:3d62a105fd34 1312 /// PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE
ashleymills 0:3d62a105fd34 1313 /// PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE
ashleymills 0:3d62a105fd34 1314
ashleymills 0:3d62a105fd34 1315 /// Moves a block of bytes to end of PDU from given offset.
ashleymills 0:3d62a105fd34 1316 /**
ashleymills 0:3d62a105fd34 1317 * This moves the block of bytes _pdu[_pduLength-1-shiftOffset-shiftAmount] ... _pdu[_pduLength-1-shiftOffset]
ashleymills 0:3d62a105fd34 1318 * to the end of the PDU.
ashleymills 0:3d62a105fd34 1319 * \param shiftOffset End of block to move, relative to end of PDU (-1).
ashleymills 0:3d62a105fd34 1320 * \param shiftAmount Length of block to move.
ashleymills 0:3d62a105fd34 1321 */
ashleymills 0:3d62a105fd34 1322 void CoapPDU::shiftPDUUp(int shiftOffset, int shiftAmount) {
ashleymills 0:3d62a105fd34 1323 DBG("shiftOffset: %d, shiftAmount: %d",shiftOffset,shiftAmount);
ashleymills 0:3d62a105fd34 1324 int destPointer = _pduLength-1;
ashleymills 0:3d62a105fd34 1325 int srcPointer = destPointer-shiftOffset;
ashleymills 0:3d62a105fd34 1326 while(shiftAmount--) {
ashleymills 0:3d62a105fd34 1327 _pdu[destPointer] = _pdu[srcPointer];
ashleymills 0:3d62a105fd34 1328 destPointer--;
ashleymills 0:3d62a105fd34 1329 srcPointer--;
ashleymills 0:3d62a105fd34 1330 }
ashleymills 0:3d62a105fd34 1331 }
ashleymills 0:3d62a105fd34 1332
ashleymills 0:3d62a105fd34 1333 /// Moves a block of bytes down a specified number of steps.
ashleymills 0:3d62a105fd34 1334 /**
ashleymills 0:3d62a105fd34 1335 * Moves the block of bytes _pdu[startLocation+shiftOffset] ... _pdu[startLocation+shiftOffset+shiftAmount]
ashleymills 0:3d62a105fd34 1336 * down to \b startLocation.
ashleymills 0:3d62a105fd34 1337 * \param startLocation Index where to shift the block to.
ashleymills 0:3d62a105fd34 1338 * \param shiftOffset Where the block starts, relative to start index.
ashleymills 0:3d62a105fd34 1339 * \param shiftAmount Length of block to shift.
ashleymills 0:3d62a105fd34 1340 */
ashleymills 0:3d62a105fd34 1341 void CoapPDU::shiftPDUDown(int startLocation, int shiftOffset, int shiftAmount) {
ashleymills 0:3d62a105fd34 1342 DBG("startLocation: %d, shiftOffset: %d, shiftAmount: %d",startLocation,shiftOffset,shiftAmount);
ashleymills 0:3d62a105fd34 1343 int srcPointer = startLocation+shiftOffset;
ashleymills 0:3d62a105fd34 1344 while(shiftAmount--) {
ashleymills 0:3d62a105fd34 1345 _pdu[startLocation] = _pdu[srcPointer];
ashleymills 0:3d62a105fd34 1346 startLocation++;
ashleymills 0:3d62a105fd34 1347 srcPointer++;
ashleymills 0:3d62a105fd34 1348 }
ashleymills 0:3d62a105fd34 1349 }
ashleymills 0:3d62a105fd34 1350
ashleymills 0:3d62a105fd34 1351 /// Gets the payload length of an option.
ashleymills 0:3d62a105fd34 1352 /**
ashleymills 0:3d62a105fd34 1353 * \param option Pointer to location of option in PDU.
ashleymills 0:3d62a105fd34 1354 * \return The 16 bit option-payload length.
ashleymills 0:3d62a105fd34 1355 */
ashleymills 0:3d62a105fd34 1356 uint16_t CoapPDU::getOptionValueLength(uint8_t *option) {
ashleymills 0:3d62a105fd34 1357 uint16_t delta = (option[0] & 0xF0) >> 4;
ashleymills 0:3d62a105fd34 1358 uint16_t length = (option[0] & 0x0F);
ashleymills 0:3d62a105fd34 1359 // no extra bytes
ashleymills 0:3d62a105fd34 1360 if(length<13) {
ashleymills 0:3d62a105fd34 1361 return length;
ashleymills 0:3d62a105fd34 1362 }
ashleymills 0:3d62a105fd34 1363
ashleymills 0:3d62a105fd34 1364 // extra bytes skip header
ashleymills 0:3d62a105fd34 1365 int offset = 1;
ashleymills 0:3d62a105fd34 1366 // skip extra option delta bytes
ashleymills 0:3d62a105fd34 1367 if(delta==13) {
ashleymills 0:3d62a105fd34 1368 offset++;
ashleymills 0:3d62a105fd34 1369 } else if(delta==14) {
ashleymills 0:3d62a105fd34 1370 offset+=2;
ashleymills 0:3d62a105fd34 1371 }
ashleymills 0:3d62a105fd34 1372
ashleymills 0:3d62a105fd34 1373 // process length
ashleymills 0:3d62a105fd34 1374 if(length==13) {
ashleymills 0:3d62a105fd34 1375 return (option[offset]+13);
ashleymills 0:3d62a105fd34 1376 } else {
ashleymills 0:3d62a105fd34 1377 // need to convert to host order
ashleymills 0:3d62a105fd34 1378 uint16_t networkOrder = 0x0000;
ashleymills 0:3d62a105fd34 1379 networkOrder |= option[offset++];
ashleymills 0:3d62a105fd34 1380 networkOrder <<= 8;
ashleymills 0:3d62a105fd34 1381 networkOrder |= option[offset];
ashleymills 0:3d62a105fd34 1382 uint16_t hostOrder = ntohs(networkOrder);
ashleymills 0:3d62a105fd34 1383 return hostOrder+269;
ashleymills 0:3d62a105fd34 1384 }
ashleymills 0:3d62a105fd34 1385
ashleymills 0:3d62a105fd34 1386 }
ashleymills 0:3d62a105fd34 1387
ashleymills 0:3d62a105fd34 1388 /// Gets the delta of an option.
ashleymills 0:3d62a105fd34 1389 /**
ashleymills 0:3d62a105fd34 1390 * \param option Pointer to location of option in PDU.
ashleymills 0:3d62a105fd34 1391 * \return The 16 bit delta.
ashleymills 0:3d62a105fd34 1392 */
ashleymills 0:3d62a105fd34 1393 uint16_t CoapPDU::getOptionDelta(uint8_t *option) {
ashleymills 0:3d62a105fd34 1394 uint16_t delta = (option[0] & 0xF0) >> 4;
ashleymills 0:3d62a105fd34 1395 if(delta<13) {
ashleymills 0:3d62a105fd34 1396 return delta;
ashleymills 0:3d62a105fd34 1397 } else if(delta==13) {
ashleymills 0:3d62a105fd34 1398 // single byte option delta
ashleymills 0:3d62a105fd34 1399 return (option[1]+13);
ashleymills 0:3d62a105fd34 1400 } else if(delta==14) {
ashleymills 0:3d62a105fd34 1401 // double byte option delta
ashleymills 0:3d62a105fd34 1402 // need to convert to host order
ashleymills 0:3d62a105fd34 1403 uint16_t networkOrder = 0x0000;
ashleymills 0:3d62a105fd34 1404 networkOrder |= option[1];
ashleymills 0:3d62a105fd34 1405 networkOrder <<= 8;
ashleymills 0:3d62a105fd34 1406 networkOrder |= option[2];
ashleymills 0:3d62a105fd34 1407 uint16_t hostOrder = ntohs(networkOrder);
ashleymills 0:3d62a105fd34 1408 return hostOrder+269;
ashleymills 0:3d62a105fd34 1409 } else {
ashleymills 0:3d62a105fd34 1410 // should only ever occur in payload marker
ashleymills 0:3d62a105fd34 1411 return delta;
ashleymills 0:3d62a105fd34 1412 }
ashleymills 0:3d62a105fd34 1413 }
ashleymills 0:3d62a105fd34 1414
ashleymills 0:3d62a105fd34 1415 /// Finds the insertion position in the current list of options for the specified option.
ashleymills 0:3d62a105fd34 1416 /**
ashleymills 0:3d62a105fd34 1417 * \param optionNumber The option's number.
ashleymills 0:3d62a105fd34 1418 * \param prevOptionNumber A pointer to a uint16_t which will store the option number of the option previous
ashleymills 0:3d62a105fd34 1419 * to the insertion point.
ashleymills 0:3d62a105fd34 1420 * \return 0 on success, 1 on failure. \b prevOptionNumber will contain the option number of the option
ashleymills 0:3d62a105fd34 1421 * before the insertion position (for example 0 if no options have been inserted).
ashleymills 0:3d62a105fd34 1422 */
ashleymills 0:3d62a105fd34 1423 int CoapPDU::findInsertionPosition(uint16_t optionNumber, uint16_t *prevOptionNumber) {
ashleymills 0:3d62a105fd34 1424 // zero this for safety
ashleymills 0:3d62a105fd34 1425 *prevOptionNumber = 0x00;
ashleymills 0:3d62a105fd34 1426
ashleymills 0:3d62a105fd34 1427 DBG("_pduLength: %d",_pduLength);
ashleymills 0:3d62a105fd34 1428
ashleymills 0:3d62a105fd34 1429 // if option is bigger than any currently stored, it goes at the end
ashleymills 0:3d62a105fd34 1430 // this includes the case that no option has yet been added
ashleymills 0:3d62a105fd34 1431 if( (optionNumber >= _maxAddedOptionNumber) || (_pduLength == (COAP_HDR_SIZE+getTokenLength())) ) {
ashleymills 0:3d62a105fd34 1432 *prevOptionNumber = _maxAddedOptionNumber;
ashleymills 0:3d62a105fd34 1433 return _pduLength;
ashleymills 0:3d62a105fd34 1434 }
ashleymills 0:3d62a105fd34 1435
ashleymills 0:3d62a105fd34 1436 // otherwise walk over the options
ashleymills 0:3d62a105fd34 1437 int optionPos = COAP_HDR_SIZE + getTokenLength();
ashleymills 0:3d62a105fd34 1438 uint16_t optionDelta = 0, optionValueLength = 0;
ashleymills 0:3d62a105fd34 1439 uint16_t currentOptionNumber = 0;
ashleymills 0:3d62a105fd34 1440 while(optionPos<_pduLength && _pdu[optionPos]!=0xFF) {
ashleymills 0:3d62a105fd34 1441 optionDelta = getOptionDelta(&_pdu[optionPos]);
ashleymills 0:3d62a105fd34 1442 currentOptionNumber += optionDelta;
ashleymills 0:3d62a105fd34 1443 optionValueLength = getOptionValueLength(&_pdu[optionPos]);
ashleymills 0:3d62a105fd34 1444 // test if this is insertion position
ashleymills 0:3d62a105fd34 1445 if(currentOptionNumber>optionNumber) {
ashleymills 0:3d62a105fd34 1446 return optionPos;
ashleymills 0:3d62a105fd34 1447 }
ashleymills 0:3d62a105fd34 1448 // keep track of the last valid option number
ashleymills 0:3d62a105fd34 1449 *prevOptionNumber = currentOptionNumber;
ashleymills 0:3d62a105fd34 1450 // move onto next option
ashleymills 0:3d62a105fd34 1451 optionPos += computeExtraBytes(optionDelta);
ashleymills 0:3d62a105fd34 1452 optionPos += computeExtraBytes(optionValueLength);
ashleymills 0:3d62a105fd34 1453 optionPos += optionValueLength;
ashleymills 0:3d62a105fd34 1454 optionPos++; // (for mandatory option header byte)
ashleymills 0:3d62a105fd34 1455 }
ashleymills 0:3d62a105fd34 1456 return optionPos;
ashleymills 0:3d62a105fd34 1457
ashleymills 0:3d62a105fd34 1458 }
ashleymills 0:3d62a105fd34 1459
ashleymills 0:3d62a105fd34 1460 /// CoAP uses a minimal-byte representation for length fields. This returns the number of bytes needed to represent a given length.
ashleymills 0:3d62a105fd34 1461 int CoapPDU::computeExtraBytes(uint16_t n) {
ashleymills 0:3d62a105fd34 1462 if(n<13) {
ashleymills 0:3d62a105fd34 1463 return 0;
ashleymills 0:3d62a105fd34 1464 }
ashleymills 0:3d62a105fd34 1465
ashleymills 0:3d62a105fd34 1466 if(n<269) {
ashleymills 0:3d62a105fd34 1467 return 1;
ashleymills 0:3d62a105fd34 1468 }
ashleymills 0:3d62a105fd34 1469
ashleymills 0:3d62a105fd34 1470 return 2;
ashleymills 0:3d62a105fd34 1471 }
ashleymills 0:3d62a105fd34 1472
ashleymills 0:3d62a105fd34 1473 /// Set the option delta to the specified value.
ashleymills 0:3d62a105fd34 1474 /**
ashleymills 0:3d62a105fd34 1475 * This assumes space has been made for the option delta.
ashleymills 0:3d62a105fd34 1476 * \param optionPosition The index of the option in the PDU.
ashleymills 0:3d62a105fd34 1477 * \param optionDelta The option delta value to set.
ashleymills 0:3d62a105fd34 1478 */
ashleymills 0:3d62a105fd34 1479 void CoapPDU::setOptionDelta(int optionPosition, uint16_t optionDelta) {
ashleymills 0:3d62a105fd34 1480 int headerStart = optionPosition;
ashleymills 0:3d62a105fd34 1481 // clear the old option delta bytes
ashleymills 0:3d62a105fd34 1482 _pdu[headerStart] &= 0x0F;
ashleymills 0:3d62a105fd34 1483
ashleymills 0:3d62a105fd34 1484 // set the option delta bytes
ashleymills 0:3d62a105fd34 1485 if(optionDelta<13) {
ashleymills 0:3d62a105fd34 1486 _pdu[headerStart] |= (optionDelta << 4);
ashleymills 0:3d62a105fd34 1487 } else if(optionDelta<269) {
ashleymills 0:3d62a105fd34 1488 // 1 extra byte
ashleymills 0:3d62a105fd34 1489 _pdu[headerStart] |= 0xD0; // 13 in first nibble
ashleymills 0:3d62a105fd34 1490 _pdu[++optionPosition] &= 0x00;
ashleymills 0:3d62a105fd34 1491 _pdu[optionPosition] |= (optionDelta-13);
ashleymills 0:3d62a105fd34 1492 } else {
ashleymills 0:3d62a105fd34 1493 // 2 extra bytes, network byte order uint16_t
ashleymills 0:3d62a105fd34 1494 _pdu[headerStart] |= 0xE0; // 14 in first nibble
ashleymills 0:3d62a105fd34 1495 optionDelta = htons(optionDelta-269);
ashleymills 0:3d62a105fd34 1496 _pdu[++optionPosition] &= 0x00;
ashleymills 0:3d62a105fd34 1497 _pdu[optionPosition] |= (optionDelta >> 8); // MSB
ashleymills 0:3d62a105fd34 1498 _pdu[++optionPosition] &= 0x00;
ashleymills 0:3d62a105fd34 1499 _pdu[optionPosition] |= (optionDelta & 0x00FF); // LSB
ashleymills 0:3d62a105fd34 1500 }
ashleymills 0:3d62a105fd34 1501 }
ashleymills 0:3d62a105fd34 1502
ashleymills 0:3d62a105fd34 1503 /// Insert an option in-memory at the specified location.
ashleymills 0:3d62a105fd34 1504 /**
ashleymills 0:3d62a105fd34 1505 * This assumes that there is enough space at the location specified.
ashleymills 0:3d62a105fd34 1506 * \param insertionPosition Position in the PDU where the option should be placed.
ashleymills 0:3d62a105fd34 1507 * \param optionDelta The delta value for the option.
ashleymills 0:3d62a105fd34 1508 * \param optionValueLength The length of the option value.
ashleymills 0:3d62a105fd34 1509 * \param optionValue A pointer to the sequence of bytes representing the option value.
ashleymills 0:3d62a105fd34 1510 * \return 0 on success, 1 on failure.
ashleymills 0:3d62a105fd34 1511 */
ashleymills 0:3d62a105fd34 1512 int CoapPDU::insertOption(
ashleymills 0:3d62a105fd34 1513 int insertionPosition,
ashleymills 0:3d62a105fd34 1514 uint16_t optionDelta,
ashleymills 0:3d62a105fd34 1515 uint16_t optionValueLength,
ashleymills 0:3d62a105fd34 1516 uint8_t *optionValue) {
ashleymills 0:3d62a105fd34 1517
ashleymills 0:3d62a105fd34 1518 int headerStart = insertionPosition;
ashleymills 0:3d62a105fd34 1519
ashleymills 0:3d62a105fd34 1520 // clear old option header start
ashleymills 0:3d62a105fd34 1521 _pdu[headerStart] &= 0x00;
ashleymills 0:3d62a105fd34 1522
ashleymills 0:3d62a105fd34 1523 // set the option delta bytes
ashleymills 0:3d62a105fd34 1524 if(optionDelta<13) {
ashleymills 0:3d62a105fd34 1525 _pdu[headerStart] |= (optionDelta << 4);
ashleymills 0:3d62a105fd34 1526 } else if(optionDelta<269) {
ashleymills 0:3d62a105fd34 1527 // 1 extra byte
ashleymills 0:3d62a105fd34 1528 _pdu[headerStart] |= 0xD0; // 13 in first nibble
ashleymills 0:3d62a105fd34 1529 _pdu[++insertionPosition] &= 0x00;
ashleymills 0:3d62a105fd34 1530 _pdu[insertionPosition] |= (optionDelta-13);
ashleymills 0:3d62a105fd34 1531 } else {
ashleymills 0:3d62a105fd34 1532 // 2 extra bytes, network byte order uint16_t
ashleymills 0:3d62a105fd34 1533 _pdu[headerStart] |= 0xE0; // 14 in first nibble
ashleymills 0:3d62a105fd34 1534 optionDelta = htons(optionDelta-269);
ashleymills 0:3d62a105fd34 1535 _pdu[++insertionPosition] &= 0x00;
ashleymills 0:3d62a105fd34 1536 _pdu[insertionPosition] |= (optionDelta >> 8); // MSB
ashleymills 0:3d62a105fd34 1537 _pdu[++insertionPosition] &= 0x00;
ashleymills 0:3d62a105fd34 1538 _pdu[insertionPosition] |= (optionDelta & 0x00FF); // LSB
ashleymills 0:3d62a105fd34 1539 }
ashleymills 0:3d62a105fd34 1540
ashleymills 0:3d62a105fd34 1541 // set the option value length bytes
ashleymills 0:3d62a105fd34 1542 if(optionValueLength<13) {
ashleymills 0:3d62a105fd34 1543 _pdu[headerStart] |= (optionValueLength & 0x000F);
ashleymills 0:3d62a105fd34 1544 } else if(optionValueLength<269) {
ashleymills 0:3d62a105fd34 1545 _pdu[headerStart] |= 0x0D; // 13 in second nibble
ashleymills 0:3d62a105fd34 1546 _pdu[++insertionPosition] &= 0x00;
ashleymills 0:3d62a105fd34 1547 _pdu[insertionPosition] |= (optionValueLength-13);
ashleymills 0:3d62a105fd34 1548 } else {
ashleymills 0:3d62a105fd34 1549 _pdu[headerStart] |= 0x0E; // 14 in second nibble
ashleymills 0:3d62a105fd34 1550 // this is in network byte order
ashleymills 0:3d62a105fd34 1551 DBG("optionValueLength: %u",optionValueLength);
ashleymills 0:3d62a105fd34 1552 uint16_t networkOrder = htons(optionValueLength-269);
ashleymills 0:3d62a105fd34 1553 _pdu[++insertionPosition] &= 0x00;
ashleymills 0:3d62a105fd34 1554 _pdu[insertionPosition] |= (networkOrder >> 8); // MSB
ashleymills 0:3d62a105fd34 1555 _pdu[++insertionPosition] &= 0x00;
ashleymills 0:3d62a105fd34 1556 _pdu[insertionPosition] |= (networkOrder & 0x00FF); // LSB
ashleymills 0:3d62a105fd34 1557 }
ashleymills 0:3d62a105fd34 1558
ashleymills 0:3d62a105fd34 1559 // and finally copy the option value itself
ashleymills 0:3d62a105fd34 1560 memcpy(&_pdu[++insertionPosition],optionValue,optionValueLength);
ashleymills 0:3d62a105fd34 1561
ashleymills 0:3d62a105fd34 1562 return 0;
ashleymills 0:3d62a105fd34 1563 }
ashleymills 0:3d62a105fd34 1564
ashleymills 0:3d62a105fd34 1565 // DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
ashleymills 0:3d62a105fd34 1566 // DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
ashleymills 0:3d62a105fd34 1567
ashleymills 0:3d62a105fd34 1568 /// Prints the PDU in human-readable format.
ashleymills 0:3d62a105fd34 1569 void CoapPDU::printHuman() {
ashleymills 1:5eec2844ad47 1570 INFOX("__________________\r\n");
ashleymills 0:3d62a105fd34 1571 if(_constructedFromBuffer) {
ashleymills 1:5eec2844ad47 1572 INFOX("PDU was constructed from buffer of %d bytes\r\n",_bufferLength);
ashleymills 0:3d62a105fd34 1573 }
ashleymills 1:5eec2844ad47 1574 INFOX("PDU is %d bytes long\r\n",_pduLength);
ashleymills 1:5eec2844ad47 1575 INFOX("CoAP Version: %d\r\n",getVersion());
ashleymills 0:3d62a105fd34 1576 INFOX("Message Type: ");
ashleymills 0:3d62a105fd34 1577 switch(getType()) {
ashleymills 0:3d62a105fd34 1578 case COAP_CONFIRMABLE:
ashleymills 1:5eec2844ad47 1579 INFOX("Confirmable\r\n");
ashleymills 0:3d62a105fd34 1580 break;
ashleymills 0:3d62a105fd34 1581
ashleymills 0:3d62a105fd34 1582 case COAP_NON_CONFIRMABLE:
ashleymills 1:5eec2844ad47 1583 INFOX("Non-Confirmable\r\n");
ashleymills 0:3d62a105fd34 1584 break;
ashleymills 0:3d62a105fd34 1585
ashleymills 0:3d62a105fd34 1586 case COAP_ACKNOWLEDGEMENT:
ashleymills 1:5eec2844ad47 1587 INFOX("Acknowledgement\r\n");
ashleymills 0:3d62a105fd34 1588 break;
ashleymills 0:3d62a105fd34 1589
ashleymills 0:3d62a105fd34 1590 case COAP_RESET:
ashleymills 1:5eec2844ad47 1591 INFOX("Reset\r\n");
ashleymills 0:3d62a105fd34 1592 break;
ashleymills 0:3d62a105fd34 1593 }
ashleymills 1:5eec2844ad47 1594 INFOX("Token length: %d\r\n",getTokenLength());
ashleymills 0:3d62a105fd34 1595 INFOX("Code: ");
ashleymills 0:3d62a105fd34 1596 switch(getCode()) {
ashleymills 0:3d62a105fd34 1597 case COAP_EMPTY:
ashleymills 1:5eec2844ad47 1598 INFOX("0.00 Empty");
ashleymills 0:3d62a105fd34 1599 break;
ashleymills 0:3d62a105fd34 1600 case COAP_GET:
ashleymills 1:5eec2844ad47 1601 INFOX("0.01 GET");
ashleymills 0:3d62a105fd34 1602 break;
ashleymills 0:3d62a105fd34 1603 case COAP_POST:
ashleymills 1:5eec2844ad47 1604 INFOX("0.02 POST");
ashleymills 0:3d62a105fd34 1605 break;
ashleymills 0:3d62a105fd34 1606 case COAP_PUT:
ashleymills 1:5eec2844ad47 1607 INFOX("0.03 PUT");
ashleymills 0:3d62a105fd34 1608 break;
ashleymills 0:3d62a105fd34 1609 case COAP_DELETE:
ashleymills 1:5eec2844ad47 1610 INFOX("0.04 DELETE");
ashleymills 0:3d62a105fd34 1611 break;
ashleymills 0:3d62a105fd34 1612 case COAP_CREATED:
ashleymills 1:5eec2844ad47 1613 INFOX("2.01 Created");
ashleymills 0:3d62a105fd34 1614 break;
ashleymills 0:3d62a105fd34 1615 case COAP_DELETED:
ashleymills 1:5eec2844ad47 1616 INFOX("2.02 Deleted");
ashleymills 0:3d62a105fd34 1617 break;
ashleymills 0:3d62a105fd34 1618 case COAP_VALID:
ashleymills 1:5eec2844ad47 1619 INFOX("2.03 Valid");
ashleymills 0:3d62a105fd34 1620 break;
ashleymills 0:3d62a105fd34 1621 case COAP_CHANGED:
ashleymills 1:5eec2844ad47 1622 INFOX("2.04 Changed");
ashleymills 0:3d62a105fd34 1623 break;
ashleymills 0:3d62a105fd34 1624 case COAP_CONTENT:
ashleymills 1:5eec2844ad47 1625 INFOX("2.05 Content");
ashleymills 0:3d62a105fd34 1626 break;
ashleymills 0:3d62a105fd34 1627 case COAP_BAD_REQUEST:
ashleymills 1:5eec2844ad47 1628 INFOX("4.00 Bad Request");
ashleymills 0:3d62a105fd34 1629 break;
ashleymills 0:3d62a105fd34 1630 case COAP_UNAUTHORIZED:
ashleymills 1:5eec2844ad47 1631 INFOX("4.01 Unauthorized");
ashleymills 0:3d62a105fd34 1632 break;
ashleymills 0:3d62a105fd34 1633 case COAP_BAD_OPTION:
ashleymills 1:5eec2844ad47 1634 INFOX("4.02 Bad Option");
ashleymills 0:3d62a105fd34 1635 break;
ashleymills 0:3d62a105fd34 1636 case COAP_FORBIDDEN:
ashleymills 1:5eec2844ad47 1637 INFOX("4.03 Forbidden");
ashleymills 0:3d62a105fd34 1638 break;
ashleymills 0:3d62a105fd34 1639 case COAP_NOT_FOUND:
ashleymills 1:5eec2844ad47 1640 INFOX("4.04 Not Found");
ashleymills 0:3d62a105fd34 1641 break;
ashleymills 0:3d62a105fd34 1642 case COAP_METHOD_NOT_ALLOWED:
ashleymills 1:5eec2844ad47 1643 INFOX("4.05 Method Not Allowed");
ashleymills 0:3d62a105fd34 1644 break;
ashleymills 0:3d62a105fd34 1645 case COAP_NOT_ACCEPTABLE:
ashleymills 1:5eec2844ad47 1646 INFOX("4.06 Not Acceptable");
ashleymills 0:3d62a105fd34 1647 break;
ashleymills 0:3d62a105fd34 1648 case COAP_PRECONDITION_FAILED:
ashleymills 1:5eec2844ad47 1649 INFOX("4.12 Precondition Failed");
ashleymills 0:3d62a105fd34 1650 break;
ashleymills 0:3d62a105fd34 1651 case COAP_REQUEST_ENTITY_TOO_LARGE:
ashleymills 1:5eec2844ad47 1652 INFOX("4.13 Request Entity Too Large");
ashleymills 0:3d62a105fd34 1653 break;
ashleymills 0:3d62a105fd34 1654 case COAP_UNSUPPORTED_CONTENT_FORMAT:
ashleymills 1:5eec2844ad47 1655 INFOX("4.15 Unsupported Content-Format");
ashleymills 0:3d62a105fd34 1656 break;
ashleymills 0:3d62a105fd34 1657 case COAP_INTERNAL_SERVER_ERROR:
ashleymills 1:5eec2844ad47 1658 INFOX("5.00 Internal Server Error");
ashleymills 0:3d62a105fd34 1659 break;
ashleymills 0:3d62a105fd34 1660 case COAP_NOT_IMPLEMENTED:
ashleymills 1:5eec2844ad47 1661 INFOX("5.01 Not Implemented");
ashleymills 0:3d62a105fd34 1662 break;
ashleymills 0:3d62a105fd34 1663 case COAP_BAD_GATEWAY:
ashleymills 1:5eec2844ad47 1664 INFOX("5.02 Bad Gateway");
ashleymills 0:3d62a105fd34 1665 break;
ashleymills 0:3d62a105fd34 1666 case COAP_SERVICE_UNAVAILABLE:
ashleymills 1:5eec2844ad47 1667 INFOX("5.03 Service Unavailable");
ashleymills 0:3d62a105fd34 1668 break;
ashleymills 0:3d62a105fd34 1669 case COAP_GATEWAY_TIMEOUT:
ashleymills 1:5eec2844ad47 1670 INFOX("5.04 Gateway Timeout");
ashleymills 0:3d62a105fd34 1671 break;
ashleymills 0:3d62a105fd34 1672 case COAP_PROXYING_NOT_SUPPORTED:
ashleymills 1:5eec2844ad47 1673 INFOX("5.05 Proxying Not Supported");
ashleymills 1:5eec2844ad47 1674 break;
ashleymills 1:5eec2844ad47 1675 case COAP_UNDEFINED_CODE:
ashleymills 1:5eec2844ad47 1676 INFOX("Undefined Code");
ashleymills 0:3d62a105fd34 1677 break;
ashleymills 0:3d62a105fd34 1678 }
ashleymills 1:5eec2844ad47 1679 INFOX("\r\n");
ashleymills 0:3d62a105fd34 1680
ashleymills 0:3d62a105fd34 1681 // print message ID
ashleymills 1:5eec2844ad47 1682 INFOX("Message ID: %u\r\n",getMessageID());
ashleymills 0:3d62a105fd34 1683
ashleymills 0:3d62a105fd34 1684 // print token value
ashleymills 0:3d62a105fd34 1685 int tokenLength = getTokenLength();
ashleymills 0:3d62a105fd34 1686 uint8_t *tokenPointer = getPDUPointer()+COAP_HDR_SIZE;
ashleymills 0:3d62a105fd34 1687 if(tokenLength==0) {
ashleymills 1:5eec2844ad47 1688 INFOX("No token.\r\n");
ashleymills 0:3d62a105fd34 1689 } else {
ashleymills 1:5eec2844ad47 1690 INFOX("Token of %d bytes.\r\n",tokenLength);
ashleymills 0:3d62a105fd34 1691 INFOX(" Value: 0x");
ashleymills 0:3d62a105fd34 1692 for(int j=0; j<tokenLength; j++) {
ashleymills 0:3d62a105fd34 1693 INFOX("%.2x",tokenPointer[j]);
ashleymills 0:3d62a105fd34 1694 }
ashleymills 1:5eec2844ad47 1695 INFOX("\r\n");
ashleymills 0:3d62a105fd34 1696 }
ashleymills 0:3d62a105fd34 1697
ashleymills 0:3d62a105fd34 1698 // print options
ashleymills 0:3d62a105fd34 1699 CoapPDU::CoapOption* options = getOptions();
ashleymills 1:5eec2844ad47 1700 INFOX("%d options:\r\n",_numOptions);
ashleymills 0:3d62a105fd34 1701 for(int i=0; i<_numOptions; i++) {
ashleymills 1:5eec2844ad47 1702 INFOX("OPTION (%d/%d)\r\n",i,_numOptions);
ashleymills 1:5eec2844ad47 1703 INFOX(" Option number (delta): %hu (%hu)\r\n",options[i].optionNumber,options[i].optionDelta);
ashleymills 0:3d62a105fd34 1704 INFOX(" Name: ");
ashleymills 0:3d62a105fd34 1705 switch(options[i].optionNumber) {
ashleymills 0:3d62a105fd34 1706 case COAP_OPTION_IF_MATCH:
ashleymills 1:5eec2844ad47 1707 INFOX("IF_MATCH");
ashleymills 0:3d62a105fd34 1708 break;
ashleymills 0:3d62a105fd34 1709 case COAP_OPTION_URI_HOST:
ashleymills 1:5eec2844ad47 1710 INFOX("URI_HOST");
ashleymills 0:3d62a105fd34 1711 break;
ashleymills 0:3d62a105fd34 1712 case COAP_OPTION_ETAG:
ashleymills 1:5eec2844ad47 1713 INFOX("ETAG");
ashleymills 0:3d62a105fd34 1714 break;
ashleymills 0:3d62a105fd34 1715 case COAP_OPTION_IF_NONE_MATCH:
ashleymills 1:5eec2844ad47 1716 INFOX("IF_NONE_MATCH");
ashleymills 0:3d62a105fd34 1717 break;
ashleymills 0:3d62a105fd34 1718 case COAP_OPTION_OBSERVE:
ashleymills 1:5eec2844ad47 1719 INFOX("OBSERVE");
ashleymills 0:3d62a105fd34 1720 break;
ashleymills 0:3d62a105fd34 1721 case COAP_OPTION_URI_PORT:
ashleymills 1:5eec2844ad47 1722 INFOX("URI_PORT");
ashleymills 0:3d62a105fd34 1723 break;
ashleymills 0:3d62a105fd34 1724 case COAP_OPTION_LOCATION_PATH:
ashleymills 1:5eec2844ad47 1725 INFOX("LOCATION_PATH");
ashleymills 0:3d62a105fd34 1726 break;
ashleymills 0:3d62a105fd34 1727 case COAP_OPTION_URI_PATH:
ashleymills 1:5eec2844ad47 1728 INFOX("URI_PATH");
ashleymills 0:3d62a105fd34 1729 break;
ashleymills 0:3d62a105fd34 1730 case COAP_OPTION_CONTENT_FORMAT:
ashleymills 1:5eec2844ad47 1731 INFOX("CONTENT_FORMAT");
ashleymills 0:3d62a105fd34 1732 break;
ashleymills 0:3d62a105fd34 1733 case COAP_OPTION_MAX_AGE:
ashleymills 1:5eec2844ad47 1734 INFOX("MAX_AGE");
ashleymills 0:3d62a105fd34 1735 break;
ashleymills 0:3d62a105fd34 1736 case COAP_OPTION_URI_QUERY:
ashleymills 1:5eec2844ad47 1737 INFOX("URI_QUERY");
ashleymills 0:3d62a105fd34 1738 break;
ashleymills 0:3d62a105fd34 1739 case COAP_OPTION_ACCEPT:
ashleymills 1:5eec2844ad47 1740 INFOX("ACCEPT");
ashleymills 0:3d62a105fd34 1741 break;
ashleymills 0:3d62a105fd34 1742 case COAP_OPTION_LOCATION_QUERY:
ashleymills 1:5eec2844ad47 1743 INFOX("LOCATION_QUERY");
ashleymills 0:3d62a105fd34 1744 break;
ashleymills 0:3d62a105fd34 1745 case COAP_OPTION_PROXY_URI:
ashleymills 1:5eec2844ad47 1746 INFOX("PROXY_URI");
ashleymills 0:3d62a105fd34 1747 break;
ashleymills 0:3d62a105fd34 1748 case COAP_OPTION_PROXY_SCHEME:
ashleymills 1:5eec2844ad47 1749 INFOX("PROXY_SCHEME");
ashleymills 0:3d62a105fd34 1750 break;
ashleymills 0:3d62a105fd34 1751 case COAP_OPTION_BLOCK1:
ashleymills 1:5eec2844ad47 1752 INFOX("BLOCK1");
ashleymills 0:3d62a105fd34 1753 break;
ashleymills 0:3d62a105fd34 1754 case COAP_OPTION_BLOCK2:
ashleymills 1:5eec2844ad47 1755 INFOX("BLOCK2");
ashleymills 0:3d62a105fd34 1756 break;
ashleymills 0:3d62a105fd34 1757 case COAP_OPTION_SIZE1:
ashleymills 1:5eec2844ad47 1758 INFOX("SIZE1");
ashleymills 0:3d62a105fd34 1759 break;
ashleymills 0:3d62a105fd34 1760 case COAP_OPTION_SIZE2:
ashleymills 1:5eec2844ad47 1761 INFOX("SIZE2");
ashleymills 0:3d62a105fd34 1762 break;
ashleymills 0:3d62a105fd34 1763 default:
ashleymills 1:5eec2844ad47 1764 INFOX("Unknown option");
ashleymills 0:3d62a105fd34 1765 break;
ashleymills 0:3d62a105fd34 1766 }
ashleymills 1:5eec2844ad47 1767 INFOX("\r\n");
ashleymills 1:5eec2844ad47 1768 INFOX(" Value length: %u\r\n",options[i].optionValueLength);
ashleymills 0:3d62a105fd34 1769 INFOX(" Value: \"");
ashleymills 0:3d62a105fd34 1770 for(int j=0; j<options[i].optionValueLength; j++) {
ashleymills 0:3d62a105fd34 1771 char c = options[i].optionValuePointer[j];
ashleymills 0:3d62a105fd34 1772 if((c>='!'&&c<='~')||c==' ') {
ashleymills 0:3d62a105fd34 1773 INFOX("%c",c);
ashleymills 0:3d62a105fd34 1774 } else {
ashleymills 0:3d62a105fd34 1775 INFOX("\\%.2d",c);
ashleymills 0:3d62a105fd34 1776 }
ashleymills 0:3d62a105fd34 1777 }
ashleymills 1:5eec2844ad47 1778 INFOX("\"\r\n");
ashleymills 0:3d62a105fd34 1779 }
ashleymills 0:3d62a105fd34 1780
ashleymills 0:3d62a105fd34 1781 // print payload
ashleymills 0:3d62a105fd34 1782 if(_payloadLength==0) {
ashleymills 1:5eec2844ad47 1783 INFOX("No payload.\r\n");
ashleymills 0:3d62a105fd34 1784 } else {
ashleymills 1:5eec2844ad47 1785 INFOX("Payload of %d bytes\r\n",_payloadLength);
ashleymills 0:3d62a105fd34 1786 INFOX(" Value: \"");
ashleymills 0:3d62a105fd34 1787 for(int j=0; j<_payloadLength; j++) {
ashleymills 0:3d62a105fd34 1788 char c = _payloadPointer[j];
ashleymills 0:3d62a105fd34 1789 if((c>='!'&&c<='~')||c==' ') {
ashleymills 0:3d62a105fd34 1790 INFOX("%c",c);
ashleymills 0:3d62a105fd34 1791 } else {
ashleymills 0:3d62a105fd34 1792 INFOX("\\%.2x",c);
ashleymills 0:3d62a105fd34 1793 }
ashleymills 0:3d62a105fd34 1794 }
ashleymills 1:5eec2844ad47 1795 INFO("\"\r\n");
ashleymills 0:3d62a105fd34 1796 }
ashleymills 1:5eec2844ad47 1797 INFOX("__________________\r\n");
ashleymills 0:3d62a105fd34 1798 }
ashleymills 0:3d62a105fd34 1799
ashleymills 0:3d62a105fd34 1800 /// Prints the PDU as a c array (useful for debugging or hardcoding PDUs)
ashleymills 0:3d62a105fd34 1801 void CoapPDU::printPDUAsCArray() {
ashleymills 0:3d62a105fd34 1802 printf("const uint8_t array[] = {\r\n ");
ashleymills 0:3d62a105fd34 1803 for(int i=0; i<_pduLength; i++) {
ashleymills 0:3d62a105fd34 1804 printf("0x%.2x, ",_pdu[i]);
ashleymills 0:3d62a105fd34 1805 }
ashleymills 0:3d62a105fd34 1806 printf("\r\n};\r\n");
ashleymills 0:3d62a105fd34 1807 }
ashleymills 0:3d62a105fd34 1808
ashleymills 0:3d62a105fd34 1809 /// A routine for printing an option in human-readable format.
ashleymills 0:3d62a105fd34 1810 /**
ashleymills 0:3d62a105fd34 1811 * \param option This is a pointer to where the option begins in the PDU.
ashleymills 0:3d62a105fd34 1812 */
ashleymills 0:3d62a105fd34 1813 void CoapPDU::printOptionHuman(uint8_t *option) {
ashleymills 0:3d62a105fd34 1814 // compute some useful stuff
ashleymills 0:3d62a105fd34 1815 uint16_t optionDelta = getOptionDelta(option);
ashleymills 0:3d62a105fd34 1816 uint16_t optionValueLength = getOptionValueLength(option);
ashleymills 0:3d62a105fd34 1817 int extraDeltaBytes = computeExtraBytes(optionDelta);
ashleymills 0:3d62a105fd34 1818 int extraValueLengthBytes = computeExtraBytes(optionValueLength);
ashleymills 0:3d62a105fd34 1819 int totalLength = 1+extraDeltaBytes+extraValueLengthBytes+optionValueLength;
ashleymills 0:3d62a105fd34 1820
ashleymills 0:3d62a105fd34 1821 if(totalLength>_pduLength) {
ashleymills 0:3d62a105fd34 1822 totalLength = &_pdu[_pduLength-1]-option;
ashleymills 0:3d62a105fd34 1823 DBG("New length: %u",totalLength);
ashleymills 0:3d62a105fd34 1824 }
ashleymills 0:3d62a105fd34 1825
ashleymills 0:3d62a105fd34 1826 // print summary
ashleymills 0:3d62a105fd34 1827 DBG("~~~~~~ Option ~~~~~~");
ashleymills 0:3d62a105fd34 1828 DBG("Delta: %u, Value length: %u",optionDelta,optionValueLength);
ashleymills 0:3d62a105fd34 1829
ashleymills 0:3d62a105fd34 1830 // print all bytes
ashleymills 0:3d62a105fd34 1831 DBG("All bytes (%d):",totalLength);
ashleymills 0:3d62a105fd34 1832 for(int i=0; i<totalLength; i++) {
ashleymills 0:3d62a105fd34 1833 if(i%4==0) {
ashleymills 0:3d62a105fd34 1834 DBG(" ");
ashleymills 0:3d62a105fd34 1835 DBGX(" %.2d ",i);
ashleymills 0:3d62a105fd34 1836 }
ashleymills 0:3d62a105fd34 1837 CoapPDU::printBinary(option[i]); DBGX(" ");
ashleymills 0:3d62a105fd34 1838 }
ashleymills 0:3d62a105fd34 1839 DBG(" "); DBG(" ");
ashleymills 0:3d62a105fd34 1840
ashleymills 0:3d62a105fd34 1841 // print header byte
ashleymills 0:3d62a105fd34 1842 DBG("Header byte:");
ashleymills 0:3d62a105fd34 1843 DBGX(" ");
ashleymills 0:3d62a105fd34 1844 CoapPDU::printBinary(*option++);
ashleymills 0:3d62a105fd34 1845 DBG(" "); DBG(" ");
ashleymills 0:3d62a105fd34 1846
ashleymills 0:3d62a105fd34 1847 // print extended delta bytes
ashleymills 0:3d62a105fd34 1848 if(extraDeltaBytes) {
ashleymills 0:3d62a105fd34 1849 DBG("Extended delta bytes (%d) in network order: ",extraDeltaBytes);
ashleymills 0:3d62a105fd34 1850 DBGX(" ");
ashleymills 0:3d62a105fd34 1851 while(extraDeltaBytes--) {
ashleymills 0:3d62a105fd34 1852 CoapPDU::printBinary(*option++); DBGX(" ");
ashleymills 0:3d62a105fd34 1853 }
ashleymills 0:3d62a105fd34 1854 } else {
ashleymills 0:3d62a105fd34 1855 DBG("No extended delta bytes");
ashleymills 0:3d62a105fd34 1856 }
ashleymills 0:3d62a105fd34 1857 DBG(" "); DBG(" ");
ashleymills 0:3d62a105fd34 1858
ashleymills 0:3d62a105fd34 1859 // print extended value length bytes
ashleymills 0:3d62a105fd34 1860 if(extraValueLengthBytes) {
ashleymills 0:3d62a105fd34 1861 DBG("Extended value length bytes (%d) in network order: ",extraValueLengthBytes);
ashleymills 0:3d62a105fd34 1862 DBGX(" ");
ashleymills 0:3d62a105fd34 1863 while(extraValueLengthBytes--) {
ashleymills 0:3d62a105fd34 1864 CoapPDU::printBinary(*option++); DBGX(" ");
ashleymills 0:3d62a105fd34 1865 }
ashleymills 0:3d62a105fd34 1866 } else {
ashleymills 0:3d62a105fd34 1867 DBG("No extended value length bytes");
ashleymills 0:3d62a105fd34 1868 }
ashleymills 0:3d62a105fd34 1869 DBG(" ");
ashleymills 0:3d62a105fd34 1870
ashleymills 0:3d62a105fd34 1871 // print option value
ashleymills 0:3d62a105fd34 1872 DBG("Option value bytes:");
ashleymills 0:3d62a105fd34 1873 for(int i=0; i<optionValueLength; i++) {
ashleymills 0:3d62a105fd34 1874 if(i%4==0) {
ashleymills 0:3d62a105fd34 1875 DBG(" ");
ashleymills 0:3d62a105fd34 1876 DBGX(" %.2d ",i);
ashleymills 0:3d62a105fd34 1877 }
ashleymills 0:3d62a105fd34 1878 CoapPDU::printBinary(*option++);
ashleymills 0:3d62a105fd34 1879 DBGX(" ");
ashleymills 0:3d62a105fd34 1880 }
ashleymills 0:3d62a105fd34 1881 DBG(" ");
ashleymills 0:3d62a105fd34 1882 }
ashleymills 0:3d62a105fd34 1883
ashleymills 0:3d62a105fd34 1884 /// Dumps the PDU header in hex.
ashleymills 0:3d62a105fd34 1885 void CoapPDU::printHex() {
ashleymills 0:3d62a105fd34 1886 printf("Hexdump dump of PDU\r\n");
ashleymills 0:3d62a105fd34 1887 printf("%.2x %.2x %.2x %.2x",_pdu[0],_pdu[1],_pdu[2],_pdu[3]);
ashleymills 0:3d62a105fd34 1888 }
ashleymills 0:3d62a105fd34 1889
ashleymills 0:3d62a105fd34 1890 /// Dumps the entire PDU in binary.
ashleymills 0:3d62a105fd34 1891 void CoapPDU::printBin() {
ashleymills 0:3d62a105fd34 1892 for(int i=0; i<_pduLength; i++) {
ashleymills 0:3d62a105fd34 1893 if(i%4==0) {
ashleymills 0:3d62a105fd34 1894 printf("\r\n");
ashleymills 0:3d62a105fd34 1895 printf("%.2d ",i);
ashleymills 0:3d62a105fd34 1896 }
ashleymills 0:3d62a105fd34 1897 CoapPDU::printBinary(_pdu[i]); printf(" ");
ashleymills 0:3d62a105fd34 1898 }
ashleymills 0:3d62a105fd34 1899 printf("\r\n");
ashleymills 0:3d62a105fd34 1900 }
ashleymills 0:3d62a105fd34 1901
ashleymills 0:3d62a105fd34 1902 /// Prints a single byte in binary.
ashleymills 0:3d62a105fd34 1903 void CoapPDU::printBinary(uint8_t b) {
ashleymills 0:3d62a105fd34 1904 printf("%d%d%d%d%d%d%d%d",
ashleymills 0:3d62a105fd34 1905 (b&0x80)&&0x01,
ashleymills 0:3d62a105fd34 1906 (b&0x40)&&0x01,
ashleymills 0:3d62a105fd34 1907 (b&0x20)&&0x01,
ashleymills 0:3d62a105fd34 1908 (b&0x10)&&0x01,
ashleymills 0:3d62a105fd34 1909 (b&0x08)&&0x01,
ashleymills 0:3d62a105fd34 1910 (b&0x04)&&0x01,
ashleymills 0:3d62a105fd34 1911 (b&0x02)&&0x01,
ashleymills 0:3d62a105fd34 1912 (b&0x01)&&0x01);
ashleymills 0:3d62a105fd34 1913 }
ashleymills 0:3d62a105fd34 1914
ashleymills 0:3d62a105fd34 1915 /// Dumps the PDU as a byte sequence to stdout.
ashleymills 0:3d62a105fd34 1916 void CoapPDU::print() {
ashleymills 0:3d62a105fd34 1917 fwrite(_pdu,1,_pduLength,stdout);
ashleymills 1:5eec2844ad47 1918 }