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

Fork of cantcoap by Ashley Mills

Files at this revision

API Documentation at this revision

Comitter:
ashleymills
Date:
Thu Jan 30 14:07:56 2014 +0000
Parent:
0:3d62a105fd34
Child:
2:1544f4758e0a
Commit message:
Updated to sync with github version.

Changed in this revision

cantcoap.cpp Show annotated file Show diff for this revision Revisions of this file
cantcoap.h Show annotated file Show diff for this revision Revisions of this file
--- a/cantcoap.cpp	Tue Oct 08 14:36:01 2013 +0000
+++ b/cantcoap.cpp	Thu Jan 30 14:07:56 2014 +0000
@@ -36,12 +36,26 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
+#include <inet.h>
 #include "cantcoap.h"
-#ifndef MBED
-#include "arpa/inet.h"
-#include "netdb.h"
+
+// for debugging output you need https://mbed.org/users/donatien/code/DebugLib/
+#define __DEBUG__ 3 // INFO
+#ifndef __MODULE__
+   #define __MODULE__ "cantcoap.cpp"
+#endif
+#include "dbg.h"
+// some extra debug stuff
+#if __DEBUG__ > 0
+   #define INFOX(...)  do { fprintf(stderr,__VA_ARGS__); } while(0)
+   #define INFOLX(...) do { fprintf(stderr,"[INFO] %s:%d ",__MODULE__,__LINE__); fprintf(stderr,__VA_ARGS__); } while(0) 
+   #define DBGLX(...)  do { fprintf(stderr,"[DBG] %s:%d ",__MODULE__,__LINE__); fprintf(stderr,__VA_ARGS__); } while(0)
+   #define DBG_PDU()   do { printBin(); } while(0)
 #else
-#include "bsd_socket.h"
+   #define INFOX(...)  do{} while(0)
+   #define INFOLX(...) do{} while(0)
+   #define DBGLX(...)  do{} while(0)
+   #define DBG_PDU()   do{} while(0)
 #endif
 
 
@@ -108,11 +122,25 @@
  * \sa CoapPDU::CoapPDU(), CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)
  */
 CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) {
+    int bufferLength = pduLength;
+    // sanity
+	if(pduLength<4&&pduLength!=0) {
+		DBG("PDU cannot have a length less than 4");
+	}
+
 	// pdu
 	_pdu = pdu;
-	_bufferLength = pduLength;
-	_pduLength = pduLength;
-	
+	_bufferLength = bufferLength;
+	if(pduLength==0) {
+		// this is actually a fresh pdu, header always exists
+		_pduLength = 4;
+		// make sure header is zeroed
+		_pdu[0] = 0x00; _pdu[1] = 0x00; _pdu[2] = 0x00; _pdu[3] = 0x00;
+		setVersion(1);
+	} else {
+		_pduLength = pduLength;
+	}
+
 	_constructedFromBuffer = 1;
 
 	// options
@@ -419,6 +447,13 @@
 	_pduLength = len;
 }
 
