This is CoAP library with a focus on simplicity. It offers minimal CoAP PDU construction and decoding to and from byte buffers.
Fork of cantcoap by
cantcoap.cpp
00001 /* 00002 Copyright (c) 2013, Ashley Mills. 00003 All rights reserved. 00004 00005 Redistribution and use in source and binary forms, with or without 00006 modification, are permitted provided that the following conditions are met: 00007 00008 1. Redistributions of source code must retain the above copyright notice, this 00009 list of conditions and the following disclaimer. 00010 2. Redistributions in binary form must reproduce the above copyright notice, 00011 this list of conditions and the following disclaimer in the documentation 00012 and/or other materials provided with the distribution. 00013 00014 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00015 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00016 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00017 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 00018 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00019 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00020 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00021 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00022 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00023 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00024 */ 00025 00026 // version, 2 bits 00027 // type, 2 bits 00028 // 00 Confirmable 00029 // 01 Non-confirmable 00030 // 10 Acknowledgement 00031 // 11 Reset 00032 00033 // token length, 4 bits 00034 // length of token in bytes (only 0 to 8 bytes allowed) 00035 #include <stdio.h> 00036 #include <stdlib.h> 00037 #include <stdint.h> 00038 #include <string.h> 00039 #include <inet.h> 00040 #include "cantcoap.h" 00041 00042 // for debugging output you need https://mbed.org/users/donatien/code/DebugLib/ 00043 #define __DEBUG__ 0 // INFO 00044 #ifndef __MODULE__ 00045 #define __MODULE__ "cantcoap.cpp" 00046 #endif 00047 00048 00049 //#include "dbg.h" 00050 // some extra debug stuff 00051 #if __DEBUG__ > 0 00052 #define INFOX(...) do { fprintf(stderr,__VA_ARGS__); } while(0) 00053 #define INFOLX(...) do { fprintf(stderr,"[INFO] %s:%d ",__MODULE__,__LINE__); fprintf(stderr,__VA_ARGS__); } while(0) 00054 #define DBGLX(...) do { fprintf(stderr,"[DBG] %s:%d ",__MODULE__,__LINE__); fprintf(stderr,__VA_ARGS__); } while(0) 00055 #define DBG_PDU() do { printBin(); } while(0) 00056 #else 00057 #define INFOX(...) do{} while(0) 00058 #define INFOLX(...) do{} while(0) 00059 #define DBGLX(...) do{} while(0) 00060 #define DBG_PDU() do{} while(0) 00061 #endif 00062 00063 #define DBG(...) do{} while(0) 00064 #define DBGX(...) do{} while(0) 00065 #define INFO(...) do{} while(0) 00066 /// Memory-managed constructor. Buffer for PDU is dynamically sized and allocated by the object. 00067 /** 00068 * When using this constructor, the CoapPDU class will allocate space for the PDU. 00069 * Contrast this with the parameterized constructors, which allow the use of an external buffer. 00070 * 00071 * Note, the PDU container and space can be reused by issuing a CoapPDU::reset(). If the new PDU exceeds the 00072 * space of the previously allocated memory, then further memory will be dynamically allocated. 00073 * 00074 * Deleting the object will free the Object container and all dynamically allocated memory. 00075 * 00076 * \note It would have been nice to use something like UDP_CORK or MSG_MORE, to allow separate buffers 00077 * for token, options, and payload but these FLAGS aren't implemented for UDP in LwIP so stuck with one buffer for now. 00078 * 00079 * CoAP version defaults to 1. 00080 * 00081 * \sa CoapPDU::CoapPDU(uint8_t *pdu, int pduLength), CoapPDU::CoapPDU::(uint8_t *buffer, int bufferLength, int pduLength), 00082 * CoapPDU:CoapPDU()~ 00083 * 00084 */ 00085 CoapPDU::CoapPDU() { 00086 // pdu 00087 _pdu = (uint8_t*)calloc(4,sizeof(uint8_t)); 00088 _pduLength = 4; 00089 _bufferLength = _pduLength; 00090 00091 //options 00092 _numOptions = 0; 00093 _maxAddedOptionNumber = 0; 00094 00095 // payload 00096 _payloadPointer = NULL; 00097 _payloadLength = 0; 00098 00099 _constructedFromBuffer = 0; 00100 00101 setVersion(1); 00102 } 00103 00104 /// Construct a PDU using an external buffer. No copy of the buffer is made. 00105 /** 00106 * This constructor is normally used where a PDU has been received over the network, and it's length is known. 00107 * In this case the CoapPDU object is probably going to be used as a temporary container to access member values. 00108 * 00109 * It is assumed that \b pduLength is the length of the actual CoAP PDU, and consequently the buffer will also be this size, 00110 * contrast this with CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength) which allows the buffer to 00111 * be larger than the PDU. 00112 * 00113 * A PDU constructed in this manner must be validated with CoapPDU::validate() before the member variables will be accessible. 00114 * 00115 * \warning The validation call parses the PDU structure to set some internal parameters. If you do 00116 * not validate the PDU, then the behaviour of member access functions will be undefined. 00117 * 00118 * The buffer can be reused by issuing a CoapPDU::reset() but the class will not change the size of the buffer. If the 00119 * newly constructed PDU exceeds the size of the buffer, the function called (for example CoapPDU::addOption) will fail. 00120 * 00121 * Deleting this object will only delete the Object container and will not delete the PDU buffer. 00122 * 00123 * @param pdu A pointer to an array of bytes which comprise the CoAP PDU 00124 * @param pduLength The length of the CoAP PDU pointed to by \b pdu 00125 00126 * \sa CoapPDU::CoapPDU(), CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength) 00127 */ 00128 CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) { 00129 int bufferLength = pduLength; 00130 // sanity 00131 if(pduLength<4&&pduLength!=0) { 00132 DBG("PDU cannot have a length less than 4"); 00133 } 00134 00135 // pdu 00136 _pdu = pdu; 00137 _bufferLength = bufferLength; 00138 if(pduLength==0) { 00139 // this is actually a fresh pdu, header always exists 00140 _pduLength = 4; 00141 // make sure header is zeroed 00142 _pdu[0] = 0x00; _pdu[1] = 0x00; _pdu[2] = 0x00; _pdu[3] = 0x00; 00143 setVersion(1); 00144 } else { 00145 _pduLength = pduLength; 00146 } 00147 00148 _constructedFromBuffer = 1; 00149 00150 // options 00151 _numOptions = 0; 00152 _maxAddedOptionNumber = 0; 00153 00154 // payload 00155 _payloadPointer = NULL; 00156 _payloadLength = 0; 00157 } 00158 00159 /// Construct object from external buffer that may be larger than actual PDU. 00160 /** 00161 * This differs from CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) in that the buffer may be larger 00162 * than the actual CoAP PDU contained int the buffer. This is typically used when a large buffer is reused 00163 * multiple times. Note that \b pduLength can be 0. 00164 * 00165 * If an actual CoAP PDU is passed in the buffer, \b pduLength should match its length. CoapPDU::validate() must 00166 * be called to initiate the object before member functions can be used. 00167 * 00168 * A PDU constructed in this manner must be validated with CoapPDU::validate() before the member variables will be accessible. 00169 * 00170 * \warning The validation call parses the PDU structure to set some internal parameters. If you do 00171 * not validate the PDU, then the behaviour of member access functions will be undefined. 00172 * 00173 * The buffer can be reused by issuing a CoapPDU::reset() but the class will not change the size of the buffer. If the 00174 * newly constructed PDU exceeds the size of the buffer, the function called (for example CoapPDU::addOption) will fail. 00175 * 00176 * Deleting this object will only delete the Object container and will not delete the PDU buffer. 00177 * 00178 * \param buffer A buffer which either contains a CoAP PDU or is intended to be used to construct one. 00179 * \param bufferLength The length of the buffer 00180 * \param pduLength If the buffer contains a CoAP PDU, this specifies the length of the PDU within the buffer. 00181 * 00182 * \sa CoapPDU::CoapPDU(), CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) 00183 */ 00184 CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength) { 00185 // sanity 00186 if(pduLength<4&&pduLength!=0) { 00187 DBG("PDU cannot have a length less than 4"); 00188 } 00189 00190 // pdu 00191 _pdu = buffer; 00192 _bufferLength = bufferLength; 00193 if(pduLength==0) { 00194 // this is actually a fresh pdu, header always exists 00195 _pduLength = 4; 00196 // make sure header is zeroed 00197 _pdu[0] = 0x00; _pdu[1] = 0x00; _pdu[2] = 0x00; _pdu[3] = 0x00; 00198 setVersion(1); 00199 } else { 00200 _pduLength = pduLength; 00201 } 00202 00203 _constructedFromBuffer = 1; 00204 00205 // options 00206 _numOptions = 0; 00207 _maxAddedOptionNumber = 0; 00208 00209 // payload 00210 _payloadPointer = NULL; 00211 _payloadLength = 0; 00212 } 00213 00214 /// Reset CoapPDU container so it can be reused to build a new PDU. 00215 /** 00216 * This resets the CoapPDU container, setting the pdu length, option count, etc back to zero. The 00217 * PDU can then be populated as if it were newly constructed. 00218 * 00219 * Note that the space available will depend on how the CoapPDU was originally constructed: 00220 * -# CoapPDU::CoapPDU() 00221 * 00222 * Available space initially be \b _pduLength. But further space will be allocated as needed on demand, 00223 * limited only by the OS/environment. 00224 * 00225 * -# CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) 00226 * 00227 * Space is limited by the variable \b pduLength. The PDU cannot exceed \b pduLength bytes. 00228 * 00229 * -# CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength) 00230 * 00231 * Space is limited by the variable \b bufferLength. The PDU cannot exceed \b bufferLength bytes. 00232 * 00233 * \return 0 on success, 1 on failure. 00234 */ 00235 int CoapPDU::reset() { 00236 // pdu 00237 memset(_pdu,0x00,_bufferLength); 00238 // packet always has at least a header 00239 _pduLength = 4; 00240 00241 // options 00242 _numOptions = 0; 00243 _maxAddedOptionNumber = 0; 00244 // payload 00245 _payloadPointer = NULL; 00246 _payloadLength = 0; 00247 return 0; 00248 } 00249 00250 /// Validates a PDU constructed using an external buffer. 00251 /** 00252 * When a CoapPDU is constructed using an external buffer, the programmer must call this function to 00253 * check that the received PDU is a valid CoAP PDU. 00254 * 00255 * \warning The validation call parses the PDU structure to set some internal parameters. If you do 00256 * not validate the PDU, then the behaviour of member access functions will be undefined. 00257 * 00258 * \return 1 if the PDU validates correctly, 0 if not. XXX maybe add some error codes 00259 */ 00260 int CoapPDU::validate() { 00261 if(_pduLength<4) { 00262 DBG("PDU has to be a minimum of 4 bytes. This: %d bytes",_pduLength); 00263 return 0; 00264 } 00265 00266 // check header 00267 // 0 1 2 3 00268 // 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 00269 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00270 // |Ver| T | TKL | Code | Message ID | 00271 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00272 // | Token (if any, TKL bytes) ... 00273 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00274 // | Options (if any) ... 00275 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00276 // |1 1 1 1 1 1 1 1| Payload (if any) ... 00277 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00278 00279 DBG("Version: %d",getVersion()); 00280 DBG("Type: %d",getType()); 00281 00282 // token length must be between 0 and 8 00283 int tokenLength = getTokenLength(); 00284 if(tokenLength<0||tokenLength>8) { 00285 DBG("Invalid token length: %d",tokenLength); 00286 return 0; 00287 } 00288 DBG("Token length: %d",tokenLength); 00289 // check total length 00290 if((COAP_HDR_SIZE+tokenLength)>_pduLength) { 00291 DBG("Token length would make pdu longer than actual length."); 00292 return 0; 00293 } 00294 00295 // check that code is valid 00296 CoapPDU::Code code = getCode(); 00297 if(code<COAP_EMPTY || 00298 (code>COAP_DELETE&&code<COAP_CREATED) || 00299 (code>COAP_CONTENT&&code<COAP_BAD_REQUEST) || 00300 (code>COAP_NOT_ACCEPTABLE&&code<COAP_PRECONDITION_FAILED) || 00301 (code==0x8E) || 00302 (code>COAP_UNSUPPORTED_CONTENT_FORMAT&&code<COAP_INTERNAL_SERVER_ERROR) || 00303 (code>COAP_PROXYING_NOT_SUPPORTED) ) { 00304 DBG("Invalid CoAP code: %d",code); 00305 return 0; 00306 } 00307 DBG("CoAP code: %d",code); 00308 00309 // token can be anything so nothing to check 00310 00311 // check that options all make sense 00312 uint16_t optionDelta =0, optionNumber = 0, optionValueLength = 0; 00313 int totalLength = 0; 00314 00315 // first option occurs after token 00316 int optionPos = COAP_HDR_SIZE + getTokenLength(); 00317 00318 // may be 0 options 00319 if(optionPos==_pduLength) { 00320 DBG("No options. No payload."); 00321 _numOptions = 0; 00322 _payloadLength = 0; 00323 return 1; 00324 } 00325 00326 int bytesRemaining = _pduLength-optionPos; 00327 int numOptions = 0; 00328 uint8_t upperNibble = 0x00, lowerNibble = 0x00; 00329 00330 // walk over options and record information 00331 while(1) { 00332 // check for payload marker 00333 if(bytesRemaining>0) { 00334 uint8_t optionHeader = _pdu[optionPos]; 00335 if(optionHeader==0xFF) { 00336 // payload 00337 if(bytesRemaining>1) { 00338 _payloadPointer = &_pdu[optionPos+1]; 00339 _payloadLength = (bytesRemaining-1); 00340 _numOptions = numOptions; 00341 DBG("Payload found, length: %d",_payloadLength); 00342 return 1; 00343 } 00344 // payload marker but no payload 00345 _payloadPointer = NULL; 00346 _payloadLength = 0; 00347 DBG("Payload marker but no payload."); 00348 return 0; 00349 } 00350 00351 // check that option delta and option length are valid values 00352 upperNibble = (optionHeader & 0xF0) >> 4; 00353 lowerNibble = (optionHeader & 0x0F); 00354 if(upperNibble==0x0F||lowerNibble==0x0F) { 00355 DBG("Expected option header or payload marker, got: 0x%x%x",upperNibble,lowerNibble); 00356 return 0; 00357 } 00358 DBG("Option header byte appears sane: 0x%x%x",upperNibble,lowerNibble); 00359 } else { 00360 DBG("No more data. No payload."); 00361 _payloadPointer = NULL; 00362 _payloadLength = 0; 00363 _numOptions = numOptions; 00364 return 1; 00365 } 00366 00367 // skip over option header byte 00368 bytesRemaining--; 00369 00370 // check that there is enough space for the extended delta and length bytes (if any) 00371 int headerBytesNeeded = computeExtraBytes(upperNibble); 00372 DBG("%d extra bytes needed for extended delta",headerBytesNeeded); 00373 if(headerBytesNeeded>bytesRemaining) { 00374 DBG("Not enough space for extended option delta, needed %d, have %d.",headerBytesNeeded,bytesRemaining); 00375 return 0; 00376 } 00377 headerBytesNeeded += computeExtraBytes(lowerNibble); 00378 if(headerBytesNeeded>bytesRemaining) { 00379 DBG("Not enough space for extended option length, needed %d, have %d.", 00380 (headerBytesNeeded-computeExtraBytes(upperNibble)),bytesRemaining); 00381 return 0; 00382 } 00383 DBG("Enough space for extended delta and length: %d, continuing.",headerBytesNeeded); 00384 00385 // extract option details 00386 optionDelta = getOptionDelta(&_pdu[optionPos]); 00387 optionNumber += optionDelta; 00388 optionValueLength = getOptionValueLength(&_pdu[optionPos]); 00389 DBG("Got option: %d with length %d",optionNumber,optionValueLength); 00390 // compute total length 00391 totalLength = 1; // mandatory header 00392 totalLength += computeExtraBytes(optionDelta); 00393 totalLength += computeExtraBytes(optionValueLength); 00394 totalLength += optionValueLength; 00395 // check there is enough space 00396 if(optionPos+totalLength>_pduLength) { 00397 DBG("Not enough space for option payload, needed %d, have %d.",(totalLength-headerBytesNeeded-1),_pduLength-optionPos); 00398 return 0; 00399 } 00400 DBG("Enough space for option payload: %d %d",optionValueLength,(totalLength-headerBytesNeeded-1)); 00401 00402 // recompute bytesRemaining 00403 bytesRemaining -= totalLength; 00404 bytesRemaining++; // correct for previous -- 00405 00406 // move to next option 00407 optionPos += totalLength; 00408 00409 // inc number of options XXX 00410 numOptions++; 00411 } 00412 00413 return 1; 00414 } 00415 00416 /// Destructor. Does not free buffer if constructor passed an external buffer. 00417 /** 00418 * The destructor acts differently, depending on how the object was initially constructed (from buffer or not): 00419 * 00420 * -# CoapPDU::CoapPDU() 00421 * 00422 * Complete object is destroyed. 00423 * 00424 * -# CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) 00425 * 00426 * Only object container is destroyed. \b pdu is left intact. 00427 * 00428 * -# CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength) 00429 * 00430 * Only object container is destroyed. \b pdu is left intact. 00431 * 00432 */ 00433 CoapPDU::~CoapPDU() { 00434 if(!_constructedFromBuffer) { 00435 free(_pdu); 00436 } 00437 } 00438 00439 /// Returns a pointer to the internal buffer. 00440 uint8_t* CoapPDU::getPDUPointer() { 00441 return _pdu; 00442 } 00443 00444 /// Set the PDU length to the length specified. 00445 /** 00446 * This is used when re-using a PDU container before calling CoapPDU::validate() as it 00447 * is not possible to deduce the length of a PDU since the payload has no length marker. 00448 * \param len The length of the PDU 00449 */ 00450 void CoapPDU::setPDULength(int len) { 00451 _pduLength = len; 00452 } 00453 00454 /// Shorthand function for setting a resource URI. 00455 /** 00456 * Calls CoapPDU::setURI(uri,strlen(uri). 00457 */ 00458 int CoapPDU::setURI(char *uri) { 00459 return setURI(uri,strlen(uri)); 00460 } 00461 00462 /// Shorthand function for setting a resource URI. 00463 /** 00464 * This will parse the supplied \b uri and construct enough URI_PATH CoAP options to encode it. 00465 * The options are added to the PDU. 00466 * 00467 * At present queries are not handled. TODO Implement queries. 00468 * 00469 * \note This uses an internal buffer of 16 bytes to manipulate strings. The internal buffer will be 00470 * expanded dynamically if necessary (path component longer than 16 bytes). The internal buffer will 00471 * be freed before the function returns. 00472 * 00473 * \param uri The uri to parse. 00474 * \param urilen The length of the uri to parse. 00475 * 00476 * \return 1 on success, 0 on failure. 00477 */ 00478 int CoapPDU::setURI(char *uri, int urilen) { 00479 // only '/' and alphabetic chars allowed 00480 // very simple splitting done 00481 00482 // sanitation 00483 if(urilen<=0||uri==NULL) { 00484 DBG("Null or zero-length uri passed."); 00485 return 1; 00486 } 00487 00488 // single character URI path (including '/' case) 00489 if(urilen==1) { 00490 addOption(COAP_OPTION_URI_PATH,1,(uint8_t*)uri); 00491 return 0; 00492 } 00493 00494 // local vars 00495 char *startP=uri,*endP=NULL; 00496 int oLen = 0; 00497 int bufSpace = 16; 00498 char *uriBuf = (char*)malloc(bufSpace*sizeof(char)); 00499 if(uriBuf==NULL) { 00500 DBG("Error allocating temporary memory."); 00501 return 1; 00502 } 00503 00504 while(1) { 00505 // stop at end of string 00506 if(*startP==0x00||*(startP+1)==0x00) { 00507 break; 00508 } 00509 00510 // ignore leading slash 00511 if(*startP=='/') { 00512 DBG("Skipping leading slash"); 00513 startP++; 00514 } 00515 00516 // find next split point 00517 endP = strchr(startP,'/'); 00518 00519 // might not be another slash 00520 if(endP==NULL) { 00521 DBG("Ending out of slash"); 00522 endP = uri+urilen; 00523 } 00524 00525 // get length of segment 00526 oLen = endP-startP; 00527 00528 // copy sequence, make space if necessary 00529 if((oLen+1)>bufSpace) { 00530 char *newBuf = (char*)realloc(uriBuf,oLen+1); 00531 if(newBuf==NULL) { 00532 DBG("Error making space for temporary buffer"); 00533 free(uriBuf); 00534 return 1; 00535 } 00536 uriBuf = newBuf; 00537 } 00538 00539 // copy into temporary buffer 00540 memcpy(uriBuf,startP,oLen); 00541 uriBuf[oLen] = 0x00; 00542 DBG("Adding URI_PATH %s",uriBuf); 00543 // add option 00544 if(addOption(COAP_OPTION_URI_PATH,oLen,(uint8_t*)uriBuf)!=0) { 00545 DBG("Error adding option"); 00546 return 1; 00547 } 00548 startP = endP; 00549 } 00550 00551 // clean up 00552 free(uriBuf); 00553 return 0; 00554 } 00555 /// Shorthand for adding a URI QUERY to the option list. 00556 /** 00557 * Adds a new option to the CoAP PDU that encodes a URI_QUERY. 00558 * 00559 * \param query The uri query to encode. 00560 * \return 0 on success, 1 on failure. 00561 */ 00562 int CoapPDU::addURIQuery(char *query) { 00563 return addOption(COAP_OPTION_URI_QUERY,strlen(query),(uint8_t*)query); 00564 } 00565 00566 /// Concatenates any URI_PATH elements into a single string. 00567 /** 00568 * Parses the PDU options and extracts all URI_PATH elements, concatenating them into a single string with slash separators. 00569 * The produced string will be null terminated. 00570 * 00571 * \param dst Buffer into which to copy the concatenated path elements. 00572 * \param dstlen Length of buffer. 00573 * \param outLen Pointer to integer, into which URI length will be placed. 00574 * 00575 * \return 0 on success, 1 on failure. \b outLen will contain the length of the concatenated elements. 00576 */ 00577 int CoapPDU::getURI(char *dst, int dstlen, int *outLen) { 00578 if(outLen==NULL) { 00579 DBG("Output length pointer is NULL"); 00580 return 1; 00581 } 00582 00583 if(dst==NULL) { 00584 DBG("NULL destination buffer"); 00585 *outLen = 0; 00586 return 1; 00587 } 00588 00589 // check destination space 00590 if(dstlen<=0) { 00591 *dst = 0x00; 00592 *outLen = 0; 00593 DBG("Destination buffer too small (0)!"); 00594 return 1; 00595 } 00596 // check option count 00597 if(_numOptions==0) { 00598 *dst = 0x00; 00599 *outLen = 0; 00600 return 0; 00601 } 00602 // get options 00603 CoapPDU::CoapOption *options = getOptions(); 00604 if(options==NULL) { 00605 *dst = 0x00; 00606 *outLen = 0; 00607 return 0; 00608 } 00609 // iterate over options to construct URI 00610 CoapOption *o = NULL; 00611 int bytesLeft = dstlen-1; // space for 0x00 00612 int oLen = 0; 00613 // add slash at beggining 00614 if(bytesLeft>=1) { 00615 *dst = '/'; 00616 dst++; 00617 bytesLeft--; 00618 } else { 00619 DBG("No space for initial slash needed 1, got %d",bytesLeft); 00620 return 1; 00621 } 00622 for(int i=0; i<_numOptions; i++) { 00623 o = &options[i]; 00624 oLen = o->optionValueLength; 00625 if(o->optionNumber==COAP_OPTION_URI_PATH) { 00626 // check space 00627 if(oLen>bytesLeft) { 00628 DBG("Destination buffer too small, needed %d, got %d",oLen,bytesLeft); 00629 return 1; 00630 } 00631 00632 // case where single '/' exists 00633 if(oLen==1&&o->optionValuePointer[0]=='/') { 00634 *dst = 0x00; 00635 *outLen = 1; 00636 return 0; 00637 } 00638 00639 // copy URI path component 00640 memcpy(dst,o->optionValuePointer,oLen); 00641 00642 // adjust counters 00643 dst += oLen; 00644 bytesLeft -= oLen; 00645 00646 // add slash following (don't know at this point if another option is coming) 00647 if(bytesLeft>=1) { 00648 *dst = '/'; 00649 dst++; 00650 bytesLeft--; 00651 } else { 00652 DBG("Ran out of space after processing option"); 00653 return 1; 00654 } 00655 } 00656 } 00657 00658 // remove terminating slash 00659 dst--; 00660 bytesLeft++; 00661 // add null terminating byte (always space since reserved) 00662 *dst = 0x00; 00663 *outLen = (dstlen-1)-bytesLeft; 00664 return 0; 00665 } 00666 00667 /// Sets the CoAP version. 00668 /** 00669 * \param version CoAP version between 0 and 3. 00670 * \return 0 on success, 1 on failure. 00671 */ 00672 int CoapPDU::setVersion(uint8_t version) { 00673 if(version>3) { 00674 return 0; 00675 } 00676 00677 _pdu[0] &= 0x3F; 00678 _pdu[0] |= (version << 6); 00679 return 1; 00680 } 00681 00682 /** 00683 * Gets the CoAP Version. 00684 * @return The CoAP version between 0 and 3. 00685 */ 00686 uint8_t CoapPDU::getVersion() { 00687 return (_pdu[0]&0xC0)>>6; 00688 } 00689 00690 /** 00691 * Sets the type of this CoAP PDU. 00692 * \param mt The type, one of: 00693 * - COAP_CONFIRMABLE 00694 * - COAP_NON_CONFIRMABLE 00695 * - COAP_ACKNOWLEDGEMENT 00696 * - COAP_RESET. 00697 */ 00698 void CoapPDU::setType(CoapPDU::Type mt) { 00699 _pdu[0] &= 0xCF; 00700 _pdu[0] |= mt; 00701 } 00702 00703 /// Returns the type of the PDU. 00704 CoapPDU::Type CoapPDU::getType() { 00705 return (CoapPDU::Type)(_pdu[0]&0x30); 00706 } 00707 00708 00709 /// Set the token length. 00710 /** 00711 * \param tokenLength The length of the token in bytes, between 0 and 8. 00712 * \return 0 on success, 1 on failure. 00713 */ 00714 int CoapPDU::setTokenLength(uint8_t tokenLength) { 00715 if(tokenLength>8) 00716 return 1; 00717 00718 _pdu[0] &= 0xF0; 00719 _pdu[0] |= tokenLength; 00720 return 0; 00721 } 00722 00723 /// Returns the token length. 00724 int CoapPDU::getTokenLength() { 00725 return _pdu[0] & 0x0F; 00726 } 00727 00728 /// Returns a pointer to the PDU token. 00729 uint8_t* CoapPDU::getTokenPointer() { 00730 if(getTokenLength()==0) { 00731 return NULL; 00732 } 00733 return &_pdu[4]; 00734 } 00735 00736 /// Set the PDU token to the supplied byte sequence. 00737 /** 00738 * This sets the PDU token to \b token and sets the token length to \b tokenLength. 00739 * \param token A sequence of bytes representing the token. 00740 * \param tokenLength The length of the byte sequence. 00741 * \return 0 on success, 1 on failure. 00742 */ 00743 int CoapPDU::setToken(uint8_t *token, uint8_t tokenLength) { 00744 DBG("Setting token"); 00745 if(token==NULL) { 00746 DBG("NULL pointer passed as token reference"); 00747 return 1; 00748 } 00749 00750 if(tokenLength==0) { 00751 DBG("Token has zero length"); 00752 return 1; 00753 } 00754 00755 // if tokenLength has not changed, just copy the new value 00756 uint8_t oldTokenLength = getTokenLength(); 00757 if(tokenLength==oldTokenLength) { 00758 memcpy((void*)&_pdu[4],token,tokenLength); 00759 return 0; 00760 } 00761 00762 // otherwise compute new length of PDU 00763 uint8_t oldPDULength = _pduLength; 00764 _pduLength -= oldTokenLength; 00765 _pduLength += tokenLength; 00766 00767 // now, have to shift old memory around, but shift direction depends 00768 // whether pdu is now bigger or smaller 00769 if(_pduLength>oldPDULength) { 00770 // new PDU is bigger, need to allocate space for new PDU 00771 if(!_constructedFromBuffer) { 00772 uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength); 00773 if(newMemory==NULL) { 00774 // malloc failed 00775 DBG("Failed to allocate memory for token"); 00776 _pduLength = oldPDULength; 00777 return 1; 00778 } 00779 _pdu = newMemory; 00780 _bufferLength = _pduLength; 00781 } else { 00782 // constructed from buffer, check space 00783 if(_pduLength>_bufferLength) { 00784 DBG("Buffer too small to contain token, needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength); 00785 _pduLength = oldPDULength; 00786 return 1; 00787 } 00788 } 00789 00790 // and then shift everything after token up to end of new PDU 00791 // memory overlaps so do this manually so to avoid additional mallocs 00792 int shiftOffset = _pduLength-oldPDULength; 00793 int shiftAmount = _pduLength-tokenLength-COAP_HDR_SIZE; // everything after token 00794 shiftPDUUp(shiftOffset,shiftAmount); 00795 00796 // now copy the token into the new space and set official token length 00797 memcpy((void*)&_pdu[4],token,tokenLength); 00798 setTokenLength(tokenLength); 00799 00800 // and return success 00801 return 0; 00802 } 00803 00804 // new PDU is smaller, copy the new token value over the old one 00805 memcpy((void*)&_pdu[4],token,tokenLength); 00806 // and shift everything after the new token down 00807 int startLocation = COAP_HDR_SIZE+tokenLength; 00808 int shiftOffset = oldPDULength-_pduLength; 00809 int shiftAmount = oldPDULength-oldTokenLength-COAP_HDR_SIZE; 00810 shiftPDUDown(startLocation,shiftOffset,shiftAmount); 00811 // then reduce size of buffer 00812 if(!_constructedFromBuffer) { 00813 uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength); 00814 if(newMemory==NULL) { 00815 // malloc failed, PDU in inconsistent state 00816 DBG("Failed to shrink PDU for new token. PDU probably broken"); 00817 return 1; 00818 } 00819 _pdu = newMemory; 00820 _bufferLength = _pduLength; 00821 } 00822 00823 // and officially set the new tokenLength 00824 setTokenLength(tokenLength); 00825 return 0; 00826 } 00827 00828 /// Sets the CoAP response code 00829 void CoapPDU::setCode(CoapPDU::Code code) { 00830 _pdu[1] = code; 00831 // there is a limited set of response codes 00832 } 00833 00834 /// Gets the CoAP response code 00835 CoapPDU::Code CoapPDU::getCode() { 00836 return (CoapPDU::Code)_pdu[1]; 00837 } 00838 00839 00840 /// Converts a http status code as an integer, to a CoAP code. 00841 /** 00842 * \param httpStatus the HTTP status code as an integer (e.g 200) 00843 * \return The correct corresponding CoapPDU::Code on success, 00844 * CoapPDU::COAP_UNDEFINED_CODE on failure. 00845 */ 00846 CoapPDU::Code CoapPDU::httpStatusToCode(int httpStatus) { 00847 switch(httpStatus) { 00848 case 1: 00849 return CoapPDU::COAP_GET; 00850 case 2: 00851 return CoapPDU::COAP_POST; 00852 case 3: 00853 return CoapPDU::COAP_PUT; 00854 case 4: 00855 return CoapPDU::COAP_DELETE; 00856 case 201: 00857 return CoapPDU::COAP_CREATED; 00858 case 202: 00859 return CoapPDU::COAP_DELETED; 00860 case 203: 00861 return CoapPDU::COAP_VALID; 00862 case 204: 00863 return CoapPDU::COAP_CHANGED; 00864 case 205: 00865 return CoapPDU::COAP_CONTENT; 00866 case 400: 00867 return CoapPDU::COAP_BAD_REQUEST; 00868 case 401: 00869 return CoapPDU::COAP_UNAUTHORIZED; 00870 case 402: 00871 return CoapPDU::COAP_BAD_OPTION; 00872 case 403: 00873 return CoapPDU::COAP_FORBIDDEN; 00874 case 404: 00875 return CoapPDU::COAP_NOT_FOUND; 00876 case 405: 00877 return CoapPDU::COAP_METHOD_NOT_ALLOWED; 00878 case 406: 00879 return CoapPDU::COAP_NOT_ACCEPTABLE; 00880 case 412: 00881 return CoapPDU::COAP_PRECONDITION_FAILED; 00882 case 413: 00883 return CoapPDU::COAP_REQUEST_ENTITY_TOO_LARGE; 00884 case 415: 00885 return CoapPDU::COAP_UNSUPPORTED_CONTENT_FORMAT; 00886 case 500: 00887 return CoapPDU::COAP_INTERNAL_SERVER_ERROR; 00888 case 501: 00889 return CoapPDU::COAP_NOT_IMPLEMENTED; 00890 case 502: 00891 return CoapPDU::COAP_BAD_GATEWAY; 00892 case 503: 00893 return CoapPDU::COAP_SERVICE_UNAVAILABLE; 00894 case 504: 00895 return CoapPDU::COAP_GATEWAY_TIMEOUT; 00896 case 505: 00897 return CoapPDU::COAP_PROXYING_NOT_SUPPORTED; 00898 default: 00899 return CoapPDU::COAP_UNDEFINED_CODE; 00900 } 00901 } 00902 00903 /// Set messageID to the supplied value. 00904 /** 00905 * \param messageID A 16bit message id. 00906 * \return 0 on success, 1 on failure. 00907 */ 00908 int CoapPDU::setMessageID(uint16_t messageID) { 00909 // message ID is stored in network byte order 00910 uint16_t networkOrder = htons(messageID); 00911 // bytes 2 and 3 hold the ID 00912 _pdu[2] &= 0x00; 00913 _pdu[2] |= (networkOrder >> 8); // MSB 00914 _pdu[3] &= 0x00; 00915 _pdu[3] |= (networkOrder & 0x00FF); // LSB 00916 return 0; 00917 } 00918 00919 /// Returns the 16 bit message ID of the PDU. 00920 uint16_t CoapPDU::getMessageID() { 00921 // mesasge ID is stored in network byteorder 00922 uint16_t networkOrder = 0x0000; 00923 networkOrder |= _pdu[2]; 00924 networkOrder <<= 8; 00925 networkOrder |= _pdu[3]; 00926 return ntohs(networkOrder); 00927 } 00928 00929 /// Returns the length of the PDU. 00930 int CoapPDU::getPDULength() { 00931 return _pduLength; 00932 } 00933 00934 /// Return the number of options that the PDU has. 00935 int CoapPDU::getNumOptions() { 00936 return _numOptions; 00937 } 00938 00939 00940 /** 00941 * This returns the options as a sequence of structs. 00942 */ 00943 CoapPDU::CoapOption* CoapPDU::getOptions() { 00944 DBG("getOptions() called, %d options.",_numOptions); 00945 00946 uint16_t optionDelta =0, optionNumber = 0, optionValueLength = 0; 00947 int totalLength = 0; 00948 00949 if(_numOptions==0) { 00950 return NULL; 00951 } 00952 00953 // malloc space for options 00954 CoapOption *options = (CoapOption*)malloc(_numOptions*sizeof(CoapOption)); 00955 00956 // first option occurs after token 00957 int optionPos = COAP_HDR_SIZE + getTokenLength(); 00958 00959 // walk over options and record information 00960 for(int i=0; i<_numOptions; i++) { 00961 // extract option details 00962 optionDelta = getOptionDelta(&_pdu[optionPos]); 00963 optionNumber += optionDelta; 00964 optionValueLength = getOptionValueLength(&_pdu[optionPos]); 00965 // compute total length 00966 totalLength = 1; // mandatory header 00967 totalLength += computeExtraBytes(optionDelta); 00968 totalLength += computeExtraBytes(optionValueLength); 00969 totalLength += optionValueLength; 00970 // record option details 00971 options[i].optionNumber = optionNumber; 00972 options[i].optionDelta = optionDelta; 00973 options[i].optionValueLength = optionValueLength; 00974 options[i].totalLength = totalLength; 00975 options[i].optionPointer = &_pdu[optionPos]; 00976 options[i].optionValuePointer = &_pdu[optionPos+totalLength-optionValueLength]; 00977 // move to next option 00978 optionPos += totalLength; 00979 } 00980 00981 return options; 00982 } 00983 00984 /// Add an option to the PDU. 00985 /** 00986 * Unlike other implementations, options can be added in any order, and in-memory manipulation will be 00987 * performed to ensure the correct ordering of options (they use a delta encoding of option numbers). 00988 * Re-ordering memory like this incurs a small performance cost, so if you care about this, then you 00989 * might want to add options in ascending order of option number. 00990 * \param optionNumber The number of the option, see the enum CoapPDU::Option for shorthand notations. 00991 * \param optionLength The length of the option payload in bytes. 00992 * \param optionValue A pointer to the byte sequence that is the option payload (bytes will be copied). 00993 * \return 0 on success, 1 on failure. 00994 */ 00995 int CoapPDU::addOption(uint16_t insertedOptionNumber, uint16_t optionValueLength, uint8_t *optionValue) { 00996 // this inserts the option in memory, and re-computes the deltas accordingly 00997 // prevOption <-- insertionPosition 00998 // nextOption 00999 01000 // find insertion location and previous option number 01001 uint16_t prevOptionNumber = 0; // option number of option before insertion point 01002 int insertionPosition = findInsertionPosition(insertedOptionNumber,&prevOptionNumber); 01003 DBG("inserting option at position %d, after option with number: %hu",insertionPosition,prevOptionNumber); 01004 01005 // compute option delta length 01006 uint16_t optionDelta = insertedOptionNumber-prevOptionNumber; 01007 uint8_t extraDeltaBytes = computeExtraBytes(optionDelta); 01008 01009 // compute option length length 01010 uint16_t extraLengthBytes = computeExtraBytes(optionValueLength); 01011 01012 // compute total length of option 01013 uint16_t optionLength = COAP_OPTION_HDR_BYTE + extraDeltaBytes + extraLengthBytes + optionValueLength; 01014 01015 // if this is at the end of the PDU, job is done, just malloc and insert 01016 if(insertionPosition==_pduLength) { 01017 DBG("Inserting at end of PDU"); 01018 // optionNumber must be biggest added 01019 _maxAddedOptionNumber = insertedOptionNumber; 01020 01021 // set new PDU length and allocate space for extra option 01022 int oldPDULength = _pduLength; 01023 _pduLength += optionLength; 01024 if(!_constructedFromBuffer) { 01025 uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength); 01026 if(newMemory==NULL) { 01027 DBG("Failed to allocate memory for option."); 01028 _pduLength = oldPDULength; 01029 // malloc failed 01030 return 1; 01031 } 01032 _pdu = newMemory; 01033 _bufferLength = _pduLength; 01034 } else { 01035 // constructed from buffer, check space 01036 if(_pduLength>_bufferLength) { 01037 DBG("Buffer too small for new option: needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength); 01038 _pduLength = oldPDULength; 01039 return 1; 01040 } 01041 } 01042 01043 // insert option at position 01044 insertOption(insertionPosition,optionDelta,optionValueLength,optionValue); 01045 _numOptions++; 01046 return 0; 01047 } 01048 // XXX could do 0xFF pdu payload case for changing of dynamically allocated application space SDUs < yeah, if you're insane 01049 01050 // the next option might (probably) needs it's delta changing 01051 // I want to take this into account when allocating space for the new 01052 // option, to avoid having to do two mallocs, first get info about this option 01053 int nextOptionDelta = getOptionDelta(&_pdu[insertionPosition]); 01054 int nextOptionNumber = prevOptionNumber + nextOptionDelta; 01055 int nextOptionDeltaBytes = computeExtraBytes(nextOptionDelta); 01056 // recompute option delta, relative to inserted option 01057 int newNextOptionDelta = nextOptionNumber-insertedOptionNumber; 01058 int newNextOptionDeltaBytes = computeExtraBytes(newNextOptionDelta); 01059 // determine adjustment 01060 int optionDeltaAdjustment = newNextOptionDeltaBytes-nextOptionDeltaBytes; 01061 01062 // create space for new option, including adjustment space for option delta 01063 DBG_PDU(); 01064 DBG("Creating space"); 01065 int mallocLength = optionLength+optionDeltaAdjustment; 01066 int oldPDULength = _pduLength; 01067 _pduLength += mallocLength; 01068 01069 if(!_constructedFromBuffer) { 01070 uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength); 01071 if(newMemory==NULL) { 01072 DBG("Failed to allocate memory for option"); 01073 _pduLength = oldPDULength; 01074 return 1; 01075 } 01076 _pdu = newMemory; 01077 _bufferLength = _pduLength; 01078 } else { 01079 // constructed from buffer, check space 01080 if(_pduLength>_bufferLength) { 01081 DBG("Buffer too small to contain option, needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength); 01082 _pduLength = oldPDULength; 01083 return 1; 01084 } 01085 } 01086 01087 // move remainder of PDU data up to create hole for new option 01088 DBG_PDU(); 01089 DBG("Shifting PDU."); 01090 shiftPDUUp(mallocLength,_pduLength-(insertionPosition+mallocLength)); 01091 DBG_PDU(); 01092 01093 // adjust option delta bytes of following option 01094 // move the option header to the correct position 01095 int nextHeaderPos = insertionPosition+mallocLength; 01096 _pdu[nextHeaderPos-optionDeltaAdjustment] = _pdu[nextHeaderPos]; 01097 nextHeaderPos -= optionDeltaAdjustment; 01098 // and set the new value 01099 setOptionDelta(nextHeaderPos, newNextOptionDelta); 01100 01101 // new option shorter 01102 // p p n n x x x x x 01103 // p p n n x x x x x - 01104 // p p - n n x x x x x 01105 // p p - - n x x x x x 01106 // p p o o n x x x x x 01107 01108 // new option longer 01109 // p p n n x x x x x 01110 // p p n n x x x x x - - - 01111 // p p - - - n n x x x x x 01112 // p p - - n n n x x x x x 01113 // p p o o n n n x x x x x 01114 01115 // note, it can only ever be shorter or the same since if an option was inserted the delta got smaller 01116 // but I'll leave that little comment in, just to show that it would work even if the delta got bigger 01117 01118 // now insert the new option into the gap 01119 DBGLX("Inserting new option..."); 01120 insertOption(insertionPosition,optionDelta,optionValueLength,optionValue); 01121 DBGX("done\r\n"); 01122 DBG_PDU(); 01123 01124 // done, mark it with B! 01125 return 0; 01126 } 01127 01128 /// Allocate space for a payload. 01129 /** 01130 * For dynamically constructed PDUs, this will allocate space for a payload in the object 01131 * and return a pointer to it. If the PDU was constructed from a buffer, this doesn't 01132 * malloc anything, it just changes the _pduLength and returns the payload pointer. 01133 * 01134 * \note The pointer returned points into the PDU buffer. 01135 * \param len The length of the payload buffer to allocate. 01136 * \return Either a pointer to the payload buffer, or NULL if there wasn't enough space / allocation failed. 01137 */ 01138 uint8_t* CoapPDU::mallocPayload(int len) { 01139 DBG("Entering mallocPayload"); 01140 // sanity checks 01141 if(len==0) { 01142 DBG("Cannot allocate a zero length payload"); 01143 return NULL; 01144 } 01145 01146 // further sanity 01147 if(len==_payloadLength) { 01148 DBG("Space for payload of specified length already exists"); 01149 if(_payloadPointer==NULL) { 01150 DBG("Garbage PDU. Payload length is %d, but existing _payloadPointer NULL",_payloadLength); 01151 return NULL; 01152 } 01153 return _payloadPointer; 01154 } 01155 01156 DBG("_bufferLength: %d, _pduLength: %d, _payloadLength: %d",_bufferLength,_pduLength,_payloadLength); 01157 01158 // might be making payload bigger (including bigger than 0) or smaller 01159 int markerSpace = 1; 01160 int payloadSpace = len; 01161 // is this a resizing? 01162 if(_payloadLength!=0) { 01163 // marker already exists 01164 markerSpace = 0; 01165 // compute new payload length (can be negative if shrinking payload) 01166 payloadSpace = len-_payloadLength; 01167 } 01168 01169 // make space for payload (and payload marker if necessary) 01170 int newLen = _pduLength+payloadSpace+markerSpace; 01171 if(!_constructedFromBuffer) { 01172 uint8_t* newPDU = (uint8_t*)realloc(_pdu,newLen); 01173 if(newPDU==NULL) { 01174 DBG("Cannot allocate (or shrink) space for payload"); 01175 return NULL; 01176 } 01177 _pdu = newPDU; 01178 _bufferLength = newLen; 01179 } else { 01180 // constructed from buffer, check space 01181 DBG("newLen: %d, _bufferLength: %d",newLen,_bufferLength); 01182 if(newLen>_bufferLength) { 01183 DBG("Buffer too small to contain desired payload, needed %d, got %d.",newLen-_pduLength,_bufferLength-_pduLength); 01184 return NULL; 01185 } 01186 } 01187 01188 // deal with fresh allocation case separately 01189 if(_payloadPointer==NULL) { 01190 // set payload marker 01191 _pdu[_pduLength] = 0xFF; 01192 // payload at end of old PDU 01193 _payloadPointer = &_pdu[_pduLength+1]; 01194 _pduLength = newLen; 01195 _payloadLength = len; 01196 return _payloadPointer; 01197 } 01198 01199 // otherwise, just adjust length of PDU 01200 _pduLength = newLen; 01201 _payloadLength = len; 01202 DBG("Leaving mallocPayload"); 01203 return _payloadPointer; 01204 } 01205 01206 /// Set the payload to the byte sequence specified. Allocates memory in dynamic PDU if necessary. 01207 /** 01208 * This will set the payload to \b payload. It will allocate memory in the case where the PDU was 01209 * constructed without an external buffer. 01210 * 01211 * This will fail either if the fixed buffer isn't big enough, or if memory could not be allocated 01212 * in the non-external-buffer case. 01213 * 01214 * \param payload Pointer to payload byte sequence. 01215 * \param len Length of payload byte sequence. 01216 * \return 0 on success, 1 on failure. 01217 */ 01218 int CoapPDU::setPayload(uint8_t *payload, int len) { 01219 if(payload==NULL) { 01220 DBG("NULL payload pointer."); 01221 return 1; 01222 } 01223 01224 uint8_t *payloadPointer = mallocPayload(len); 01225 if(payloadPointer==NULL) { 01226 DBG("Allocation of payload failed"); 01227 return 1; 01228 } 01229 01230 // copy payload contents 01231 memcpy(payloadPointer,payload,len); 01232 01233 return 0; 01234 } 01235 01236 /// Returns a pointer to the payload buffer. 01237 uint8_t* CoapPDU::getPayloadPointer() { 01238 return _payloadPointer; 01239 } 01240 01241 /// Gets the length of the payload buffer. 01242 int CoapPDU::getPayloadLength() { 01243 return _payloadLength; 01244 } 01245 01246 /// Returns a pointer to a buffer which is a copy of the payload buffer (dynamically allocated). 01247 uint8_t* CoapPDU::getPayloadCopy() { 01248 if(_payloadLength==0) { 01249 return NULL; 01250 } 01251 01252 // malloc space for copy 01253 uint8_t *payload = (uint8_t*)malloc(_payloadLength); 01254 if(payload==NULL) { 01255 DBG("Unable to allocate memory for payload"); 01256 return NULL; 01257 } 01258 01259 // copy and return 01260 memcpy(payload,_payloadPointer,_payloadLength); 01261 return payload; 01262 } 01263 01264 /// Shorthand for setting the content-format option. 01265 /** 01266 * Sets the content-format to the specified value (adds an option). 01267 * \param format The content format, one of: 01268 * 01269 * - COAP_CONTENT_FORMAT_TEXT_PLAIN 01270 * - COAP_CONTENT_FORMAT_APP_LINK 01271 * - COAP_CONTENT_FORMAT_APP_XML 01272 * - COAP_CONTENT_FORMAT_APP_OCTET 01273 * - COAP_CONTENT_FORMAT_APP_EXI 01274 * - COAP_CONTENT_FORMAT_APP_JSON 01275 * 01276 * \return 0 on success, 1 on failure. 01277 */ 01278 int CoapPDU::setContentFormat(CoapPDU::ContentFormat format) { 01279 if(format==0) { 01280 // minimal representation means null option value 01281 if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,0,NULL)!=0) { 01282 DBG("Error setting content format"); 01283 return 1; 01284 } 01285 return 0; 01286 } 01287 01288 uint8_t c[2]; 01289 01290 // just use 1 byte if can do it 01291 if(format<256) { 01292 c[0] = format; 01293 if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,1,c)!=0) { 01294 DBG("Error setting content format"); 01295 return 1; 01296 } 01297 return 0; 01298 } 01299 01300 uint16_t networkOrder = htons(format); 01301 c[0] &= 0x00; 01302 c[0] |= (networkOrder >> 8); // MSB 01303 c[1] &= 0x00; 01304 c[1] |= (networkOrder & 0x00FF); // LSB 01305 if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,2,c)!=0) { 01306 DBG("Error setting content format"); 01307 return 1; 01308 } 01309 return 0; 01310 } 01311 01312 /// PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE 01313 /// PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE 01314 01315 /// Moves a block of bytes to end of PDU from given offset. 01316 /** 01317 * This moves the block of bytes _pdu[_pduLength-1-shiftOffset-shiftAmount] ... _pdu[_pduLength-1-shiftOffset] 01318 * to the end of the PDU. 01319 * \param shiftOffset End of block to move, relative to end of PDU (-1). 01320 * \param shiftAmount Length of block to move. 01321 */ 01322 void CoapPDU::shiftPDUUp(int shiftOffset, int shiftAmount) { 01323 DBG("shiftOffset: %d, shiftAmount: %d",shiftOffset,shiftAmount); 01324 int destPointer = _pduLength-1; 01325 int srcPointer = destPointer-shiftOffset; 01326 while(shiftAmount--) { 01327 _pdu[destPointer] = _pdu[srcPointer]; 01328 destPointer--; 01329 srcPointer--; 01330 } 01331 } 01332 01333 /// Moves a block of bytes down a specified number of steps. 01334 /** 01335 * Moves the block of bytes _pdu[startLocation+shiftOffset] ... _pdu[startLocation+shiftOffset+shiftAmount] 01336 * down to \b startLocation. 01337 * \param startLocation Index where to shift the block to. 01338 * \param shiftOffset Where the block starts, relative to start index. 01339 * \param shiftAmount Length of block to shift. 01340 */ 01341 void CoapPDU::shiftPDUDown(int startLocation, int shiftOffset, int shiftAmount) { 01342 DBG("startLocation: %d, shiftOffset: %d, shiftAmount: %d",startLocation,shiftOffset,shiftAmount); 01343 int srcPointer = startLocation+shiftOffset; 01344 while(shiftAmount--) { 01345 _pdu[startLocation] = _pdu[srcPointer]; 01346 startLocation++; 01347 srcPointer++; 01348 } 01349 } 01350 01351 /// Gets the payload length of an option. 01352 /** 01353 * \param option Pointer to location of option in PDU. 01354 * \return The 16 bit option-payload length. 01355 */ 01356 uint16_t CoapPDU::getOptionValueLength(uint8_t *option) { 01357 uint16_t delta = (option[0] & 0xF0) >> 4; 01358 uint16_t length = (option[0] & 0x0F); 01359 // no extra bytes 01360 if(length<13) { 01361 return length; 01362 } 01363 01364 // extra bytes skip header 01365 int offset = 1; 01366 // skip extra option delta bytes 01367 if(delta==13) { 01368 offset++; 01369 } else if(delta==14) { 01370 offset+=2; 01371 } 01372 01373 // process length 01374 if(length==13) { 01375 return (option[offset]+13); 01376 } else { 01377 // need to convert to host order 01378 uint16_t networkOrder = 0x0000; 01379 networkOrder |= option[offset++]; 01380 networkOrder <<= 8; 01381 networkOrder |= option[offset]; 01382 uint16_t hostOrder = ntohs(networkOrder); 01383 return hostOrder+269; 01384 } 01385 01386 } 01387 01388 /// Gets the delta of an option. 01389 /** 01390 * \param option Pointer to location of option in PDU. 01391 * \return The 16 bit delta. 01392 */ 01393 uint16_t CoapPDU::getOptionDelta(uint8_t *option) { 01394 uint16_t delta = (option[0] & 0xF0) >> 4; 01395 if(delta<13) { 01396 return delta; 01397 } else if(delta==13) { 01398 // single byte option delta 01399 return (option[1]+13); 01400 } else if(delta==14) { 01401 // double byte option delta 01402 // need to convert to host order 01403 uint16_t networkOrder = 0x0000; 01404 networkOrder |= option[1]; 01405 networkOrder <<= 8; 01406 networkOrder |= option[2]; 01407 uint16_t hostOrder = ntohs(networkOrder); 01408 return hostOrder+269; 01409 } else { 01410 // should only ever occur in payload marker 01411 return delta; 01412 } 01413 } 01414 01415 /// Finds the insertion position in the current list of options for the specified option. 01416 /** 01417 * \param optionNumber The option's number. 01418 * \param prevOptionNumber A pointer to a uint16_t which will store the option number of the option previous 01419 * to the insertion point. 01420 * \return 0 on success, 1 on failure. \b prevOptionNumber will contain the option number of the option 01421 * before the insertion position (for example 0 if no options have been inserted). 01422 */ 01423 int CoapPDU::findInsertionPosition(uint16_t optionNumber, uint16_t *prevOptionNumber) { 01424 // zero this for safety 01425 *prevOptionNumber = 0x00; 01426 01427 DBG("_pduLength: %d",_pduLength); 01428 01429 // if option is bigger than any currently stored, it goes at the end 01430 // this includes the case that no option has yet been added 01431 if( (optionNumber >= _maxAddedOptionNumber) || (_pduLength == (COAP_HDR_SIZE+getTokenLength())) ) { 01432 *prevOptionNumber = _maxAddedOptionNumber; 01433 return _pduLength; 01434 } 01435 01436 // otherwise walk over the options 01437 int optionPos = COAP_HDR_SIZE + getTokenLength(); 01438 uint16_t optionDelta = 0, optionValueLength = 0; 01439 uint16_t currentOptionNumber = 0; 01440 while(optionPos<_pduLength && _pdu[optionPos]!=0xFF) { 01441 optionDelta = getOptionDelta(&_pdu[optionPos]); 01442 currentOptionNumber += optionDelta; 01443 optionValueLength = getOptionValueLength(&_pdu[optionPos]); 01444 // test if this is insertion position 01445 if(currentOptionNumber>optionNumber) { 01446 return optionPos; 01447 } 01448 // keep track of the last valid option number 01449 *prevOptionNumber = currentOptionNumber; 01450 // move onto next option 01451 optionPos += computeExtraBytes(optionDelta); 01452 optionPos += computeExtraBytes(optionValueLength); 01453 optionPos += optionValueLength; 01454 optionPos++; // (for mandatory option header byte) 01455 } 01456 return optionPos; 01457 01458 } 01459 01460 /// CoAP uses a minimal-byte representation for length fields. This returns the number of bytes needed to represent a given length. 01461 int CoapPDU::computeExtraBytes(uint16_t n) { 01462 if(n<13) { 01463 return 0; 01464 } 01465 01466 if(n<269) { 01467 return 1; 01468 } 01469 01470 return 2; 01471 } 01472 01473 /// Set the option delta to the specified value. 01474 /** 01475 * This assumes space has been made for the option delta. 01476 * \param optionPosition The index of the option in the PDU. 01477 * \param optionDelta The option delta value to set. 01478 */ 01479 void CoapPDU::setOptionDelta(int optionPosition, uint16_t optionDelta) { 01480 int headerStart = optionPosition; 01481 // clear the old option delta bytes 01482 _pdu[headerStart] &= 0x0F; 01483 01484 // set the option delta bytes 01485 if(optionDelta<13) { 01486 _pdu[headerStart] |= (optionDelta << 4); 01487 } else if(optionDelta<269) { 01488 // 1 extra byte 01489 _pdu[headerStart] |= 0xD0; // 13 in first nibble 01490 _pdu[++optionPosition] &= 0x00; 01491 _pdu[optionPosition] |= (optionDelta-13); 01492 } else { 01493 // 2 extra bytes, network byte order uint16_t 01494 _pdu[headerStart] |= 0xE0; // 14 in first nibble 01495 optionDelta = htons(optionDelta-269); 01496 _pdu[++optionPosition] &= 0x00; 01497 _pdu[optionPosition] |= (optionDelta >> 8); // MSB 01498 _pdu[++optionPosition] &= 0x00; 01499 _pdu[optionPosition] |= (optionDelta & 0x00FF); // LSB 01500 } 01501 } 01502 01503 /// Insert an option in-memory at the specified location. 01504 /** 01505 * This assumes that there is enough space at the location specified. 01506 * \param insertionPosition Position in the PDU where the option should be placed. 01507 * \param optionDelta The delta value for the option. 01508 * \param optionValueLength The length of the option value. 01509 * \param optionValue A pointer to the sequence of bytes representing the option value. 01510 * \return 0 on success, 1 on failure. 01511 */ 01512 int CoapPDU::insertOption( 01513 int insertionPosition, 01514 uint16_t optionDelta, 01515 uint16_t optionValueLength, 01516 uint8_t *optionValue) { 01517 01518 int headerStart = insertionPosition; 01519 01520 // clear old option header start 01521 _pdu[headerStart] &= 0x00; 01522 01523 // set the option delta bytes 01524 if(optionDelta<13) { 01525 _pdu[headerStart] |= (optionDelta << 4); 01526 } else if(optionDelta<269) { 01527 // 1 extra byte 01528 _pdu[headerStart] |= 0xD0; // 13 in first nibble 01529 _pdu[++insertionPosition] &= 0x00; 01530 _pdu[insertionPosition] |= (optionDelta-13); 01531 } else { 01532 // 2 extra bytes, network byte order uint16_t 01533 _pdu[headerStart] |= 0xE0; // 14 in first nibble 01534 optionDelta = htons(optionDelta-269); 01535 _pdu[++insertionPosition] &= 0x00; 01536 _pdu[insertionPosition] |= (optionDelta >> 8); // MSB 01537 _pdu[++insertionPosition] &= 0x00; 01538 _pdu[insertionPosition] |= (optionDelta & 0x00FF); // LSB 01539 } 01540 01541 // set the option value length bytes 01542 if(optionValueLength<13) { 01543 _pdu[headerStart] |= (optionValueLength & 0x000F); 01544 } else if(optionValueLength<269) { 01545 _pdu[headerStart] |= 0x0D; // 13 in second nibble 01546 _pdu[++insertionPosition] &= 0x00; 01547 _pdu[insertionPosition] |= (optionValueLength-13); 01548 } else { 01549 _pdu[headerStart] |= 0x0E; // 14 in second nibble 01550 // this is in network byte order 01551 DBG("optionValueLength: %u",optionValueLength); 01552 uint16_t networkOrder = htons(optionValueLength-269); 01553 _pdu[++insertionPosition] &= 0x00; 01554 _pdu[insertionPosition] |= (networkOrder >> 8); // MSB 01555 _pdu[++insertionPosition] &= 0x00; 01556 _pdu[insertionPosition] |= (networkOrder & 0x00FF); // LSB 01557 } 01558 01559 // and finally copy the option value itself 01560 memcpy(&_pdu[++insertionPosition],optionValue,optionValueLength); 01561 01562 return 0; 01563 } 01564 01565 // DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG 01566 // DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG 01567 01568 /// Prints the PDU in human-readable format. 01569 void CoapPDU::printHuman() { 01570 INFOX("__________________\r\n"); 01571 if(_constructedFromBuffer) { 01572 INFOX("PDU was constructed from buffer of %d bytes\r\n",_bufferLength); 01573 } 01574 INFOX("PDU is %d bytes long\r\n",_pduLength); 01575 INFOX("CoAP Version: %d\r\n",getVersion()); 01576 INFOX("Message Type: "); 01577 switch(getType()) { 01578 case COAP_CONFIRMABLE: 01579 INFOX("Confirmable\r\n"); 01580 break; 01581 01582 case COAP_NON_CONFIRMABLE: 01583 INFOX("Non-Confirmable\r\n"); 01584 break; 01585 01586 case COAP_ACKNOWLEDGEMENT: 01587 INFOX("Acknowledgement\r\n"); 01588 break; 01589 01590 case COAP_RESET: 01591 INFOX("Reset\r\n"); 01592 break; 01593 } 01594 INFOX("Token length: %d\r\n",getTokenLength()); 01595 INFOX("Code: "); 01596 switch(getCode()) { 01597 case COAP_EMPTY: 01598 INFOX("0.00 Empty"); 01599 break; 01600 case COAP_GET: 01601 INFOX("0.01 GET"); 01602 break; 01603 case COAP_POST: 01604 INFOX("0.02 POST"); 01605 break; 01606 case COAP_PUT: 01607 INFOX("0.03 PUT"); 01608 break; 01609 case COAP_DELETE: 01610 INFOX("0.04 DELETE"); 01611 break; 01612 case COAP_CREATED: 01613 INFOX("2.01 Created"); 01614 break; 01615 case COAP_DELETED: 01616 INFOX("2.02 Deleted"); 01617 break; 01618 case COAP_VALID: 01619 INFOX("2.03 Valid"); 01620 break; 01621 case COAP_CHANGED: 01622 INFOX("2.04 Changed"); 01623 break; 01624 case COAP_CONTENT: 01625 INFOX("2.05 Content"); 01626 break; 01627 case COAP_BAD_REQUEST: 01628 INFOX("4.00 Bad Request"); 01629 break; 01630 case COAP_UNAUTHORIZED: 01631 INFOX("4.01 Unauthorized"); 01632 break; 01633 case COAP_BAD_OPTION: 01634 INFOX("4.02 Bad Option"); 01635 break; 01636 case COAP_FORBIDDEN: 01637 INFOX("4.03 Forbidden"); 01638 break; 01639 case COAP_NOT_FOUND: 01640 INFOX("4.04 Not Found"); 01641 break; 01642 case COAP_METHOD_NOT_ALLOWED: 01643 INFOX("4.05 Method Not Allowed"); 01644 break; 01645 case COAP_NOT_ACCEPTABLE: 01646 INFOX("4.06 Not Acceptable"); 01647 break; 01648 case COAP_PRECONDITION_FAILED: 01649 INFOX("4.12 Precondition Failed"); 01650 break; 01651 case COAP_REQUEST_ENTITY_TOO_LARGE: 01652 INFOX("4.13 Request Entity Too Large"); 01653 break; 01654 case COAP_UNSUPPORTED_CONTENT_FORMAT: 01655 INFOX("4.15 Unsupported Content-Format"); 01656 break; 01657 case COAP_INTERNAL_SERVER_ERROR: 01658 INFOX("5.00 Internal Server Error"); 01659 break; 01660 case COAP_NOT_IMPLEMENTED: 01661 INFOX("5.01 Not Implemented"); 01662 break; 01663 case COAP_BAD_GATEWAY: 01664 INFOX("5.02 Bad Gateway"); 01665 break; 01666 case COAP_SERVICE_UNAVAILABLE: 01667 INFOX("5.03 Service Unavailable"); 01668 break; 01669 case COAP_GATEWAY_TIMEOUT: 01670 INFOX("5.04 Gateway Timeout"); 01671 break; 01672 case COAP_PROXYING_NOT_SUPPORTED: 01673 INFOX("5.05 Proxying Not Supported"); 01674 break; 01675 case COAP_UNDEFINED_CODE: 01676 INFOX("Undefined Code"); 01677 break; 01678 } 01679 INFOX("\r\n"); 01680 01681 // print message ID 01682 INFOX("Message ID: %u\r\n",getMessageID()); 01683 01684 // print token value 01685 int tokenLength = getTokenLength(); 01686 uint8_t *tokenPointer = getPDUPointer()+COAP_HDR_SIZE; 01687 if(tokenLength==0) { 01688 INFOX("No token.\r\n"); 01689 } else { 01690 INFOX("Token of %d bytes.\r\n",tokenLength); 01691 INFOX(" Value: 0x"); 01692 for(int j=0; j<tokenLength; j++) { 01693 INFOX("%.2x",tokenPointer[j]); 01694 } 01695 INFOX("\r\n"); 01696 } 01697 01698 // print options 01699 CoapPDU::CoapOption* options = getOptions(); 01700 INFOX("%d options:\r\n",_numOptions); 01701 for(int i=0; i<_numOptions; i++) { 01702 INFOX("OPTION (%d/%d)\r\n",i,_numOptions); 01703 INFOX(" Option number (delta): %hu (%hu)\r\n",options[i].optionNumber,options[i].optionDelta); 01704 INFOX(" Name: "); 01705 switch(options[i].optionNumber) { 01706 case COAP_OPTION_IF_MATCH: 01707 INFOX("IF_MATCH"); 01708 break; 01709 case COAP_OPTION_URI_HOST: 01710 INFOX("URI_HOST"); 01711 break; 01712 case COAP_OPTION_ETAG: 01713 INFOX("ETAG"); 01714 break; 01715 case COAP_OPTION_IF_NONE_MATCH: 01716 INFOX("IF_NONE_MATCH"); 01717 break; 01718 case COAP_OPTION_OBSERVE: 01719 INFOX("OBSERVE"); 01720 break; 01721 case COAP_OPTION_URI_PORT: 01722 INFOX("URI_PORT"); 01723 break; 01724 case COAP_OPTION_LOCATION_PATH: 01725 INFOX("LOCATION_PATH"); 01726 break; 01727 case COAP_OPTION_URI_PATH: 01728 INFOX("URI_PATH"); 01729 break; 01730 case COAP_OPTION_CONTENT_FORMAT: 01731 INFOX("CONTENT_FORMAT"); 01732 break; 01733 case COAP_OPTION_MAX_AGE: 01734 INFOX("MAX_AGE"); 01735 break; 01736 case COAP_OPTION_URI_QUERY: 01737 INFOX("URI_QUERY"); 01738 break; 01739 case COAP_OPTION_ACCEPT: 01740 INFOX("ACCEPT"); 01741 break; 01742 case COAP_OPTION_LOCATION_QUERY: 01743 INFOX("LOCATION_QUERY"); 01744 break; 01745 case COAP_OPTION_PROXY_URI: 01746 INFOX("PROXY_URI"); 01747 break; 01748 case COAP_OPTION_PROXY_SCHEME: 01749 INFOX("PROXY_SCHEME"); 01750 break; 01751 case COAP_OPTION_BLOCK1: 01752 INFOX("BLOCK1"); 01753 break; 01754 case COAP_OPTION_BLOCK2: 01755 INFOX("BLOCK2"); 01756 break; 01757 case COAP_OPTION_SIZE1: 01758 INFOX("SIZE1"); 01759 break; 01760 case COAP_OPTION_SIZE2: 01761 INFOX("SIZE2"); 01762 break; 01763 default: 01764 INFOX("Unknown option"); 01765 break; 01766 } 01767 INFOX("\r\n"); 01768 INFOX(" Value length: %u\r\n",options[i].optionValueLength); 01769 INFOX(" Value: \""); 01770 for(int j=0; j<options[i].optionValueLength; j++) { 01771 char c = options[i].optionValuePointer[j]; 01772 if((c>='!'&&c<='~')||c==' ') { 01773 INFOX("%c",c); 01774 } else { 01775 INFOX("\\%.2d",c); 01776 } 01777 } 01778 INFOX("\"\r\n"); 01779 } 01780 01781 // print payload 01782 if(_payloadLength==0) { 01783 INFOX("No payload.\r\n"); 01784 } else { 01785 INFOX("Payload of %d bytes\r\n",_payloadLength); 01786 INFOX(" Value: \""); 01787 for(int j=0; j<_payloadLength; j++) { 01788 char c = _payloadPointer[j]; 01789 if((c>='!'&&c<='~')||c==' ') { 01790 INFOX("%c",c); 01791 } else { 01792 INFOX("\\%.2x",c); 01793 } 01794 } 01795 INFO("\"\r\n"); 01796 } 01797 INFOX("__________________\r\n"); 01798 } 01799 01800 /// Prints the PDU as a c array (useful for debugging or hardcoding PDUs) 01801 void CoapPDU::printPDUAsCArray() { 01802 printf("const uint8_t array[] = {\r\n "); 01803 for(int i=0; i<_pduLength; i++) { 01804 printf("0x%.2x, ",_pdu[i]); 01805 } 01806 printf("\r\n};\r\n"); 01807 } 01808 01809 /// A routine for printing an option in human-readable format. 01810 /** 01811 * \param option This is a pointer to where the option begins in the PDU. 01812 */ 01813 void CoapPDU::printOptionHuman(uint8_t *option) { 01814 // compute some useful stuff 01815 uint16_t optionDelta = getOptionDelta(option); 01816 uint16_t optionValueLength = getOptionValueLength(option); 01817 int extraDeltaBytes = computeExtraBytes(optionDelta); 01818 int extraValueLengthBytes = computeExtraBytes(optionValueLength); 01819 int totalLength = 1+extraDeltaBytes+extraValueLengthBytes+optionValueLength; 01820 01821 if(totalLength>_pduLength) { 01822 totalLength = &_pdu[_pduLength-1]-option; 01823 DBG("New length: %u",totalLength); 01824 } 01825 01826 // print summary 01827 DBG("~~~~~~ Option ~~~~~~"); 01828 DBG("Delta: %u, Value length: %u",optionDelta,optionValueLength); 01829 01830 // print all bytes 01831 DBG("All bytes (%d):",totalLength); 01832 for(int i=0; i<totalLength; i++) { 01833 if(i%4==0) { 01834 DBG(" "); 01835 DBGX(" %.2d ",i); 01836 } 01837 CoapPDU::printBinary(option[i]); DBGX(" "); 01838 } 01839 DBG(" "); DBG(" "); 01840 01841 // print header byte 01842 DBG("Header byte:"); 01843 DBGX(" "); 01844 CoapPDU::printBinary(*option++); 01845 DBG(" "); DBG(" "); 01846 01847 // print extended delta bytes 01848 if(extraDeltaBytes) { 01849 DBG("Extended delta bytes (%d) in network order: ",extraDeltaBytes); 01850 DBGX(" "); 01851 while(extraDeltaBytes--) { 01852 CoapPDU::printBinary(*option++); DBGX(" "); 01853 } 01854 } else { 01855 DBG("No extended delta bytes"); 01856 } 01857 DBG(" "); DBG(" "); 01858 01859 // print extended value length bytes 01860 if(extraValueLengthBytes) { 01861 DBG("Extended value length bytes (%d) in network order: ",extraValueLengthBytes); 01862 DBGX(" "); 01863 while(extraValueLengthBytes--) { 01864 CoapPDU::printBinary(*option++); DBGX(" "); 01865 } 01866 } else { 01867 DBG("No extended value length bytes"); 01868 } 01869 DBG(" "); 01870 01871 // print option value 01872 DBG("Option value bytes:"); 01873 for(int i=0; i<optionValueLength; i++) { 01874 if(i%4==0) { 01875 DBG(" "); 01876 DBGX(" %.2d ",i); 01877 } 01878 CoapPDU::printBinary(*option++); 01879 DBGX(" "); 01880 } 01881 DBG(" "); 01882 } 01883 01884 /// Dumps the PDU header in hex. 01885 void CoapPDU::printHex() { 01886 printf("Hexdump dump of PDU\r\n"); 01887 printf("%.2x %.2x %.2x %.2x",_pdu[0],_pdu[1],_pdu[2],_pdu[3]); 01888 } 01889 01890 /// Dumps the entire PDU in binary. 01891 void CoapPDU::printBin() { 01892 for(int i=0; i<_pduLength; i++) { 01893 if(i%4==0) { 01894 printf("\r\n"); 01895 printf("%.2d ",i); 01896 } 01897 CoapPDU::printBinary(_pdu[i]); printf(" "); 01898 } 01899 printf("\r\n"); 01900 } 01901 01902 /// Prints a single byte in binary. 01903 void CoapPDU::printBinary(uint8_t b) { 01904 printf("%d%d%d%d%d%d%d%d", 01905 (b&0x80)&&0x01, 01906 (b&0x40)&&0x01, 01907 (b&0x20)&&0x01, 01908 (b&0x10)&&0x01, 01909 (b&0x08)&&0x01, 01910 (b&0x04)&&0x01, 01911 (b&0x02)&&0x01, 01912 (b&0x01)&&0x01); 01913 } 01914 01915 /// Dumps the PDU as a byte sequence to stdout. 01916 void CoapPDU::print() { 01917 fwrite(_pdu,1,_pduLength,stdout); 01918 }
Generated on Wed Jul 13 2022 03:00:56 by
1.7.2
