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