+/// Shorthand function for setting a resource URI.
+/**
+ * Calls CoapPDU::setURI(uri,strlen(uri).
+ */
+int CoapPDU::setURI(char *uri) {
+	return setURI(uri,strlen(uri));
+}
 
 /// Shorthand function for setting a resource URI.
 /**
@@ -513,10 +548,21 @@
 	free(uriBuf);
 	return 0;
 }
+/// Shorthand for adding a URI QUERY to the option list.
+/**
+ * Adds a new option to the CoAP PDU that encodes a URI_QUERY.
+ *
+ * \param query The uri query to encode.
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::addURIQuery(char *query) {
+	return addOption(COAP_OPTION_URI_QUERY,strlen(query),(uint8_t*)query);
+}
 
 /// Concatenates any URI_PATH elements into a single string.
 /**
  * Parses the PDU options and extracts all URI_PATH elements, concatenating them into a single string with slash separators.
+ * The produced string will be null terminated.
  * 
  * \param dst Buffer into which to copy the concatenated path elements.
  * \param dstlen Length of buffer.
@@ -785,6 +831,71 @@
 CoapPDU::Code CoapPDU::getCode() {
 	return (CoapPDU::Code)_pdu[1];
 }
+
+
+/// Converts a http status code as an integer, to a CoAP code.
+/**
+ * \param httpStatus the HTTP status code as an integer (e.g 200)
+ * \return The correct corresponding CoapPDU::Code on success,
+ * CoapPDU::COAP_UNDEFINED_CODE on failure.
+ */
+CoapPDU::Code CoapPDU::httpStatusToCode(int httpStatus) {
+	switch(httpStatus) {
+		case 1:
+			return CoapPDU::COAP_GET;
+		case 2:
+			return CoapPDU::COAP_POST;
+		case 3:
+			return CoapPDU::COAP_PUT;
+		case 4:
+			return CoapPDU::COAP_DELETE;
+		case 201:
+			return CoapPDU::COAP_CREATED;
+		case 202:
+			return CoapPDU::COAP_DELETED;
+		case 203:
+			return CoapPDU::COAP_VALID;
+		case 204:
+			return CoapPDU::COAP_CHANGED;
+		case 205:
+			return CoapPDU::COAP_CONTENT;
+		case 400:
+			return CoapPDU::COAP_BAD_REQUEST;
+		case 401:
+			return CoapPDU::COAP_UNAUTHORIZED;
+		case 402:
+			return CoapPDU::COAP_BAD_OPTION;
+		case 403:
+			return CoapPDU::COAP_FORBIDDEN;
+		case 404:
+			return CoapPDU::COAP_NOT_FOUND;
+		case 405:
+			return CoapPDU::COAP_METHOD_NOT_ALLOWED;
+		case 406:
+			return CoapPDU::COAP_NOT_ACCEPTABLE;
+		case 412:
+			return CoapPDU::COAP_PRECONDITION_FAILED;
+		case 413:
+			return CoapPDU::COAP_REQUEST_ENTITY_TOO_LARGE;
+		case 415:
+			return CoapPDU::COAP_UNSUPPORTED_CONTENT_FORMAT;
+		case 500:
+			return CoapPDU::COAP_INTERNAL_SERVER_ERROR;
+		case 501:
+			return CoapPDU::COAP_NOT_IMPLEMENTED;
+		case 502:
+			return CoapPDU::COAP_BAD_GATEWAY;
+		case 503:
+			return CoapPDU::COAP_SERVICE_UNAVAILABLE;
+		case 504:
+			return CoapPDU::COAP_GATEWAY_TIMEOUT;
+		case 505:
+			return CoapPDU::COAP_PROXYING_NOT_SUPPORTED;
+		default:
+			return CoapPDU::COAP_UNDEFINED_CODE;
+	}
+}
+
 /// Set messageID to the supplied value.
 /**
  * \param messageID A 16bit message id.
@@ -1452,200 +1563,205 @@
 
 /// Prints the PDU in human-readable format.
 void CoapPDU::printHuman() {
-	INFO("__________________");
+	INFOX("__________________\r\n");
 	if(_constructedFromBuffer) {
-		INFO("PDU was constructed from buffer of %d bytes",_bufferLength);
+		INFOX("PDU was constructed from buffer of %d bytes\r\n",_bufferLength);
 	}
-	INFO("PDU is %d bytes long",_pduLength);
-	INFO("CoAP Version: %d",getVersion());
+	INFOX("PDU is %d bytes long\r\n",_pduLength);
+	INFOX("CoAP Version: %d\r\n",getVersion());
 	INFOX("Message Type: ");
 	switch(getType()) {
 		case COAP_CONFIRMABLE:
-			INFO("Confirmable");
+			INFOX("Confirmable\r\n");
 		break;
 
 		case COAP_NON_CONFIRMABLE:
-			INFO("Non-Confirmable");
+			INFOX("Non-Confirmable\r\n");
 		break;
 
 		case COAP_ACKNOWLEDGEMENT:
-			INFO("Acknowledgement");
+			INFOX("Acknowledgement\r\n");
 		break;
 
 		case COAP_RESET:
-			INFO("Reset");
+			INFOX("Reset\r\n");
 		break;
 	}
-	INFO("Token length: %d",getTokenLength());
+	INFOX("Token length: %d\r\n",getTokenLength());
 	INFOX("Code: ");
 	switch(getCode()) {
 		case COAP_EMPTY:
-			INFO("0.00 Empty");
+			INFOX("0.00 Empty");
 		break;
 		case COAP_GET:
-			INFO("0.01 GET");
+			INFOX("0.01 GET");
 		break;
 		case COAP_POST:
-			INFO("0.02 POST");
+			INFOX("0.02 POST");
 		break;
 		case COAP_PUT:
-			INFO("0.03 PUT");
+			INFOX("0.03 PUT");
 		break;
 		case COAP_DELETE:
-			INFO("0.04 DELETE");
+			INFOX("0.04 DELETE");
 		break;
 		case COAP_CREATED:
-			INFO("2.01 Created");
+			INFOX("2.01 Created");
 		break;
 		case COAP_DELETED:
-			INFO("2.02 Deleted");
+			INFOX("2.02 Deleted");
 		break;
 		case COAP_VALID:
-			INFO("2.03 Valid");
+			INFOX("2.03 Valid");
 		break;
 		case COAP_CHANGED:
-			INFO("2.04 Changed");
+			INFOX("2.04 Changed");
 		break;
 		case COAP_CONTENT:
-			INFO("2.05 Content");
+			INFOX("2.05 Content");
 		break;
 		case COAP_BAD_REQUEST:
-			INFO("4.00 Bad Request");
+			INFOX("4.00 Bad Request");
 		break;
 		case COAP_UNAUTHORIZED:
-			INFO("4.01 Unauthorized");
+			INFOX("4.01 Unauthorized");
 		break;
 		case COAP_BAD_OPTION:
-			INFO("4.02 Bad Option");
+			INFOX("4.02 Bad Option");
 		break;
 		case COAP_FORBIDDEN:
-			INFO("4.03 Forbidden");
+			INFOX("4.03 Forbidden");
 		break;
 		case COAP_NOT_FOUND:
-			INFO("4.04 Not Found");
+			INFOX("4.04 Not Found");
 		break;
 		case COAP_METHOD_NOT_ALLOWED:
-			INFO("4.05 Method Not Allowed");
+			INFOX("4.05 Method Not Allowed");
 		break;
 		case COAP_NOT_ACCEPTABLE:
-			INFO("4.06 Not Acceptable");
+			INFOX("4.06 Not Acceptable");
 		break;
 		case COAP_PRECONDITION_FAILED:
-			INFO("4.12 Precondition Failed");
+			INFOX("4.12 Precondition Failed");
 		break;
 		case COAP_REQUEST_ENTITY_TOO_LARGE:
-			INFO("4.13 Request Entity Too Large");
+			INFOX("4.13 Request Entity Too Large");
 		break;
 		case COAP_UNSUPPORTED_CONTENT_FORMAT:
-			INFO("4.15 Unsupported Content-Format");
+			INFOX("4.15 Unsupported Content-Format");
 		break;
 		case COAP_INTERNAL_SERVER_ERROR:
-			INFO("5.00 Internal Server Error");
+			INFOX("5.00 Internal Server Error");
 		break;
 		case COAP_NOT_IMPLEMENTED:
-			INFO("5.01 Not Implemented");
+			INFOX("5.01 Not Implemented");
 		break;
 		case COAP_BAD_GATEWAY:
-			INFO("5.02 Bad Gateway");
+			INFOX("5.02 Bad Gateway");
 		break;
 		case COAP_SERVICE_UNAVAILABLE:
-			INFO("5.03 Service Unavailable");
+			INFOX("5.03 Service Unavailable");
 		break;
 		case COAP_GATEWAY_TIMEOUT:
-			INFO("5.04 Gateway Timeout");
+			INFOX("5.04 Gateway Timeout");
 		break;
 		case COAP_PROXYING_NOT_SUPPORTED:
-			INFO("5.05 Proxying Not Supported");
+			INFOX("5.05 Proxying Not Supported");
+		break;
+		case COAP_UNDEFINED_CODE:
+			INFOX("Undefined Code");
 		break;
 	}
+	INFOX("\r\n");
 
 	// print message ID
-	INFO("Message ID: %u",getMessageID());
+	INFOX("Message ID: %u\r\n",getMessageID());
 
 	// print token value
 	int tokenLength = getTokenLength();
 	uint8_t *tokenPointer = getPDUPointer()+COAP_HDR_SIZE;
 	if(tokenLength==0) {
-		INFO("No token.");
+		INFOX("No token.\r\n");
 	} else {
-		INFO("Token of %d bytes.",tokenLength);
+		INFOX("Token of %d bytes.\r\n",tokenLength);
 		INFOX("   Value: 0x");
 		for(int j=0; j<tokenLength; j++) {
 			INFOX("%.2x",tokenPointer[j]);
 		}
-		INFO(" ");
+		INFOX("\r\n");
 	}
 
 	// print options
 	CoapPDU::CoapOption* options = getOptions();
-	INFO("%d options:",_numOptions);
+	INFOX("%d options:\r\n",_numOptions);
 	for(int i=0; i<_numOptions; i++) {
-		INFO("OPTION (%d/%d)",i,_numOptions);
-		INFO("   Option number (delta): %hu (%hu)",options[i].optionNumber,options[i].optionDelta);
+		INFOX("OPTION (%d/%d)\r\n",i,_numOptions);
+		INFOX("   Option number (delta): %hu (%hu)\r\n",options[i].optionNumber,options[i].optionDelta);
 		INFOX("   Name: ");
 		switch(options[i].optionNumber) {
 			case COAP_OPTION_IF_MATCH:
-				INFO("IF_MATCH");
+				INFOX("IF_MATCH");
 			break;
 			case COAP_OPTION_URI_HOST:
-				INFO("URI_HOST");
+				INFOX("URI_HOST");
 			break;
 			case COAP_OPTION_ETAG:
-				INFO("ETAG");
+				INFOX("ETAG");
 			break;
 			case COAP_OPTION_IF_NONE_MATCH:
-				INFO("IF_NONE_MATCH");
+				INFOX("IF_NONE_MATCH");
 			break;
 			case COAP_OPTION_OBSERVE:
-				INFO("OBSERVE");
+				INFOX("OBSERVE");
 			break;
 			case COAP_OPTION_URI_PORT:
-				INFO("URI_PORT");
+				INFOX("URI_PORT");
 			break;
 			case COAP_OPTION_LOCATION_PATH:
-				INFO("LOCATION_PATH");
+				INFOX("LOCATION_PATH");
 			break;
 			case COAP_OPTION_URI_PATH:
-				INFO("URI_PATH");
+				INFOX("URI_PATH");
 			break;
 			case COAP_OPTION_CONTENT_FORMAT:
-				INFO("CONTENT_FORMAT");
+				INFOX("CONTENT_FORMAT");
 			break;
 			case COAP_OPTION_MAX_AGE:
-				INFO("MAX_AGE");
+				INFOX("MAX_AGE");
 			break;
 			case COAP_OPTION_URI_QUERY:
-				INFO("URI_QUERY");
+				INFOX("URI_QUERY");
 			break;
 			case COAP_OPTION_ACCEPT:
-				INFO("ACCEPT");
+				INFOX("ACCEPT");
 			break;
 			case COAP_OPTION_LOCATION_QUERY:
-				INFO("LOCATION_QUERY");
+				INFOX("LOCATION_QUERY");
 			break;
 			case COAP_OPTION_PROXY_URI:
-				INFO("PROXY_URI");
+				INFOX("PROXY_URI");
 			break;
 			case COAP_OPTION_PROXY_SCHEME:
-				INFO("PROXY_SCHEME");
+				INFOX("PROXY_SCHEME");
 			break;
 			case COAP_OPTION_BLOCK1:
-				INFO("BLOCK1");
+				INFOX("BLOCK1");
 			break;
 			case COAP_OPTION_BLOCK2:
-				INFO("BLOCK2");
+				INFOX("BLOCK2");
 			break;
 			case COAP_OPTION_SIZE1:
-				INFO("SIZE1");
+				INFOX("SIZE1");
 			break;
 			case COAP_OPTION_SIZE2:
-				INFO("SIZE2");
+				INFOX("SIZE2");
 			break;
 			default:
-				INFO("Unknown option");
+				INFOX("Unknown option");
 			break;
 		}
-		INFO("   Value length: %u",options[i].optionValueLength);
+		INFOX("\r\n");
+		INFOX("   Value length: %u\r\n",options[i].optionValueLength);
 		INFOX("   Value: \"");
 		for(int j=0; j<options[i].optionValueLength; j++) {
 			char c = options[i].optionValuePointer[j];
@@ -1655,14 +1771,14 @@
 				INFOX("\\%.2d",c);
 			}
 		}
-		INFO("\"");
+		INFOX("\"\r\n");
 	}
 	
 	// print payload
 	if(_payloadLength==0) {
-		INFO("No payload.");
+		INFOX("No payload.\r\n");
 	} else {
-		INFO("Payload of %d bytes",_payloadLength);
+		INFOX("Payload of %d bytes\r\n",_payloadLength);
 		INFOX("   Value: \"");
 		for(int j=0; j<_payloadLength; j++) {
 			char c = _payloadPointer[j];
@@ -1672,9 +1788,9 @@
 				INFOX("\\%.2x",c);
 			}
 		}
-		INFO("\"");
+		INFO("\"\r\n");
 	}
-	INFO("__________________");
+	INFOX("__________________\r\n");
 }
 
 /// Prints the PDU as a c array (useful for debugging or hardcoding PDUs)
@@ -1795,4 +1911,4 @@
 /// Dumps the PDU as a byte sequence to stdout.
 void CoapPDU::print() {
 	fwrite(_pdu,1,_pduLength,stdout);
-}
+}
\ No newline at end of file
--- a/cantcoap.h	Tue Oct 08 14:36:01 2013 +0000
+++ b/cantcoap.h	Thu Jan 30 14:07:56 2014 +0000
@@ -1,25 +1,31 @@
-/// Copyright (c) 2013, Ashley Mills.
-#define MBED
-#ifndef MBED
-#include <unistd.h>
-#endif
-#include <stdint.h>
+/**
+Copyright (c) 2013, Ashley Mills.
+All rights reserved.
 
-#define INFO(...) printf(__VA_ARGS__); printf("\r\n");
-#define INFOX(...); printf(__VA_ARGS__);
-#define ERR(...) printf(__VA_ARGS__); printf("\r\n");
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met: 
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution. 
 
-#ifdef DEBUG
-	#define DBG(...) fprintf(stderr,"%s:%d ",__FILE__,__LINE__); fprintf(stderr,__VA_ARGS__); fprintf(stderr,"\r\n");
-	#define DBGX(...) fprintf(stderr,__VA_ARGS__);
-	#define DBGLX(...) fprintf(stderr,"%s:%d ",__FILE__,__LINE__); fprintf(stderr,__VA_ARGS__);
-	#define DBG_PDU() printBin();
-#else
-	#define DBG(...) {};
-	#define DBGX(...) {};
-	#define DBGLX(...) {};
-	#define DBG_PDU() {};
-#endif
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include <stdint.h>
 
 #define COAP_HDR_SIZE 4
 #define COAP_OPTION_HDR_BYTE 1
@@ -77,7 +83,8 @@
 			COAP_BAD_GATEWAY,
 			COAP_SERVICE_UNAVAILABLE,
 			COAP_GATEWAY_TIMEOUT,
-			COAP_PROXYING_NOT_SUPPORTED
+			COAP_PROXYING_NOT_SUPPORTED,
+			COAP_UNDEFINED_CODE=0xFF
 		};
 
 		/// CoAP option numbers.
@@ -148,6 +155,7 @@
 		// message code
 		void setCode(CoapPDU::Code code);
 		CoapPDU::Code getCode();
+		CoapPDU::Code httpStatusToCode(int httpStatus);
 
 		// message ID
 		int setMessageID(uint16_t messageID);
@@ -159,8 +167,10 @@
 		CoapOption* getOptions();
 		int getNumOptions();
 		// shorthand helpers
+		int setURI(char *uri);
 		int setURI(char *uri, int urilen);
 		int getURI(char *dst, int dstlen, int *outLen);
+		int addURIQuery(char *query);
 
 		// content format helper
 		int setContentFormat(CoapPDU::ContentFormat format);
@@ -251,4 +261,4 @@
 #define COAP_CODE_SERVICE_UNAVAILABLE        0xA3
 #define COAP_CODE_GATEWAY_TIMEOUT            0xA4
 #define COAP_CODE_PROXYING_NOT_SUPPORTED     0xA5
-*/
+*/
\ No newline at end of file