Adapted to LoRa Semtech + Nucleo

Dependents:   LoRaWAN-lmic-app LoRaWAN-lmic-app LoRaWAN-test-10secs LoRaPersonalizedDeviceForEverynet ... more

Fork of cantcoap by Ashley Mills

Committer:
pnysten
Date:
Fri Nov 20 12:30:26 2015 +0000
Revision:
2:d0d57af6c9df
Parent:
1:5eec2844ad47
?

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