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