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:
Tue Oct 08 14:36:01 2013 +0000
Revision:
0:3d62a105fd34
Child:
1:5eec2844ad47
CoAP library with a focus on simplicity. Init.

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