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