This is CoAP library with a focus on simplicity. It offers minimal CoAP PDU construction and decoding to and from byte buffers.

Dependents:   cantcoap_cellular_test yeswecancoap

Teaser

CoAP implementation that focuses on simplicity by offering a minimal set of functions and straightforward interface.

	CoapPDU *pdu = new CoapPDU();
	pdu->setType(CoapPDU::COAP_CONFIRMABLE);
	pdu->setCode(CoapPDU::COAP_GET);
	pdu->setToken((uint8_t*)"\3\2\1\0",4);
	pdu->setMessageID(0x0005);
	pdu->setURI((char*)"test",4);

	// send packet 
	ret = send(sockfd,pdu->getPDUPointer(),pdu->getPDULength(),0);

...

	// receive packet
	ret = recvfrom(sockfd,&buffer,BUF_LEN,0,(sockaddr*)&recvAddr,&recvAddrLen);
	CoapPDU *recvPDU = new CoapPDU((uint8_t*)buffer,ret);
	if(recvPDU->validate()) {
		recvPDU->getURI(uriBuffer,URI_BUF_LEN,&recvURILen);
		...
	}

Long description

This is a CoAP implementation with a focus on simplicity. The library only provides PDU construction and de-construction.

The user is expected to deal with retransmissions, timeouts, and message ID matching themselves. This isn’t as arduous as it sounds and makes a lot more sense on a constrained device.

Imagine for example a simple microcontroller sensor that only reports readings once every 15 minutes, and only sends a few packets each time. Do you really need a complicated framework to deal with acknowledgements and re-transmissions?

Since CoAP recommends you only send one packet at at time, this means you only need to keep track of one on-going transaction at a time. Yeah... I think you’re capable of this.

Furthermore, the timers and interrupt processes between different embedded processor architectures, vary quite a bit. So it often makes sense to write the packet sending processes yourself.

Finally, you might be sending the packets over odd transport bearers such as a SMS (woah dude, that's just totally wild) or a simple radio bearer. In which case, it’s easiest to deal with buffers. If I built retransmission handlers, they’d all be UDP/IP specific and would bloat the code for no reason.

Resources

Github page for the cantcoap library is here:

https://github.com/staropram/cantcoap

Doxygen for the library is here:

http://staropram.github.io/cantcoap/index.html

Examples

Construction

There are a couple of different ways to construct a PDU depending on whether you want the library to allocate memory for you, or whether you have an external buffer you want to use. You can also re-purpose existing objects.

Using a managed object

The simplest usage scenario hands control of memory allocation to the library:

CoapPDU *pdu = new CoapPDU();
...
pdu->setType(CoapPDU::COAP_CONFIRMABLE);
pdu->setCode(CoapPDU::COAP_GET);
pdu->addOption(11,5,(uint8_t*)"hello");
pdu->addOption(11,5,(uint8_t*)"there");
pdu->addOption(11,6,(uint8_t*)"server");

In this case you just call the default constructor. That's it. The library handles memory from there-on out. For example, when adding each of those options, the library will realloc the pdu to accomodate space for them. It will also shrink the PDU if something changes (like the token length) so that it always uses the minimum amount of memory.

When you free the PDU, all data including the buffer is deleted. The PDU can also be reused as shown below.

Using an external buffer for memory

There are two obvious reasons why you would do this:

1. The buffer contains a CoAP PDU and you want to access the data in the PDU. 2. Buffers cost space and allocating memory consumes processor resources. On embedded targets it is often simpler to reuse buffers where possible.

The first instance is a special case and requires some extra work. Just using an external buffer is as simple as follows:

uint8_t *buffer[100];
CoapPDU *pdu = new CoapPDU((uint8_t*)buffer,100,0);
...
pdu->setType(CoapPDU::COAP_CONFIRMABLE);
pdu->setCode(CoapPDU::COAP_GET);
pdu->addOption(11,5,(uint8_t*)"hello");
pdu->addOption(11,5,(uint8_t*)"there");
pdu->addOption(11,6,(uint8_t*)"server");

The PDU is constructed as normal except that the memory of your buffer is used instead of allocated memory.

A call such as this:

pdu->addOption(11,5,(uint8_t*)"hello");

Will fail if there is no space left in the buffer.

When you delete the object, the buffer is not freed. Hey, it's your buffer mannn!

Reusing an existing object

Regardless of whether you constructed a PDU using either of the above methods, you can always reuse it:

pdu->reset(); 
...
pdu->setType(CoapPDU::COAP_CONFIRMABLE);
pdu->setCode(CoapPDU::COAP_GET);
pdu->addOption(11,5,(uint8_t*)"hello");
pdu->addOption(11,5,(uint8_t*)"there");
pdu->addOption(11,6,(uint8_t*)"server");

The only difference is that if the PDU was initially constructed using managed-memory, then it will continue to have managed-memory. Whereas if the PDU was constructed with an external buffer, then you are limited in space by the size of the buffer you used.

Receving CoAP packets over a network or something

In this case you have a CoAP PDU in a buffer you just gobbled from a socket and want to read it:

uint8_t *buffer[100];
int ret = recvfrom(sockfd,&buffer,BUF_LEN,0,(sockaddr*)&recvAddr,&recvAddrLen);
CoapPDU *recvPDU = new CoapPDU((uint8_t*)buffer,ret,100);
if(recvPDU->validate()) {
	recvPDU->printHuman();
	// do your work
}

You must call CoapPDU::validate() and get a positive response before accessing any of the data members. This sets up some internal pionters and so on, so if you fail to do it, undefined behaviour will result.

Note that the constructor is just a shorthand for the external-buffer-constructor explained above, and you can use the long form if you want. For example. you might want to use the long form if you have a buffer bigger than the PDU and you expect to reuse it.

You can reuse this object by resetting it as above.

If you reuse such an object, you need to set the PDU length manually because there is no way to deduce the PDU length using validate():

	// earlier
	#define BUFLEN 500
	char buffer[BUFLEN];
	CoapPDU *recvPDU = new CoapPDU((uint8_t*)buffer,BUFLEN,BUFLEN);

	...

	while(1) {
		// receive packet
		ret = sockfd,&buffer,BUFLEN,0);
		if(ret==-1) {
			INFO("Error receiving data");
			// handle error
		}

		// validate packet
		// you should also check that ret doesn't exceed buffer length
		recvPDU->setPDULength(ret);
		if(recvPDU->validate()!=1) {
			INFO("Malformed CoAP packet");
			// handle error
		}
	}
Committer:
ashleymills
Date:
Thu Jan 30 14:07:56 2014 +0000
Revision:
1:5eec2844ad47
Parent:
0:3d62a105fd34
Updated to sync with github version.

Who changed what in which revision?

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