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:
ashleymills
Date:
Thu Jan 30 14:07:56 2014 +0000
Revision:
1:5eec2844ad47
Parent:
0:3d62a105fd34
Child:
2:1544f4758e0a
Updated to sync with github version.

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