From eeec6a8789bf9a995506d648b43e61e5f1447491 Mon Sep 17 00:00:00 2001 From: Sangkoo Kim Date: Mon, 17 Apr 2017 14:29:08 +0900 Subject: [PATCH] Initial version --- CMakeLists.txt | 76 + content_server/content_server.js | 299 ++++ content_server/file_upload.html | 108 ++ content_server/install.sh | 12 + content_server/package.json | 17 + content_server/ss_bsdiff | Bin 0 -> 350858 bytes content_server/ss_bspatch | Bin 0 -> 110837 bytes content_server/sub.js | 33 + inc/iotivity/AttributeValue.h | 156 ++ inc/iotivity/CAManager.h | 90 + inc/iotivity/IClientWrapper.h | 158 ++ inc/iotivity/IServerWrapper.h | 83 + inc/iotivity/InProcClientWrapper.h | 248 +++ inc/iotivity/InProcServerWrapper.h | 83 + inc/iotivity/InitializeException.h | 39 + inc/iotivity/OCAccountManager.h | 356 ++++ inc/iotivity/OCApi.h | 306 ++++ inc/iotivity/OCCloudProvisioning.hpp | 139 ++ inc/iotivity/OCDirectPairing.h | 69 + inc/iotivity/OCException.h | 56 + inc/iotivity/OCHeaderOption.h | 124 ++ inc/iotivity/OCPlatform.h | 707 ++++++++ inc/iotivity/OCPlatform_impl.h | 305 ++++ inc/iotivity/OCProvisioningManager.hpp | 445 +++++ inc/iotivity/OCRepresentation.h | 512 ++++++ inc/iotivity/OCResource.h | 691 ++++++++ inc/iotivity/OCResourceRequest.h | 268 +++ inc/iotivity/OCResourceResponse.h | 303 ++++ inc/iotivity/OCSerialization.h | 164 ++ inc/iotivity/OCUtilities.h | 148 ++ inc/iotivity/OutOfProcClientWrapper.h | 179 ++ inc/iotivity/OutOfProcServerWrapper.h | 124 ++ inc/iotivity/RDClient.h | 118 ++ inc/iotivity/ResourceInitException.h | 126 ++ inc/iotivity/StringConstants.h | 166 ++ inc/iotivity/WrapperFactory.h | 89 + inc/iotivity/iotivity_config.h | 63 + inc/iotivity/logger.h | 251 +++ inc/iotivity/logger_types.h | 85 + inc/iotivity/oc_log_stream.hpp | 80 + inc/iotivity/oc_logger.h | 54 + inc/iotivity/oc_logger.hpp | 31 + inc/iotivity/oc_logger_types.h | 86 + inc/iotivity/ocpayload.h | 291 ++++ inc/iotivity/ocpresence.h | 45 + inc/iotivity/ocstack.h | 737 +++++++++ inc/iotivity/ocstackconfig.h | 114 ++ inc/iotivity/octypes.h | 1716 ++++++++++++++++++++ inc/iotivity/platform_features.h | 90 + inc/iotivity/targets/oc_console_logger.h | 43 + inc/iotivity/targets/oc_ostream_logger.h | 49 + inc/ua_client.h | 46 + lib/libc_common.a | Bin 0 -> 35752 bytes lib/libcoap.a | Bin 0 -> 322656 bytes lib/libconnectivity_abstraction.a | Bin 0 -> 924084 bytes lib/liblogger.a | Bin 0 -> 9748 bytes lib/liboc.a | Bin 0 -> 40836978 bytes lib/liboc_logger.a | Bin 0 -> 166984 bytes lib/libocsrm.a | Bin 0 -> 1292762 bytes lib/liboctbstack.a | Bin 0 -> 1020642 bytes lib/libresource_directory.a | Bin 0 -> 3297410 bytes lib/libroutingmanager.a | Bin 0 -> 45614 bytes packaging/ua-client.service | 10 + packaging/ua-client.spec | 63 + .../iotivity-sec_3.0/iotivity-1.2.1-0.armv7l.rpm | Bin 0 -> 432306 bytes .../iotivity-devel-1.2.1-0.armv7l.rpm | Bin 0 -> 944371 bytes .../iotivity-service-1.2.1-0.armv7l.rpm | Bin 0 -> 316158 bytes .../iotivity-test-1.2.1-0.armv7l.rpm | Bin 0 -> 36550 bytes .../iotivity_unified/iotivity-1.2.1-0.armv7l.rpm | Bin 0 -> 384353 bytes .../iotivity-debuginfo-1.2.1-0.armv7l.rpm | Bin 0 -> 3043968 bytes .../iotivity-debugsource-1.2.1-0.armv7l.rpm | Bin 0 -> 624943 bytes .../iotivity-devel-1.2.1-0.armv7l.rpm | Bin 0 -> 979922 bytes .../iotivity-service-1.2.1-0.armv7l.rpm | Bin 0 -> 383233 bytes .../iotivity-service-debuginfo-1.2.1-0.armv7l.rpm | Bin 0 -> 8403260 bytes .../iotivity-test-1.2.1-0.armv7l.rpm | Bin 0 -> 310457 bytes .../iotivity-test-debuginfo-1.2.1-0.armv7l.rpm | Bin 0 -> 6605352 bytes res/.firmware_controlee.dat | Bin 0 -> 466 bytes res/device_info.ini | 7 + src/ua_client.cpp | 1019 ++++++++++++ src/ua_http.cpp | 214 +++ src/ua_json_parser.cpp | 170 ++ 81 files changed, 12061 insertions(+) create mode 100755 CMakeLists.txt create mode 100644 content_server/content_server.js create mode 100644 content_server/file_upload.html create mode 100755 content_server/install.sh create mode 100644 content_server/package.json create mode 100755 content_server/ss_bsdiff create mode 100755 content_server/ss_bspatch create mode 100644 content_server/sub.js create mode 100644 inc/iotivity/AttributeValue.h create mode 100644 inc/iotivity/CAManager.h create mode 100644 inc/iotivity/IClientWrapper.h create mode 100644 inc/iotivity/IServerWrapper.h create mode 100644 inc/iotivity/InProcClientWrapper.h create mode 100644 inc/iotivity/InProcServerWrapper.h create mode 100644 inc/iotivity/InitializeException.h create mode 100644 inc/iotivity/OCAccountManager.h create mode 100644 inc/iotivity/OCApi.h create mode 100755 inc/iotivity/OCCloudProvisioning.hpp create mode 100644 inc/iotivity/OCDirectPairing.h create mode 100644 inc/iotivity/OCException.h create mode 100644 inc/iotivity/OCHeaderOption.h create mode 100644 inc/iotivity/OCPlatform.h create mode 100644 inc/iotivity/OCPlatform_impl.h create mode 100644 inc/iotivity/OCProvisioningManager.hpp create mode 100644 inc/iotivity/OCRepresentation.h create mode 100644 inc/iotivity/OCResource.h create mode 100644 inc/iotivity/OCResourceRequest.h create mode 100644 inc/iotivity/OCResourceResponse.h create mode 100644 inc/iotivity/OCSerialization.h create mode 100644 inc/iotivity/OCUtilities.h create mode 100644 inc/iotivity/OutOfProcClientWrapper.h create mode 100644 inc/iotivity/OutOfProcServerWrapper.h create mode 100644 inc/iotivity/RDClient.h create mode 100644 inc/iotivity/ResourceInitException.h create mode 100644 inc/iotivity/StringConstants.h create mode 100644 inc/iotivity/WrapperFactory.h create mode 100755 inc/iotivity/iotivity_config.h create mode 100644 inc/iotivity/logger.h create mode 100644 inc/iotivity/logger_types.h create mode 100644 inc/iotivity/oc_log_stream.hpp create mode 100644 inc/iotivity/oc_logger.h create mode 100644 inc/iotivity/oc_logger.hpp create mode 100644 inc/iotivity/oc_logger_types.h create mode 100644 inc/iotivity/ocpayload.h create mode 100644 inc/iotivity/ocpresence.h create mode 100644 inc/iotivity/ocstack.h create mode 100644 inc/iotivity/ocstackconfig.h create mode 100755 inc/iotivity/octypes.h create mode 100644 inc/iotivity/platform_features.h create mode 100644 inc/iotivity/targets/oc_console_logger.h create mode 100644 inc/iotivity/targets/oc_ostream_logger.h create mode 100644 inc/ua_client.h create mode 100755 lib/libc_common.a create mode 100755 lib/libcoap.a create mode 100755 lib/libconnectivity_abstraction.a create mode 100755 lib/liblogger.a create mode 100755 lib/liboc.a create mode 100755 lib/liboc_logger.a create mode 100755 lib/libocsrm.a create mode 100755 lib/liboctbstack.a create mode 100755 lib/libresource_directory.a create mode 100755 lib/libroutingmanager.a create mode 100644 packaging/ua-client.service create mode 100755 packaging/ua-client.spec create mode 100644 ref_rpms/iotivity-sec_3.0/iotivity-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity-sec_3.0/iotivity-devel-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity-sec_3.0/iotivity-service-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity-sec_3.0/iotivity-test-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity_unified/iotivity-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity_unified/iotivity-debuginfo-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity_unified/iotivity-debugsource-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity_unified/iotivity-devel-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity_unified/iotivity-service-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity_unified/iotivity-service-debuginfo-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity_unified/iotivity-test-1.2.1-0.armv7l.rpm create mode 100644 ref_rpms/iotivity_unified/iotivity-test-debuginfo-1.2.1-0.armv7l.rpm create mode 100755 res/.firmware_controlee.dat create mode 100755 res/device_info.ini create mode 100755 src/ua_client.cpp create mode 100644 src/ua_http.cpp create mode 100644 src/ua_json_parser.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..15d1344 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,76 @@ +cmake_minimum_required (VERSION 2.8) + +project (ua-client) + +#set(CMAKE_SKIP_BUILD_RPATH TRUE) + +include(CheckCXXCompilerFlag) + +CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) +CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) +IF(COMPILER_SUPPORTS_CXX11) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +ELSEIF(COMPILER_SUPPORTS_CXX0X) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +ELSE() + MESSAGE(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++ support. Please use a different C++ compiler.") +ENDIF() + +install(FILES ${CMAKE_SOURCE_DIR}/res/device_info.ini DESTINATION /opt/usr/data/ua_client/) +install(FILES ${CMAKE_SOURCE_DIR}/res/.firmware_controlee.dat DESTINATION /opt/usr/data/ua_client/) + + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -O2 -g -Wall") + +add_definitions(-D__TIZEN__ -D_GNU_SOURCE -DTIZEN_DEBUG_ENABLE -DTB_LOG -DWITH_CLOUD -DRD_SERVER) + +include_directories( + ${CMAKE_SOURCE_DIR}/inc/ + ${CMAKE_SOURCE_DIR}/inc/iotivity/ + ) + +set(SOURCES + ${CMAKE_SOURCE_DIR}/src/ua_client.cpp + ${CMAKE_SOURCE_DIR}/src/ua_http.cpp + ${CMAKE_SOURCE_DIR}/src/ua_json_parser.cpp + ) + +#set(dependents "boost dlog glib-2.0 iotivity libcurl uuid json-glib-1.0 capi-network-connection") +set(dependents "boost dlog glib-2.0 libcurl uuid json-glib-1.0 capi-network-connection capi-network-wifi") +include(FindPkgConfig) +pkg_check_modules(${PROJECT_NAME} REQUIRED ${dependents}) + +foreach(flag ${${PROJECT_NAME}_CFLAGS}) + set(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag} -std=c++11") +endforeach(flag) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS}") + +#find_library(IOTIVITY_LIBRARY +# NAMES oc oc_logger octbstack ocsrm routingmanager connectivity_abstraction c_common coap logger +# PATHS ${CMAKE_SOURCE_DIR}/lib/ +#) + +set(LINK_STATIC_LIBS + oc + oc_logger + octbstack + ocsrm + routingmanager + connectivity_abstraction + c_common + coap + resource_directory + logger + pthread + rt + uuid + capi-network-wifi + ) + +set(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed") + +link_directories(${CMAKE_SOURCE_DIR}/lib/) +add_executable(${PROJECT_NAME} ${SOURCES}) +target_link_libraries(${PROJECT_NAME} ${${PROJECT_NAME}_LDFLAGS} ${LINK_STATIC_LIBS}) +install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/content_server/content_server.js b/content_server/content_server.js new file mode 100644 index 0000000..8ee06e0 --- /dev/null +++ b/content_server/content_server.js @@ -0,0 +1,299 @@ +const PORT = 8000 +const IMAGE_DIR = "/var/www/images/" + +const HTTP_OK = 200; +const HTTP_BAD_REQUEST = 400; +const HTTP_INTERNAL_ERROR = 500; + +var express = require('express'); +var app = express(); +var fs = require("fs"); +var host_ip = require("ip"); + +var bodyParser = require('body-parser'); +var multer = require('multer'); +const cp = require('child_process'); +var sqlite3 = require('sqlite3').verbose(); +var db = new sqlite3.Database('firmware.db'); +var child = cp.fork(__dirname +'/sub.js'); +var qcount = 0; +var cmd_list = []; +var resp_msg = {}; +var update_msg = {}; +var g_res; + +app.use(express.static('public')); +app.use(bodyParser.urlencoded({ extended: false })); + +app.get('/file_upload.html', function (req, res) { + res.sendFile( __dirname + "/" + "file_upload.html" ); +// res.sendFile( __dirname + "/" + "file_upload3.html" ); +}) + +/* +app.get('/monitoring.html', function (req, res) { + res.sendFile( __dirname + "/" + "monitoring.html" ); +// res.sendFile( __dirname + "/" + "file_upload3.html" ); +}) +*/ + +var server = app.listen(PORT, function () { + var host = host_ip.address(); + var port = server.address().port; + + console.log("content-server listening at http://%s:%s", host, port) +}) + +db.serialize(function() { + db.run("CREATE TABLE IF NOT EXISTS full_tbl (manufacturer TEXT, model TEXT, version TEXT, file TEXT, patch_version TEXT, patch_url TEXT, priority INT)"); + db.each("SELECT model, version, file FROM full_tbl", function(err, row) { + console.log(row.model, ",", row.version, ":", row.file); + }); +}); + + +var upload = multer({ dest: '/tmp/'}); + +// curl -v -X GET http://localhost:3000/firmware?manufacturer=samsung&model=tm1&version=1.0 +app.get('/firmware', function(req, res){ + console.log("url: [", req.url, "]"); + console.log("query: [", req.query, "]"); + var manufacturer = req.query.manufacturer; + var model = req.query.model; + var cur_ver = req.query.version; + console.log("manufacturer: [", manufacturer, "]"); + console.log("model: [", model, "]"); + + if (!(manufacturer || model || version)) { + console.log("bad request - manufacturer[", manufacturer, "], model[", model, "]"); + res.status(HTTP_BAD_REQUEST).json({errmsg: "missing parameters"}); + return; + } + + var ret = {}; + db.get("SELECT * FROM full_tbl WHERE manufacturer=? AND model=? AND version=?", manufacturer, model, cur_ver, function(err, row) { + if (err){ + console.error("error", err); + res.status(HTTP_INTERNAL_ERROR).json(err); + } + else if (!row) { + console.log('firmware not found'); + res.status(HTTP_BAD_REQUEST).json({errmsg:'firmware not found'}); + } + else { + console.log(row); + ret.old_version = cur_ver; + ret.new_verion = row.patch_version; + ret.url = row.patch_url; + ret.priority = row.priority; + res.json(ret); + } + }); +}); + + +app.post('/file_upload', upload.single('file'), function(req, res) { + var file = IMAGE_DIR + req.file.originalname; + var mf = req.body.manufacturer; + var model = req.body.model; + var ver = req.body.version; + var priority = req.body.priority; + console.log("req.file: ", file); + console.log("manufacturer: ", mf); + console.log("model: ", model); + console.log("version: ", ver); + console.log("priority: ", priority); + + if(!(file && mf && model && ver)) { + console.log("file[", file,"], manufacturer[",mf ,"], model[", model,"], version[",ver ,"]"); + res.status(HTTP_BAD_REQUEST).json({errmsg: "missing parameters"}); + return; + } + + + console.log("req.body:", req.body); + cmd_list = []; + resp_msg = {}; + resp_msg.results = []; + update_msg = {}; + update_msg.urls = []; + + if(req.body.upload) { + fs.rename(req.file.path, file, function(err) { + if (err) { + console.log("error: ", err); + res.status(HTTP_INTERNAL_ERROR).json(err); + } else { + db.get("SELECT file FROM full_tbl WHERE manufacturer=? and model=? and version=?", mf, model, ver, function(err, row) { + if (err){ + console.error("error", err); + res.status(HTTP_INTERNAL_ERROR).json(err); + } + else if (row) { + console.log("the same version already exists"); + res.status(HTTP_BAD_REQUEST).json({errmsg:'version duplicated'}); + } + else { + db.run("INSERT INTO full_tbl (manufacturer, model, version, file, patch_version, patch_url, priority) VALUES (?,?,?,?,?,?,?)", mf, model, ver, file, ver, req.file.originalname, priority, function(err) { + if (err){ + console.error("error", err); + res.status(HTTP_INTERNAL_ERROR).json(err); + } + else + res.json({'manufacturer':mf, 'model': model, 'version':ver, 'file':req.file.originalname, 'priority':priority}); + }); + } + }); + } + }); + } + else if(req.body.bsdiff) { + db.each("SELECT * FROM full_tbl WHERE manufacturer=? and model=?", mf, model, + function(err, row){ /* result callback */ + console.log("old version [" + row.version + "]"); + if(ver > row.version) { + var cmd = {}; + cmd.old_ver = row.version; + cmd.old_file = row.file; + cmd.new_file = file; + cmd.new_ver = ver; +// var cmd = __dirname + '/ss_bsdiff' + " " + old_file + " " + file + " "+ patch_file; + console.log("cmd:", cmd); + cmd_list.push(cmd); + } + }, function(err,row) { /* completion callback */ + if (err){ + console.error("error", err); + res.status(HTTP_INTERNAL_ERROR).json(err); + } + else if(row==0 || cmd_list.length == 0){ + res.status(HTTP_BAD_REQUEST).json({'errmsg':'no firmware available'}); + } + else { + update_msg.manufacturer = mf; + update_msg.model = model; +// update_msg.cmd = "WRITE"; + update_msg.priority = priority; + console.log("cmd list:", cmd_list, ", length:", cmd_list.length); + // send the first cmd to child process + child.send(cmd_list[0]); + qcount = 1; + g_res = res; // after processing the last command, g_res is used for response + } + }); + } + else if(req.body.diff) { + var old_ver = req.body.old_version; + if(!old_ver) { + console.log("old_version", old_ver,"]"); + res.status(HTTP_BAD_REQUEST).json({errmsg: "missing parameters: old_version"}); + return; + } + + fs.rename(req.file.path, file, function(err) { + if (err) { + console.log("error: ", err); + res.status(HTTP_INTERNAL_ERROR).json(err); + } else { + db.get("SELECT * FROM full_tbl WHERE manufacturer=? and model=? and version=?", mf, model, old_ver, function(err, row) { + if (err){ + console.error("error", err); + res.status(HTTP_INTERNAL_ERROR).json(err); + } + else if (!row) { + console.log("version not found"); + res.status(HTTP_BAD_REQUEST).json({errmsg:'version not found'}); + } + else { + var patch_url = "http://" + host_ip.address() + "/images/" + req.file.originalname; + db.run("UPDATE full_tbl SET patch_version=?, patch_url=?, priority=? WHERE manufacturer=? AND model=? AND version=?", ver, patch_url, priority, mf, model, old_ver, function(err) { + if (err){ + console.error("error", err); + res.status(HTTP_INTERNAL_ERROR).json(err); + } + else + res.json({'manufacturer':mf, 'model': model, 'old_version':old_ver, 'new_version':ver, 'url':patch_url ,'priority':priority, }); + }); + } + }); + } + }); + } +}); + + +child.on('message', function(m) { + console.log('return:', m); + console.log('qcount:', qcount, "qlength:", cmd_list.length); + + var resp = {}; + resp.version = m.old_ver; + resp.errmsg = m.errmsg; + resp_msg.results.push(resp); + + var update = {}; + update.old_version = m.old_ver; + update.new_version = m.new_ver; + update.url = "http://" + host_ip.address() + "/images/" + m.patch_name; + console.log("added:", update); + update_msg.urls.push(update); + + db.run("UPDATE full_tbl SET patch_version=?,patch_url=?,priority=? WHERE manufacturer=? AND model=? AND version=?", update.new_version, update.url, update_msg.priority, update_msg.manufacturer, update_msg.model, update.old_version, function(err) { + if (err){ + console.error("error", err); + res.status(HTTP_INTERNAL_ERROR).json(err); + } + else { + if (qcount == cmd_list.length) { + // the last command + console.log("diff done"); + console.log("update_msg:", update_msg); + g_res.json(resp_msg); + } + else { + // request the next command + console.log("cmd:", cmd_list[qcount]); + child.send(cmd_list[qcount]); + qcount++; + } + } + }); +}); + +/* else if(req.body.nodiff) { + db.get("SELECT file FROM full_tbl WHERE manufacturer=? and model=? and version=?", mf, model, ver, function(err, row) { + if (err){ + console.error("error", err); + res.status(HTTP_INTERNAL_ERROR).json(err); + } + else if (!row) { + console.log("firmware not found"); + res.status(HTTP_BAD_REQUEST).json({errmsg:'firmware not found'}); + } + else { + var resp = {}; + resp.old_ver = m.old_ver; + resp.new_ver = m.new_ver; + resp.errmsg = "success"; + resp.patch_name = patch_name; + console.log(resp); + update_msg.manufacturer = mf; + update_msg.model = model; + update_msg.cmd = "WRITE"; + + var options = { + uri: REST_SERVER_ADDR+"/devices/update", + method: 'POST', + json: update_msg + }; + request.post(options, function(error, response, body) { + if(error) { + console.log(error); + } + else { + console.log(body); + } + }); + } + }); + } */ diff --git a/content_server/file_upload.html b/content_server/file_upload.html new file mode 100644 index 0000000..be2cf65 --- /dev/null +++ b/content_server/file_upload.html @@ -0,0 +1,108 @@ + + +Firmware Uploading Form + + +

Firmware Upload:

+Select a file to upload:
+ +
+
+Manufacturer:
+
+Model:
+
+New Firmware Version:
+
+Priority:
+

+ +

+Old Firmware Version:
+
+ +
+
RESULT
+
+ + + + + diff --git a/content_server/install.sh b/content_server/install.sh new file mode 100755 index 0000000..76b4997 --- /dev/null +++ b/content_server/install.sh @@ -0,0 +1,12 @@ +#/bin/bash +sudo apt-get install nginx +echo "Configuring /etc/nginx/sites-available/default" +sudo chmod 777 /etc/nginx/sites-available/default +echo 'server { + location /images/ { + root /var/www; + } +}' >> /etc/nginx/sites-available/default +echo "mkdir & chmod /var/www/images" +sudo mkdir /var/www/images/ +sudo chmod 777 /var/www/images/ diff --git a/content_server/package.json b/content_server/package.json new file mode 100644 index 0000000..c7d2d96 --- /dev/null +++ b/content_server/package.json @@ -0,0 +1,17 @@ +{ + "name": "tizen-firmware-rest-api-server", + "version": "0.0.1", + "main": "apiserver.js", + "dependencies": { + "express": "4.14.x", + "body-parser": "1.16.x", + "sqlite3": "3.1.x", + "ref": "1.3.x", + "ffi": "2.2.x", + "hashmap": "2.0.x", + "child_process": "1.0.x", + "request" : "2.81.x", + "multer" : "1.3.x", + "ip" : "1.1.x" + } +} diff --git a/content_server/ss_bsdiff b/content_server/ss_bsdiff new file mode 100755 index 0000000000000000000000000000000000000000..107ae6dcf6e77ad31e580a01ad361f1fa4fce92f GIT binary patch literal 350858 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 z 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%0AuZ+GPqq3QFExNB8MA7dyWk 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 literal 0 HcmV?d00001 diff --git a/content_server/ss_bspatch b/content_server/ss_bspatch new file mode 100755 index 0000000000000000000000000000000000000000..956d75ddcf6e77825815900c436750f14bf1d9ae GIT binary patch literal 110837 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 z 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

*X*0E%Ufpg1YVXRVdV8GGuI@~#bkX9fshOrW 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 AyZ`_I literal 0 HcmV?d00001 diff --git a/content_server/sub.js b/content_server/sub.js new file mode 100644 index 0000000..fd8146a --- /dev/null +++ b/content_server/sub.js @@ -0,0 +1,33 @@ +const webpath = "/var/www/images" +const exec = require('child_process').exec; +var errmsg; + +process.on('message', function(m) { + console.log("message:",m); + console.log("old_ver:",m.old_ver); + console.log("old_file:",m.old_file); + console.log("new_file:",m.new_file); + var patch_name = "patch_" + m.old_ver + "-" + m.new_ver; + var patch_file = webpath + "/" + patch_name; + console.log("patch:", patch_file); + var cmd = __dirname + "/ss_bsdiff" + " " + m.old_file + " " + m.new_file + " "+ patch_file; + var cmd2 = ";chmod 755 " + patch_file; + console.log(cmd); + exec(cmd+cmd2, function(error) { + if (error) { + console.log(error); + errmsg = error; + // res.sendStatus(500); + } else { + var resp = {}; + resp.old_ver = m.old_ver; + resp.new_ver = m.new_ver; + resp.errmsg = "success"; + resp.patch_name = patch_name; + console.log(resp); + process.send(resp); + // process.disconnect(); + } + }); +}); + diff --git a/inc/iotivity/AttributeValue.h b/inc/iotivity/AttributeValue.h new file mode 100644 index 0000000..3315356 --- /dev/null +++ b/inc/iotivity/AttributeValue.h @@ -0,0 +1,156 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/** + * @file + * + * This file contains the definition of the internally used type + * AttributeValue. + */ + +#ifndef OC_ATTRIBUTEVALUE_H_ +#define OC_ATTRIBUTEVALUE_H_ + +// These defines are required to get the boost::variant to hold more than 20 items. +// documentation requires that you use a power of 10 +#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS +#define BOOST_MPL_LIMIT_LIST_SIZE 30 +#define BOOST_MPL_LIMIT_VECTOR_SIZE 30 +#include +#include +#include +namespace OC +{ + class OCRepresentation; + + struct NullType{}; + + // Since null needs to be encoded in a special fashion in JSON, the encoder + // needs to know the index of the NullType Sentinel Any time the code does a special + // case for the NullType, we use the AttributeValueNullIndex. This MUST be kept up to date + // with the variant's which() for NullType. + static const int AttributeValueNullIndex = 0; + typedef boost::variant< + NullType, // Note: this handles the null-type and must match the above static const + int, + double, + bool, + std::string, + OC::OCRepresentation, + OCByteString, + + // Sequences: + std::vector, + std::vector, + std::vector, + std::vector, + std::vector, + std::vector, + + // Nested sequences: + std::vector>, + std::vector>>, + + std::vector>, + std::vector>>, + + std::vector>, + std::vector>>, + + std::vector>, + std::vector>>, + + std::vector>, + std::vector>>, + + std::vector>, + std::vector>>, + + // used for binary data type + std::vector + > AttributeValue; + + enum class AttributeType + { + Null, + Integer, + Double, + Boolean, + String, + OCRepresentation, + Vector, + Binary, + OCByteString + }; + + template + struct AttributeTypeConvert{}; + + template<> + struct AttributeTypeConvert + { + BOOST_STATIC_CONSTEXPR AttributeType type = AttributeType::Null; + }; + + template<> + struct AttributeTypeConvert + { + BOOST_STATIC_CONSTEXPR AttributeType type = AttributeType::Integer; + }; + + template<> + struct AttributeTypeConvert + { + BOOST_STATIC_CONSTEXPR AttributeType type = AttributeType::Double; + }; + + template<> + struct AttributeTypeConvert + { + BOOST_STATIC_CONSTEXPR AttributeType type = AttributeType::Boolean; + }; + + template<> + struct AttributeTypeConvert + { + BOOST_STATIC_CONSTEXPR AttributeType type = AttributeType::String; + }; + + template<> + struct AttributeTypeConvert + { + BOOST_STATIC_CONSTEXPR AttributeType type = AttributeType::OCRepresentation; + }; + + template<> + struct AttributeTypeConvert + { + BOOST_STATIC_CONSTEXPR AttributeType type = AttributeType::OCByteString; + }; + + template<> + struct AttributeTypeConvert> + { + BOOST_STATIC_CONSTEXPR AttributeType type = AttributeType::Binary; + }; + + std::ostream& operator << (std::ostream& os, const AttributeType at); +} +#endif // OC_ATTRIBUTEVALUE_H_ diff --git a/inc/iotivity/CAManager.h b/inc/iotivity/CAManager.h new file mode 100644 index 0000000..3a19a07 --- /dev/null +++ b/inc/iotivity/CAManager.h @@ -0,0 +1,90 @@ +/* **************************************************************** + * + * Copyright 2016 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#ifndef CA_MANAGER_H_ +#define CA_MANAGER_H_ + +#include + +namespace OC +{ + /** + * This namespace contains the main entrance/functionality to monitoring network changes. + * It may be used with OC::CAManager::functionName. To set a custom callback function, + * the implementer must make a call to CAManager::setNetworkMonitorHandler. + */ + namespace CAManager + { + // typedef to get adapter status changes from CA. + typedef std::function ConnectionChangedCallback; + + // typedef to get connection status changes from CA. + typedef std::function AdapterChangedCallback; + + /** + * Set network monitoring handler. + * @param adapterHandler adapter state change handler to handle changes for + * any transport types. + * @param connectionHandler connection state change handler to handle changes for + * connection with remote devices. + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult setNetworkMonitorHandler(AdapterChangedCallback adapterHandler, + ConnectionChangedCallback connectionHandler); + + /** + * Set port number to use. + * @param adapter transport adapter type to assign the specified port number. + * @param flag transport flag information. + * @param port the specified port number to use. + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult setPortNumberToAssign(OCTransportAdapter adapter, + OCTransportFlags flag, uint16_t port); + + /** + * Get the assigned port number. + * @param adapter transport adapter type to get the opened port number. + * @param flag transport flag information. + * @return Returns currently assigned port number. + */ + uint16_t getAssignedPortNumber(OCTransportAdapter adapter, OCTransportFlags flag); + +#if defined(__WITH_DTLS__) || defined(__WITH_TLS__) + /** + * Select the cipher suite for TLS/DTLS handshake. + * @param cipher cipher suite (Note : Make sure endianness). + * 0x35 : TLS_RSA_WITH_AES_256_CBC_SHA + * 0xC018 : TLS_ECDH_anon_WITH_AES_128_CBC_SHA + * 0xC037 : TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * 0xC0AE : TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + * @param adapter transport adapter type. + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult setCipherSuite(const uint16_t cipher, OCTransportAdapter adapter); +#endif // defined(__WITH_DTLS__) || defined(__WITH_TLS__) + } +} + +#endif // CA_MANAGER_H_ + + + diff --git a/inc/iotivity/IClientWrapper.h b/inc/iotivity/IClientWrapper.h new file mode 100644 index 0000000..b453068 --- /dev/null +++ b/inc/iotivity/IClientWrapper.h @@ -0,0 +1,158 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_I_CLIENT_WRAPPER_H_ +#define OC_I_CLIENT_WRAPPER_H_ + +#include +#include +#include + +namespace OC +{ + class OCPlatform_impl; + + class IClientWrapper : public std::enable_shared_from_this + { + protected: + + public: + typedef std::shared_ptr Ptr; + + IClientWrapper() + {} + + virtual OCStackResult ListenForResource(const std::string& serviceUrl, + const std::string& resourceType, + OCConnectivityType connectivityType, + FindCallback& callback, + QualityOfService QoS) = 0; + + virtual OCStackResult ListenForResource2(const std::string& serviceUrl, + const std::string& resourceType, + OCConnectivityType connectivityType, + FindResListCallback& callback, + QualityOfService QoS) = 0; + + virtual OCStackResult ListenErrorForResource(const std::string& serviceUrl, + const std::string& resourceType, + OCConnectivityType connectivityType, + FindCallback& callback, + FindErrorCallback& errorCallback, + QualityOfService QoS) = 0; + + virtual OCStackResult ListenForDevice(const std::string& serviceUrl, + const std::string& deviceURI, + OCConnectivityType connectivityType, + FindDeviceCallback& callback, + QualityOfService QoS) = 0; + + virtual OCStackResult GetResourceRepresentation( + const OCDevAddr& devAddr, + const std::string& uri, + const QueryParamsMap& queryParams, + const HeaderOptions& headerOptions, + OCConnectivityType connectivityType, + GetCallback& callback, QualityOfService QoS)=0; + + virtual OCStackResult PutResourceRepresentation( + const OCDevAddr& devAddr, + const std::string& uri, + const OCRepresentation& rep, const QueryParamsMap& queryParams, + const HeaderOptions& headerOptions, + PutCallback& callback, QualityOfService QoS) = 0; + + virtual OCStackResult PostResourceRepresentation( + const OCDevAddr& devAddr, + const std::string& uri, + const OCRepresentation& rep, const QueryParamsMap& queryParams, + const HeaderOptions& headerOptions, + OCConnectivityType connectivityType, + PostCallback& callback, QualityOfService QoS) = 0; + + virtual OCStackResult DeleteResource( + const OCDevAddr& devAddr, + const std::string& uri, + const HeaderOptions& headerOptions, + OCConnectivityType connectivityType, + DeleteCallback& callback, QualityOfService QoS) = 0; + + virtual OCStackResult ObserveResource( + ObserveType observeType, OCDoHandle* handle, + const OCDevAddr& devAddr, + const std::string& uri, + const QueryParamsMap& queryParams, + const HeaderOptions& headerOptions, ObserveCallback& callback, + QualityOfService QoS)=0; + + virtual OCStackResult CancelObserveResource( + OCDoHandle handle, + const std::string& host, + const std::string& uri, + const HeaderOptions& headerOptions, + QualityOfService QoS)=0; + + virtual OCStackResult SubscribePresence(OCDoHandle* handle, + const std::string& host, + const std::string& resourceType, + OCConnectivityType connectivityType, + SubscribeCallback& presenceHandler)=0; + + virtual OCStackResult UnsubscribePresence(OCDoHandle handle) =0; + +#ifdef WITH_CLOUD + virtual OCStackResult SubscribeDevicePresence(OCDoHandle* handle, + const std::string& host, + const std::vector& di, + OCConnectivityType connectivityType, + ObserveCallback& callback) = 0; +#endif + + virtual OCStackResult GetDefaultQos(QualityOfService& qos) = 0; + + virtual OCStackResult FindDirectPairingDevices(unsigned short waittime, + GetDirectPairedCallback& callback) = 0; + + virtual OCStackResult GetDirectPairedDevices(GetDirectPairedCallback& callback) = 0; + + virtual OCStackResult DoDirectPairing(std::shared_ptr< OCDirectPairing > peer, + const OCPrm_t& pmSel, const std::string& pinNumber, + DirectPairingCallback& resultCallback) = 0; + +#ifdef WITH_MQ + virtual OCStackResult ListenForMQTopic( + const OCDevAddr& devAddr, + const std::string& resourceUri, + const QueryParamsMap& queryParams, const HeaderOptions& headerOptions, + MQTopicCallback& callback, QualityOfService QoS) = 0; + + virtual OCStackResult PutMQTopicRepresentation( + const OCDevAddr& devAddr, + const std::string& uri, + const OCRepresentation& rep, + const QueryParamsMap& queryParams, const HeaderOptions& headerOptions, + MQTopicCallback& callback, QualityOfService QoS) = 0; +#endif + virtual ~IClientWrapper(){} + }; +} + +#endif + diff --git a/inc/iotivity/IServerWrapper.h b/inc/iotivity/IServerWrapper.h new file mode 100644 index 0000000..d49dc1b --- /dev/null +++ b/inc/iotivity/IServerWrapper.h @@ -0,0 +1,83 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_I_SERVER_WRAPPER_H_ +#define OC_I_SERVER_WRAPPER_H_ + +#include +#include + +#include +#include +#include +#include + +namespace OC +{ + class IServerWrapper + { + protected: + + public: + typedef std::shared_ptr Ptr; + + IServerWrapper() + {} + + virtual ~IServerWrapper(){}; + + virtual OCStackResult registerResource( + OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler& entityHandler, + uint8_t resourceProperty) = 0; + + virtual OCStackResult registerDeviceInfo( + const OCDeviceInfo deviceInfo) = 0; + + virtual OCStackResult registerPlatformInfo( + const OCPlatformInfo PlatformInfo) = 0; + + virtual OCStackResult unregisterResource( + const OCResourceHandle& resourceHandle) = 0; + virtual OCStackResult bindTypeToResource( + const OCResourceHandle& resourceHandle, + const std::string& resourceTypeName) = 0; + + virtual OCStackResult bindInterfaceToResource( + const OCResourceHandle& resourceHandle, + const std::string& resourceInterfaceName) = 0; + + virtual OCStackResult startPresence(const unsigned int seconds) = 0; + + virtual OCStackResult stopPresence() = 0; + + virtual OCStackResult setDefaultDeviceEntityHandler(EntityHandler entityHandler) = 0; + + virtual OCStackResult sendResponse(const std::shared_ptr pResponse) = 0; + + virtual OCStackResult setPropertyValue(OCPayloadType type, const std::string& tag, const std::string& value) = 0; + virtual OCStackResult getPropertyValue(OCPayloadType type, const std::string& tag, std::string& value) = 0; + }; +} + +#endif diff --git a/inc/iotivity/InProcClientWrapper.h b/inc/iotivity/InProcClientWrapper.h new file mode 100644 index 0000000..bbf6a38 --- /dev/null +++ b/inc/iotivity/InProcClientWrapper.h @@ -0,0 +1,248 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_IN_PROC_CLIENT_WRAPPER_H_ +#define OC_IN_PROC_CLIENT_WRAPPER_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace OC +{ + namespace ClientCallbackContext + { + struct GetContext + { + GetCallback callback; + GetContext(GetCallback cb) : callback(cb){} + }; + + struct SetContext + { + PutCallback callback; + SetContext(PutCallback cb) : callback(cb){} + }; + + struct ListenContext + { + FindCallback callback; + std::weak_ptr clientWrapper; + + ListenContext(FindCallback cb, std::weak_ptr cw) + : callback(cb), clientWrapper(cw){} + }; + + struct ListenContext2 + { + FindResListCallback callback; + std::weak_ptr clientWrapper; + + ListenContext2(FindResListCallback cb, std::weak_ptr cw) + : callback(cb), clientWrapper(cw){} + }; + + struct ListenErrorContext + { + FindCallback callback; + FindErrorCallback errorCallback; + std::weak_ptr clientWrapper; + + ListenErrorContext(FindCallback cb1, FindErrorCallback cb2, + std::weak_ptr cw) + : callback(cb1), errorCallback(cb2), clientWrapper(cw){} + }; + + struct DeviceListenContext + { + FindDeviceCallback callback; + IClientWrapper::Ptr clientWrapper; + DeviceListenContext(FindDeviceCallback cb, IClientWrapper::Ptr cw) + : callback(cb), clientWrapper(cw){} + }; + + struct SubscribePresenceContext + { + SubscribeCallback callback; + SubscribePresenceContext(SubscribeCallback cb) : callback(cb){} + }; + + struct DeleteContext + { + DeleteCallback callback; + DeleteContext(DeleteCallback cb) : callback(cb){} + }; + + struct ObserveContext + { + ObserveCallback callback; + ObserveContext(ObserveCallback cb) : callback(cb){} + }; + + struct DirectPairingContext + { + DirectPairingCallback callback; + DirectPairingContext(DirectPairingCallback cb) : callback(cb){} + + }; + +#ifdef WITH_MQ + struct MQTopicContext + { + MQTopicCallback callback; + std::weak_ptr clientWrapper; + MQTopicContext(MQTopicCallback cb, std::weak_ptr cw) + : callback(cb), clientWrapper(cw){} + }; +#endif + } + + class InProcClientWrapper : public IClientWrapper + { + + public: + + InProcClientWrapper(std::weak_ptr csdkLock, + PlatformConfig cfg); + virtual ~InProcClientWrapper(); + + virtual OCStackResult ListenForResource(const std::string& serviceUrl, + const std::string& resourceType, OCConnectivityType transportFlags, + FindCallback& callback, QualityOfService QoS); + + virtual OCStackResult ListenForResource2(const std::string& serviceUrl, + const std::string& resourceType, OCConnectivityType transportFlags, + FindResListCallback& callback, QualityOfService QoS); + + virtual OCStackResult ListenErrorForResource(const std::string& serviceUrl, + const std::string& resourceType, OCConnectivityType transportFlags, + FindCallback& callback, FindErrorCallback& errorCallback, QualityOfService QoS); + + virtual OCStackResult ListenForDevice(const std::string& serviceUrl, + const std::string& deviceURI, OCConnectivityType transportFlags, + FindDeviceCallback& callback, QualityOfService QoS); + + virtual OCStackResult GetResourceRepresentation( + const OCDevAddr& devAddr, + const std::string& uri, + const QueryParamsMap& queryParams, const HeaderOptions& headerOptions, + OCConnectivityType connectivityType, + GetCallback& callback, QualityOfService QoS); + + virtual OCStackResult PutResourceRepresentation( + const OCDevAddr& devAddr, + const std::string& uri, + const OCRepresentation& attributes, const QueryParamsMap& queryParams, + const HeaderOptions& headerOptions, PutCallback& callback, QualityOfService QoS); + + virtual OCStackResult PostResourceRepresentation( + const OCDevAddr& devAddr, + const std::string& uri, + const OCRepresentation& attributes, const QueryParamsMap& queryParams, + const HeaderOptions& headerOptions, OCConnectivityType connectivityType, + PostCallback& callback, QualityOfService QoS); + + virtual OCStackResult DeleteResource( + const OCDevAddr& devAddr, + const std::string& uri, + const HeaderOptions& headerOptions, + OCConnectivityType connectivityType, + DeleteCallback& callback, QualityOfService QoS); + + virtual OCStackResult ObserveResource( + ObserveType observeType, OCDoHandle* handle, + const OCDevAddr& devAddr, + const std::string& uri, + const QueryParamsMap& queryParams, const HeaderOptions& headerOptions, + ObserveCallback& callback, QualityOfService QoS); + + virtual OCStackResult CancelObserveResource( + OCDoHandle handle, + const std::string& host, + const std::string& uri, + const HeaderOptions& headerOptions, QualityOfService QoS); + + virtual OCStackResult SubscribePresence( + OCDoHandle *handle, + const std::string& host, + const std::string& resourceType, + OCConnectivityType transportFlags, + SubscribeCallback& presenceHandler); + + virtual OCStackResult UnsubscribePresence(OCDoHandle handle); + +#ifdef WITH_CLOUD + virtual OCStackResult SubscribeDevicePresence(OCDoHandle* handle, + const std::string& host, + const std::vector& di, + OCConnectivityType connectivityType, + ObserveCallback& callback); +#endif + + OCStackResult GetDefaultQos(QualityOfService& QoS); + + virtual OCStackResult FindDirectPairingDevices(unsigned short waittime, + GetDirectPairedCallback& callback); + + virtual OCStackResult GetDirectPairedDevices(GetDirectPairedCallback& callback); + + virtual OCStackResult DoDirectPairing(std::shared_ptr peer, const OCPrm_t& pmSel, + const std::string& pinNumber, DirectPairingCallback& resultCallback); + +#ifdef WITH_MQ + virtual OCStackResult ListenForMQTopic( + const OCDevAddr& devAddr, + const std::string& resourceUri, + const QueryParamsMap& queryParams, const HeaderOptions& headerOptions, + MQTopicCallback& callback, QualityOfService QoS); + + virtual OCStackResult PutMQTopicRepresentation( + const OCDevAddr& devAddr, + const std::string& uri, + const OCRepresentation& rep, + const QueryParamsMap& queryParams, const HeaderOptions& headerOptions, + MQTopicCallback& callback, QualityOfService QoS); +#endif + + private: + void listeningFunc(); + std::string assembleSetResourceUri(std::string uri, const QueryParamsMap& queryParams); + std::string assembleSetResourceUri(std::string uri, const QueryParamsList& queryParams); + OCPayload* assembleSetResourcePayload(const OCRepresentation& attributes); + OCHeaderOption* assembleHeaderOptions(OCHeaderOption options[], + const HeaderOptions& headerOptions); + void convert(const OCDPDev_t *list, PairedDevices& dpList); + std::thread m_listeningThread; + bool m_threadRun; + std::weak_ptr m_csdkLock; + + private: + PlatformConfig m_cfg; + }; +} + +#endif + diff --git a/inc/iotivity/InProcServerWrapper.h b/inc/iotivity/InProcServerWrapper.h new file mode 100644 index 0000000..0ea25e8 --- /dev/null +++ b/inc/iotivity/InProcServerWrapper.h @@ -0,0 +1,83 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_IN_PROC_SERVER_WRAPPER_H_ +#define OC_IN_PROC_SERVER_WRAPPER_H_ + +#include +#include + +#include + +namespace OC +{ + class InProcServerWrapper : public IServerWrapper + { + public: + InProcServerWrapper( + std::weak_ptr csdkLock, + PlatformConfig cfg); + virtual ~InProcServerWrapper(); + + virtual OCStackResult registerResource( + OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler& entityHandler, + uint8_t resourceProperty); + + virtual OCStackResult registerDeviceInfo( + const OCDeviceInfo deviceInfo); + + virtual OCStackResult registerPlatformInfo( + const OCPlatformInfo PlatformInfo); + + virtual OCStackResult unregisterResource( + const OCResourceHandle& resourceHandle); + + virtual OCStackResult bindTypeToResource( + const OCResourceHandle& resourceHandle, + const std::string& resourceTypeName); + + virtual OCStackResult bindInterfaceToResource( + const OCResourceHandle& resourceHandle, + const std::string& resourceInterface); + + virtual OCStackResult startPresence(const unsigned int seconds); + + virtual OCStackResult stopPresence(); + + virtual OCStackResult setDefaultDeviceEntityHandler(EntityHandler entityHandler); + + virtual OCStackResult sendResponse(const std::shared_ptr pResponse); + + virtual OCStackResult setPropertyValue(OCPayloadType type, const std::string& tag, const std::string& value); + virtual OCStackResult getPropertyValue(OCPayloadType type, const std::string& tag, std::string& value); + + private: + void processFunc(); + std::thread m_processThread; + bool m_threadRun; + std::weak_ptr m_csdkLock; + }; +} + +#endif diff --git a/inc/iotivity/InitializeException.h b/inc/iotivity/InitializeException.h new file mode 100644 index 0000000..ab5282f --- /dev/null +++ b/inc/iotivity/InitializeException.h @@ -0,0 +1,39 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_INITIALIZE_EXCEPTION_H_ +#define OC_INITIALIZE_EXCEPTION_H_ + +#include +#include "StringConstants.h" + +namespace OC +{ + class InitializeException : public OC::OCException + { + public: + InitializeException(const std::string& msg, OCStackResult reasonCode): + OC::OCException(msg, reasonCode) + { + } + }; +} + +#endif diff --git a/inc/iotivity/OCAccountManager.h b/inc/iotivity/OCAccountManager.h new file mode 100644 index 0000000..11fa50b --- /dev/null +++ b/inc/iotivity/OCAccountManager.h @@ -0,0 +1,356 @@ +/* **************************************************************** + * + * Copyright 2016 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#ifndef OC_ACCOUNT_MANAGER_H_ +#define OC_ACCOUNT_MANAGER_H_ + +#include + +#include +#include +#include + +namespace OC +{ + class OCAccountManager + { + friend class OCPlatform_impl; + + public: + typedef std::shared_ptr Ptr; + + OCAccountManager(OCAccountManager&&) = default; + OCAccountManager(const OCAccountManager&) = delete; + OCAccountManager& operator=(OCAccountManager&&) = delete; + OCAccountManager& operator=(const OCAccountManager&) = delete; + + virtual ~OCAccountManager(void); + + /** + * Function to get the host address of account server. + * + * @return std::string host address + */ + std::string host() const; + + /** + * Function to get the connectivity type for account server. + * + * @return enum connectivity type (flags and adapter) + */ + OCConnectivityType connectivityType() const; + + /** + * Function for account registration to account server. + * + * @param authProvider Provider name used for authentication. + * @param authCode The authorization code obtained by using an authorization server + * as an intermediary between the client and resource owner. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult signUp(const std::string& authProvider, + const std::string& authCode, + PostCallback cloudConnectHandler); + + /** + * Overload + * + * @param authProvider Provider name used for authentication. + * @param authCode The authorization code obtained by using an authorization server + * as an intermediary between the client and resource owner. + * @param options The option values depends on auth provider. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult signUp(const std::string& authProvider, + const std::string& authCode, + const QueryParamsMap& options, + PostCallback cloudConnectHandler); + + /** + * Function for sign-in to account server. + * + * @param userUuid Identifier of the user obtained by account registration. + * @param accessToken Identifier of the resource obtained by account registration. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult signIn(const std::string& userUuid, + const std::string& accessToken, + PostCallback cloudConnectHandler); + + /** + * Function for sign-out to account server. + * + * @param accessToken Identifier of the resource obtained by account registration. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult signOut(const std::string& accessToken, + PostCallback cloudConnectHandler); + + /** + * Function for refresh access token to account server. + * + * @param userUuid Identifier of the user obtained by account registration. + * @param refreshToken Refresh token used for access token refresh. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult refreshAccessToken(const std::string& userUuid, + const std::string& refreshToken, + PostCallback cloudConnectHandler); + + /** + * Function to get information of the user to account server. + * + * @param queryParams Map that has a query key and value for specific users. + * Account server can response information of more than one user. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult searchUser(const QueryParamsMap& queryParams, + GetCallback cloudConnectHandler); + + /** + * Function to delete the device registered on the account signed-in. + * + * @param accessToken Identifier of the resource obtained by account registration. + * @param deviceId Device ID to delete. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult deleteDevice(const std::string& accessToken, + const std::string& deviceId, + DeleteCallback cloudConnectHandler); + + /** + * Function to create a group on account server. + * + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult createGroup(PostCallback cloudConnectHandler); + + /** + * Overload + * + * @param queryParams Map that has optional properties and values to create a group. + * Defined properties on the OCF spec are [gname, parent] so far. + * (2016/10/19) + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult createGroup(const QueryParamsMap& queryParams, + PostCallback cloudConnectHandler); + + /** + * Function to delete the group from account server. + * + * @param groupId Group ID to delete. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult deleteGroup(const std::string& groupId, + DeleteCallback cloudConnectHandler); + + /** + * Function to get infomation of all your group from account server. + * + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + + OCStackResult getGroupInfoAll(GetCallback cloudConnectHandler); + + /** + * Function to get information of the specific group from account server. + * + * @param groupId Group ID to get information. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult getGroupInfo(const std::string& groupId, + GetCallback cloudConnectHandler); + + /** + * Function to add values for properties to the group on account server. + * + * @param groupId Group ID to add property values. + * @param propertyValue OCRepresentation info that has pairs of property and value. + * Defined properties on the OCF spec are [members, masters, devices, + * resources, links] so far. (2016/10/19) + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult addPropertyValueToGroup(const std::string& groupId, + const OCRepresentation propertyValue, + PostCallback cloudConnectHandler); + + /** + * Function to delete values for properties from the group on account server. + * + * @param groupId Group ID to delete information. + * @param propertyValue OCRepresentation info that has pairs of property and value. + * Defined properties on the OCF spec are [members, masters, devices, + * resources, links] so far. (2016/10/19) + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult deletePropertyValueFromGroup(const std::string& groupId, + const OCRepresentation propertyValue, + PostCallback cloudConnectHandler); + + /** + * Function to update values for properties on the group on account server. + * It completely replaces existing values for specific properties. + * + * @param groupId Group ID to add devices. + * @param propertyValue OCRepresentation info that has pairs of property and value. + * Defined properties on the OCF spec are [members, gname, owner, + * masters, devices, resources, latitude, longitude, radius, + * backgroundImage] so far. (2016/10/19) + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult updatePropertyValueOnGroup(const std::string& groupId, + const OCRepresentation propertyValue, + PostCallback cloudConnectHandler); + + /** + * Function to register observe to group resource on account server. + * You can receive a notify when any value of property get changed in the group you joined. + * + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult observeGroup(ObserveCallback cloudConnectHandler); + + /** + * Function to cancel observe to group resource on account server. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult cancelObserveGroup(); + + /** + * Function to register observe to invitation resource on account server. + * You can receive a notify when you send or receive a invitation. + * Sending a invitation will be notified as 'invite' and Receiving will be as 'invited'. + * If you receive a invitation from other user, you should call 'replyToInvitation' to + * delete the invitation on account server, otherwise it will remain on the server. + * + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult observeInvitation(ObserveCallback cloudConnectHandler); + + /** + * Function to cancel observe to invitation resource on account server. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult cancelObserveInvitation(); + + /** + * Function to send a invitation to invite a user into a group. + * + * @param groupId Group ID for inviting. + * @param userUuid Identifier of the user to invite. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult sendInvitation(const std::string& groupId, + const std::string& userUuid, + PostCallback cloudConnectHandler); + + /** + * Function to cancel a invitation you has sent on account server before the invited user + * replies. + * + * @param groupId Group ID to cancel a invitation. + * @param userUuid Identifier of the user to cancel a invitation. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult cancelInvitation(const std::string& groupId, + const std::string& userUuid, + DeleteCallback cloudConnectHandler); + + /** + * Function to reply to the invitation that you has received. + * If you set accept as true, you will join the group as a member and the invitation + * will be deleted on account server. + * If false, only the invitation will be deleted. + * + * @param groupId Group ID to delete a invitation. + * @param accept boolean whether to join the group or not. + * @param cloudConnectHandler Callback function that will get the result of the operation. + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult replyToInvitation(const std::string& groupId, + const bool accept, + DeleteCallback cloudConnectHandler); + + private: + std::weak_ptr m_clientWrapper; + std::string m_deviceID; + std::string m_host; + std::string m_userUuid; + OCDoHandle m_invitationObserveHandle; + OCDoHandle m_groupObserveHandle; + OCConnectivityType m_connType; + QualityOfService m_defaultQos; + + private: + OCAccountManager(std::weak_ptr clientWrapper, + const std::string& host, + OCConnectivityType connectivityType); + + OCStackResult signInOut(const std::string& userUuid, + const std::string& accessToken, + bool isSignIn, + PostCallback cloudConnectHandler); + }; +} // namespace OC + +#endif // OC_ACCOUNT_MANAGER_H_ + diff --git a/inc/iotivity/OCApi.h b/inc/iotivity/OCApi.h new file mode 100644 index 0000000..ff2d212 --- /dev/null +++ b/inc/iotivity/OCApi.h @@ -0,0 +1,306 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_OCAPI_H_ +#define OC_OCAPI_H_ + +#include +#include +#include +#include +#include +#include +#if defined(_MSC_VER) +#include +#endif + +#include "octypes.h" +#include "OCHeaderOption.h" +#include +#include "StringConstants.h" +#include "oc_logger.hpp" + +#include + +namespace OC +{ + class OCResource; + class OCResourceRequest; + class OCResourceResponse; + class OCDirectPairing; +} // namespace OC + +namespace OC +{ +#if defined(_MSC_VER) + extern std::ostream& oclog(); +#else + typedef boost::iostreams::stream log_target_t; + + namespace detail + { + /* We'll want to provide some sort of explicit hook for custom logging at some + point; until then, this should do nicely (note that since these are lambdas, + later a special target could be captured, allowing much flexibility): */ + auto oclog_target = []() -> log_target_t& + { + static OC::oc_log_stream ols(oc_make_ostream_logger); + static log_target_t os(ols); + + return os; + }; + } // namespace OC::detail + + auto oclog = []() -> boost::iostreams::stream& + { + return detail::oclog_target(); + }; +#endif +} // namespace OC + +namespace OC +{ + + enum class OCPlatformStatus + { + PlatformUp, + PlatformDown + }; + + enum class OCAdvertisementStatus + { + None + }; + + typedef std::string URI; + + enum class ServiceType + { + InProc, + OutOfProc + }; + + /** + * Host Mode of Operation. + */ + enum class ModeType + { + Server, + Client, + Both, + Gateway /**< Client server mode along with routing capabilities.*/ + }; + + /** + * Quality of Service attempts to abstract the guarantees provided by the underlying transport + * protocol. The precise definitions of each quality of service level depend on the + * implementation. In descriptions below are for the current implementation and may changed + * over time. + */ + enum class QualityOfService : uint8_t + { + /** Packet delivery is best effort. */ + LowQos = OC_LOW_QOS, + + /** Packet delivery is best effort. */ + MidQos = OC_MEDIUM_QOS, + + /** Acknowledgments are used to confirm delivery. */ + HighQos = OC_HIGH_QOS, + + /** No Quality is defined, let the stack decide. */ + NaQos = OC_NA_QOS + }; + + /** + * Data structure to provide the configuration. + */ + struct PlatformConfig + { + /** indicate InProc or OutOfProc. */ + ServiceType serviceType; + + /** indicate whether we want to do server, client or both. */ + ModeType mode; + + /** default flags for server. */ + OCConnectivityType serverConnectivity; + + /** default flags for client. */ + OCConnectivityType clientConnectivity; + + /** not used. */ + std::string ipAddress; + + /** not used. */ + uint16_t port; + + /** indicate Quality of Service : LowQos, MidQos,HighQos and NaQos(No quality Defined). */ + QualityOfService QoS; + + /** persistant storage Handler structure (open/read/write/close/unlink). */ + OCPersistentStorage *ps; + + public: + PlatformConfig() + : serviceType(ServiceType::InProc), + mode(ModeType::Both), + serverConnectivity(CT_DEFAULT), + clientConnectivity(CT_DEFAULT), + ipAddress("0.0.0.0"), + port(0), + QoS(QualityOfService::NaQos), + ps(nullptr) + {} + PlatformConfig(const ServiceType serviceType_, + const ModeType mode_, + OCConnectivityType serverConnectivity_, + OCConnectivityType clientConnectivity_, + const QualityOfService QoS_, + OCPersistentStorage *ps_ = nullptr) + : serviceType(serviceType_), + mode(mode_), + serverConnectivity(serverConnectivity_), + clientConnectivity(clientConnectivity_), + ipAddress(""), + port(0), + QoS(QoS_), + ps(ps_) + {} + // for backward compatibility + PlatformConfig(const ServiceType serviceType_, + const ModeType mode_, + const std::string& ipAddress_, + const uint16_t port_, + const QualityOfService QoS_, + OCPersistentStorage *ps_ = nullptr) + : serviceType(serviceType_), + mode(mode_), + serverConnectivity(CT_DEFAULT), + clientConnectivity(CT_DEFAULT), + ipAddress(ipAddress_), + port(port_), + QoS(QoS_), + ps(ps_) + {} + }; + + enum RequestHandlerFlag + { + RequestFlag = 1 << 1, + ObserverFlag = 1 << 2 + }; + + enum class ObserveType + { + Observe, + ObserveAll + }; + + // Typedef for list of resource handles. + typedef std::vector ResourceHandles; + + // Typedef for header option vector. + // OCHeaderOption class is in HeaderOption namespace. + typedef std::vector HeaderOptions; + + // Typedef for query parameter map. + typedef std::map QueryParamsMap; + + // Typedef for query parameter map with Vector + typedef std::map< std::string, std::vector > QueryParamsList; + + // Typedef for list of observation IDs. + typedef std::vector ObservationIds; + + enum class ObserveAction + { + ObserveRegister, + ObserveUnregister + }; + + typedef struct + { + // Action associated with observation request + ObserveAction action; + // Identifier for observation being registered/unregistered + OCObservationId obsId; + + OCConnectivityType connectivityType; + std::string address; + uint16_t port; + } ObservationInfo; + + // const strings for different interfaces + + // Default interface + const std::string DEFAULT_INTERFACE = "oic.if.baseline"; + + // Used in discovering (GET) links to other resources of a collection. + const std::string LINK_INTERFACE = "oic.if.ll"; + + // Used in GET, PUT, POST, DELETE methods on links to other resources of a collection. + const std::string BATCH_INTERFACE = "oic.if.b"; + + // Used in GET, PUT, POST methods on links to other remote resources of a group. + const std::string GROUP_INTERFACE = "oic.mi.grp"; + + //Typedef for list direct paired devices + typedef std::vector> PairedDevices; + + typedef std::function)> FindCallback; + + typedef std::function FindErrorCallback; + + typedef std::function>)> FindResListCallback; + + typedef std::function FindDeviceCallback; + + typedef std::function FindPlatformCallback; + + typedef std::function)> EntityHandler; + + typedef std::function SubscribeCallback; + + typedef std::function GetCallback; + + typedef std::function PostCallback; + + typedef std::function PutCallback; + + typedef std::function DeleteCallback; + + typedef std::function ObserveCallback; + + typedef std::function, OCStackResult)> DirectPairingCallback; + + typedef std::function GetDirectPairedCallback; + + typedef std::function)> MQTopicCallback; +} // namespace OC + +#endif diff --git a/inc/iotivity/OCCloudProvisioning.hpp b/inc/iotivity/OCCloudProvisioning.hpp new file mode 100755 index 0000000..491f68a --- /dev/null +++ b/inc/iotivity/OCCloudProvisioning.hpp @@ -0,0 +1,139 @@ +//**************************************************************** +// +// Copyright 2016 Samsung Electronics All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_CLOUD_PROVISIONING_CXX_H_ +#define OC_CLOUD_PROVISIONING_CXX_H_ + +#include + +#include "occloudprovisioning.h" +#include "OCApi.h" +#include "OCPlatform_impl.h" +#include "CAManager.h" + +namespace OC +{ + typedef std::function ResponseCallBack; + typedef std::function AclIdResponseCallBack; + + /** + * Context to be passed to the underlying stack. This is passed back as argument + * to the callback function + */ + struct CloudProvisionContext + { + ResponseCallBack callback; + CloudProvisionContext(ResponseCallBack cb) : callback(cb){} + }; + + struct AclIdContext + { + AclIdResponseCallBack callback; + AclIdContext(AclIdResponseCallBack cb) : callback(cb){} + }; + + class OCCloudProvisioning + { + + private: + OCDevAddr m_devAddr; + public: + + /** + * API to construct the CloudProvisioning + * @param ipAddr address of the cloud server + * @param port port of the cloud server + */ + OCCloudProvisioning(std::string& ipAddr, uint16_t port); + ~OCCloudProvisioning(); + + void setIpAddr(std::string& ipAddr) + { + memcpy(m_devAddr.addr, ipAddr.c_str(), MAX_ADDR_STR_SIZE); + } + + void setPort(uint16_t port) + { + m_devAddr.port = port; + } + + /** + * API to Request a certificate from the cloud + * @param callback function called by the stack on completion of request + * @return ::OC_STACK_OK on Success and other values otherwise + */ + OCStackResult requestCertificate(ResponseCallBack callback); + + /** + * API to get ACL ID for the device + * @param deviceId device ID for which the Acl ID is requested + * @param callback function called by the stack on completion of request + * @return ::OC_STACK_OK on Success and other values otherwise + */ + OCStackResult getAclIdByDevice(const std::string& deviceId, AclIdResponseCallBack callback); + + /** + * API to get ACL information about the given Acl ID + * @param aclId ACL ID for which the Acl information is requested + * @param callback function called by the stack on completion of request + * @return ::OC_STACK_OK on Success and other values otherwise + */ + OCStackResult getIndividualAclInfo(const std::string& aclId, ResponseCallBack callback); + + /** + * API to get certificate revocation list + * @param callback function called by the stack on completion of request + * @return ::OC_STACK_OK on Success and other values otherwise + */ + OCStackResult getCRL(ResponseCallBack callback); + + /** + * API to post the certificate revocation list to cloud + * @param thisUpdate thisUpdate [mandatory param] + * @param nextUpdate nextUpdate [mandatory param] + * @param crl revocation list [optional] + * @param serialNumbers [optional] + * @param callback function called by the stack on completion of request + * @return ::OC_STACK_OK on Success and other values otherwise + */ + OCStackResult postCRL(const std::string& thisUpdate, + const std::string& nextUpdate, + const OCByteString *crl, + const stringArray_t *serialNumbers, + ResponseCallBack callback); + + /** + * Common callback wrapper for all the callback functions. + * @param ctx user context passed to the request API + * @param result result of the request performed + * @param data response data + */ + static void callbackWrapper(void* ctx, OCStackResult result, void* data); + + /** + * Callback wrapper for Acl ID get request + * @param ctx user context passed to the request API + * @param result result of the request performed + * @param data AclID for the device + */ + static void aclIdResponseWrapper(void* ctx, OCStackResult result, void* data); + }; +} +#endif //OC_CLOUD_PROVISIONING_CXX_H_ diff --git a/inc/iotivity/OCDirectPairing.h b/inc/iotivity/OCDirectPairing.h new file mode 100644 index 0000000..3f27b83 --- /dev/null +++ b/inc/iotivity/OCDirectPairing.h @@ -0,0 +1,69 @@ +//****************************************************************** +// +// Copyright 2016 Samsung Electronics All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_DIRECT_PAIRING_H_ +#define OC_DIRECT_PAIRING_H_ +#include + +namespace OC +{ + class OCDirectPairing + { + public: + OCDirectPairing(OCDPDev_t *ptr); + /** + * Function to get the host address of direct pairing device. + * + * @return Returns host address in the format + * :IP:securePort + */ + std::string getHost(); + + /** + * Function to get the device ID of the direct pairing device. + * + * @return Returns device ID (UUID) + */ + std::string getDeviceID(); + + /** + * Function to get the pairing methods supported by direct pairing device. + * + * @return Returns vector of pairing methods supported. + * DP_NOT_ALLOWED + * DP_PRE_CONFIGURED + * DP_RANDOM_PIN + */ + std::vector getPairingMethods(); + + /** + * Function to get the connectivity Type. + * + * @return Returns connectivity Type + */ + OCConnectivityType getConnType(); + + OCDPDev_t* getDev(); + + private: + OCDPDev_t *m_devPtr; + }; +} +#endif //OC_DIRECT_PAIRING_H_ diff --git a/inc/iotivity/OCException.h b/inc/iotivity/OCException.h new file mode 100644 index 0000000..1d70e7d --- /dev/null +++ b/inc/iotivity/OCException.h @@ -0,0 +1,56 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_EXCEPTION_H_ +#define OC_EXCEPTION_H_ + +#include +#include +#include + +namespace OC { + +class OCException : public std::runtime_error +{ + public: + OCException(const std::string& msg, OCStackResult reason = OC_STACK_ERROR) + : std::runtime_error(msg), + m_reason(reason) + {} + + static std::string reason(const OCStackResult sr); + + std::string reason() const + { + return reason(m_reason); + } + + OCStackResult code() const + { + return m_reason; + } + + private: + OCStackResult m_reason; +}; + +} // namespace OC + +#endif diff --git a/inc/iotivity/OCHeaderOption.h b/inc/iotivity/OCHeaderOption.h new file mode 100644 index 0000000..78f9029 --- /dev/null +++ b/inc/iotivity/OCHeaderOption.h @@ -0,0 +1,124 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/** + * @file + * + * This file contains the declaration of classes and its members related to + * OCHeaderOption. + */ + +#ifndef OC_HEADEROPTION_H_ +#define OC_HEADEROPTION_H_ + +#include +#include +namespace OC +{ + namespace HeaderOption + { + /** + * @brief OCHeaderOption class allows to create instances which comprises optionID + * and optionData as members. These are used in setting Header options. + * After creating instances of OCHeaderOptions, use setHeaderOptions API + * (in OCResource.h) to set header Options. + * NOTE: HeaderOptionID is an unsigned integer value which MUST be within + * range of 2048 to 3000 inclusive of lower and upper bound + * except for If-Match with empty(num : 1), If-None-Match(num : 5), + * Location-Path(num : 8), Location-Query(num : 20) option. + * HeaderOptions instance creation fails if above condition is not satisfied. + */ + const uint16_t MIN_HEADER_OPTIONID = 2048; + const uint16_t MAX_HEADER_OPTIONID = 3000; + const uint16_t IF_MATCH_OPTION_ID = 1; + const uint16_t IF_NONE_MATCH_OPTION_ID = 5; + const uint16_t LOCATION_PATH_OPTION_ID = 8; + const uint16_t LOCATION_QUERY_OPTION_ID = 20; + + class OCHeaderOption + { + private: + uint16_t m_optionID; + std::string m_optionData; + + public: + /** + * OCHeaderOption constructor + */ + OCHeaderOption(uint16_t optionID, std::string optionData): + m_optionID(optionID), + m_optionData(optionData) + { + if (!(optionID >= MIN_HEADER_OPTIONID && optionID <= MAX_HEADER_OPTIONID) + && optionID != IF_MATCH_OPTION_ID + && optionID != IF_NONE_MATCH_OPTION_ID + && optionID != LOCATION_PATH_OPTION_ID + && optionID != LOCATION_QUERY_OPTION_ID) + { + throw OCException(OC::Exception::OPTION_ID_RANGE_INVALID); + } + } + + virtual ~OCHeaderOption(){} + + OCHeaderOption(const OCHeaderOption&) = default; + +#if defined(_MSC_VER) && (_MSC_VER < 1900) + OCHeaderOption(OCHeaderOption&& o) + { + std::memmove(this, &o, sizeof(o)); + } +#else + OCHeaderOption(OCHeaderOption&&) = default; +#endif + + OCHeaderOption& operator=(const OCHeaderOption&) = default; + +#if defined(_MSC_VER) && (_MSC_VER < 1900) + OCHeaderOption& operator=(OCHeaderOption&& o) + { + std::memmove(this, &o, sizeof(o)); + } +#else + OCHeaderOption& operator=(OCHeaderOption&&) = default; +#endif + + /** + * API to get Option ID + * @return unsigned integer option ID + */ + uint16_t getOptionID() const + { + return m_optionID; + } + + /* + * API to get Option data + * @return std::string of option data + */ + std::string getOptionData() const + { + return m_optionData; + } + }; + } // namespace HeaderOption +} // namespace OC + +#endif // OC_HEADEROPTION_H_ diff --git a/inc/iotivity/OCPlatform.h b/inc/iotivity/OCPlatform.h new file mode 100644 index 0000000..9903611 --- /dev/null +++ b/inc/iotivity/OCPlatform.h @@ -0,0 +1,707 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/** + * @file + * + * This file contains the declaration of classes and its members related to + * OCPlatform. + */ + +#ifndef OC_PLATFORM_H_ +#define OC_PLATFORM_H_ +#include +#include +namespace OC +{ + /** + * This namespace contains the main entrance/functionality of the product. + * It may be used with OC::OCPlatform::functionName. To set a custom configuration, + * the implementer must make a call to OCPlatform::Configure before the first usage + * of a function in this namespace. + */ + namespace OCPlatform + { + /** + * API for overwriting the default configuration of the OCPlatform object. + * @note Any calls made to this AFTER the first call to OCPlatform::Instance + * will have no affect + */ + void Configure(const PlatformConfig& config); + + // typedef for handle to cancel presence info with + typedef OCDoHandle OCPresenceHandle; + + /** + * API for notifying base that resource's attributes have changed. + * + * @param resourceHandle resource handle of the resource + * + * @return Returns ::OC_STACK_OK if success. + * @note This API is for server side only. + * @note OCResourceHandle is defined in ocstack.h + * @note OCStackResult is defined in ocstack.h. + * @see notifyAllObservers(OCResourceHandle, QualityOfService) + */ + OCStackResult notifyAllObservers(OCResourceHandle resourceHandle); + + /** + * @overload + * + * @param resourceHandle resource handle of the resource + * @param QoS the quality of communication + * @see notifyAllObservers(OCResourceHandle) + */ + OCStackResult notifyAllObservers(OCResourceHandle resourceHandle, QualityOfService QoS); + + /** + * API for notifying only specific clients that resource's attributes have changed. + * + * @param resourceHandle resource handle of the resource + * @param observationIds std vector of observationIds. These set of ids are ones which + * which will be notified upon resource change. + * @param responsePtr OCResourceResponse pointer used by app to fill the response for this + * resource change. + * + * @return Returns ::OC_STACK_OK if success. + * @note This API is for server side only. + * @note OCResourceHandle is defined in ocstack.h. + * @note OCStackResult is defined in ocstack.h. + * @see notifyListOfObservers(OCResourceHandle, ObservationIds&, const std::shared_ptr, QualityOfService) + */ + OCStackResult notifyListOfObservers( + OCResourceHandle resourceHandle, + ObservationIds& observationIds, + const std::shared_ptr responsePtr); + /** + * @overload + * + * @param resourceHandle resource handle of the resource + * @param observationIds std vector of observationIds. These set of ids are ones which + * which will be notified upon resource change. + * @param responsePtr OCResourceResponse pointer used by app to fill the response for this + * resource change. + * @param QoS the quality of communication + * @see notifyListOfObservers(OCResourceHandle, ObservationIds&, const std::shared_ptr) + */ + OCStackResult notifyListOfObservers( + OCResourceHandle resourceHandle, + ObservationIds& observationIds, + const std::shared_ptr responsePtr, + QualityOfService QoS); + + /** + * API for Service and Resource Discovery. + * @note This API applies to client side only. + * + * @param host Host IP Address of a service to direct resource discovery query. If null or + * empty, performs multicast resource discovery query + * @param resourceURI name of the resource. If null or empty, performs search for all + * resource names + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * @param resourceHandler Handles callbacks, success states and failure states. + * + * Four modes of discovery defined as follows: + * (NULL/Empty, NULL/Empty) - Performs ALL service discovery AND ALL resource + * discovery. + * (NULL/Empty, Not Empty) - Performs query for a filtered/scoped/particular + * resource(s) from ALL services. + * (Not Empty, NULL/Empty) - Performs ALL resource discovery on a particular service. + * (Not Empty, Not Empty) - Performs query for a filtered/scoped/particular + * resource(s) + * from a particular service. + * + * @return Returns ::OC_STACK_OK if success. + * @note First parameter 'host' currently represents an IP address. This will change in + * future and will refer to endpoint interface so that we can refer to other transports such + * as BTH etc. + * @note OCStackResult is defined in ocstack.h. + * @see findResource(const std::string&, const std::string&, OCConnectivityType, FindCallback, QualityOfService) + */ + OCStackResult findResource(const std::string& host, const std::string& resourceURI, + OCConnectivityType connectivityType, FindCallback resourceHandler); + /** + * @overload + * + * @param host Host IP Address of a service to direct resource discovery query. If null or + * empty, performs multicast resource discovery query + * @param resourceURI name of the resource. If null or empty, performs search for all + * resource names + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * @param resourceHandler Handles callbacks, success states and failure states. + * + * Four modes of discovery defined as follows: + * (NULL/Empty, NULL/Empty) - Performs ALL service discovery AND ALL resource + * discovery. + * (NULL/Empty, Not Empty) - Performs query for a filtered/scoped/particular + * resource(s) from ALL services. + * (Not Empty, NULL/Empty) - Performs ALL resource discovery on a particular service. + * (Not Empty, Not Empty) - Performs query for a filtered/scoped/particular + * resource(s) + * from a particular service. + * @param QoS QualityOfService the quality of communication + * @see findResource(const std::string&, const std::string&, OCConnectivityType, FindCallback) + */ + OCStackResult findResource(const std::string& host, const std::string& resourceURI, + OCConnectivityType connectivityType, FindCallback resourceHandler, + QualityOfService QoS); + + OCStackResult findResource(const std::string& host, const std::string& resourceURI, + OCConnectivityType connectivityType, FindCallback resourceHandler, + FindErrorCallback errorHandler); + + OCStackResult findResource(const std::string& host, const std::string& resourceURI, + OCConnectivityType connectivityType, FindCallback resourceHandler, + FindErrorCallback errorHandler, QualityOfService QoS); + + OCStackResult findResourceList(const std::string& host, const std::string& resourceURI, + OCConnectivityType connectivityType, FindResListCallback resourceHandler, + QualityOfService QoS = QualityOfService::LowQos); + + OCStackResult setPropertyValue(OCPayloadType type, const std::string& tag, const std::string& value); + OCStackResult setPropertyValue(OCPayloadType type, const std::string& tag, const std::vector& value); + OCStackResult getPropertyValue(OCPayloadType type, const std::string& tag, std::string& value); + OCStackResult getPropertyValue(OCPayloadType type, const std::string& tag, std::vector& value); + /** + * API for Device Discovery + * + * + * @param host Host IP Address. If null or empty, Multicast is performed. + * @param deviceURI Uri containing address to the virtual device in C Stack + ("/oic/d") + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * @param deviceInfoHandler device discovery callback + * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + * @see getDeviceInfo(const std::string&, const std::string&, OCConnectivityType, FindDeviceCallback, QualityOfService) + */ + OCStackResult getDeviceInfo(const std::string& host, const std::string& deviceURI, + OCConnectivityType connectivityType, FindDeviceCallback deviceInfoHandler); + /** + * @overload + * + * @param host Host IP Address. If null or empty, Multicast is performed. + * @param deviceURI Uri containing address to the virtual device in C Stack + ("/oic/d") + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * @param deviceInfoHandler device discovery callback + * @param QoS the quality of communication + * @see getDeviceInfo(const std::string&, const std::string&, OCConnectivityType, FindDeviceCallback) + */ + OCStackResult getDeviceInfo(const std::string& host, const std::string& deviceURI, + OCConnectivityType connectivityType, FindDeviceCallback deviceInfoHandler, + QualityOfService QoS); + + /** + * API for Platform Discovery + * + * + * @param host Host IP Address. If null or empty, Multicast is performed. + * @param platformURI Uri containing address to the virtual platform in C Stack + ("/oic/p") + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * @param platformInfoHandler platform discovery callback + * + * @return Returns ::OC_STACK_OK if success. + * + * @note OCStackResult is defined in ocstack.h. + * @see getPlatformInfo(const std::string&, const std::string&, OCConnectivityType, FindPlatformCallback, QualityOfService) + */ + OCStackResult getPlatformInfo(const std::string& host, const std::string& platformURI, + OCConnectivityType connectivityType, FindPlatformCallback platformInfoHandler); + /** + * @overload + * + * @param host Host IP Address. If null or empty, Multicast is performed. + * @param platformURI Uri containing address to the virtual platform in C Stack + ("/oic/p") + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * @param platformInfoHandler platform discovery callback + * @param QoS the quality of communication + * @see getPlatformInfo(const std::string&, const std::string&, OCConnectivityType, FindPlatformCallback) + */ + OCStackResult getPlatformInfo(const std::string& host, const std::string& platformURI, + OCConnectivityType connectivityType, FindPlatformCallback platformInfoHandler, + QualityOfService QoS); + + /** + * This API registers a resource with the server + * @note This API applies to server side only. + * + * @param resourceHandle Upon successful registration, resourceHandle will be filled + * @param resourceURI The URI of the resource. Example: "a/light". See NOTE below + * @param resourceTypeName The resource type. Example: "light" + * @param resourceInterface The resource interface (whether it is collection etc). + * @param entityHandler entity handler callback. + * @param resourceProperty indicates the property of the resource. Defined in ocstack.h. + * setting resourceProperty as OC_DISCOVERABLE will allow Discovery of this resource + * setting resourceProperty as OC_OBSERVABLE will allow observation + * settings resourceProperty as OC_DISCOVERABLE | OC_OBSERVABLE will allow both discovery and + * observation + * + * @return Returns ::OC_STACK_OK if success. + * @note "a/light" is a relative URI. + * Above relative URI will be prepended (by core) with a host IP + namespace "oic" + * Therefore, fully qualified URI format would be //HostIP-Address/namespace/relativeURI" + * Example, a relative URI: 'a/light' will result in a fully qualified URI: + * //192.168.1.1/oic/a/light" + * First parameter can take a relative URI and core will take care of preparing the fully + * qualified URI OR + * first parameter can take fully qualified URI and core will take that as is for further + * operations + * @note OCStackResult is defined in ocstack.h. + * @note entity handler callback : + * When you set specific return value like OC_EH_CHANGED, OC_EH_CONTENT, + * OC_EH_SLOW and etc in entity handler callback, + * ocstack will be not send response automatically to client + * except for error return value like OC_EH_ERROR + * If you want to send response to client with specific result, + * OCDoResponse API should be called with the result value. + */ + OCStackResult registerResource(OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler entityHandler, + uint8_t resourceProperty); + + /** + * This API registers a resource with the server + * @note This API applies to server & client side. + * + * @param resourceHandle Upon successful registration, resourceHandle will be filled + * @param resource The instance of OCResource that all data filled. + * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + */ + OCStackResult registerResource(OCResourceHandle& resourceHandle, + const std::shared_ptr< OCResource > resource); + + /** + * Register Device Info + * + * @param deviceInfo structure containing all the device specific information + * @return Returns ::OC_STACK_OK if no errors and ::OC_STACK_ERROR in case of stack process error + */ + OCStackResult registerDeviceInfo(const OCDeviceInfo deviceInfo); + + /** + * Register Platform Info + * + * @param platformInfo structure containing all the platform specific information + * @return Returns ::OC_STACK_OK if no errors and ::OC_STACK_ERROR in case of stack process error + */ + OCStackResult registerPlatformInfo(const OCPlatformInfo platformInfo); + + /** + * Set default device entity handler + * + * @param entityHandler entity handler to handle requests for + * any undefined resources or default actions. + * if NULL is passed it removes the device default entity handler. + * @return Returns ::OC_STACK_OK if no errors and ::OC_STACK_ERROR in case of stack process error + * @note entity handler callback : + * When you set specific return value like OC_EH_CHANGED, OC_EH_CONTENT, + * OC_EH_SLOW and etc in entity handler callback, + * ocstack will be not send response automatically to client + * except for error return value like OC_EH_ERROR + * If you want to send response to client with specific result, + * sendResponse API should be called with the result value. + */ + OCStackResult setDefaultDeviceEntityHandler(EntityHandler entityHandler); + + /** + * This API unregisters a resource with the server + * @note This API applies to server side only. + * + * @param resourceHandle This is the resource handle which we need to unregister from the + * server + * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + */ + OCStackResult unregisterResource(const OCResourceHandle& resourceHandle); + + /** + * Add a resource to a collection resource. + * + * @param collectionHandle handle to the collection resource + * @param resourceHandle handle to resource to be added to the collection resource + * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + * @note bindResource must be used only after the both collection resource and + * resource to add under a collections are created and respective handles obtained + * + * @par Example: + * -# registerResource(homeResourceHandle, "a/home", "home", Link_Interface, + * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, + * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# bindResource(homeResourceHandle, kitchenResourceHandle); + * @par + * At the end of Step 3, resource "a/home" will contain a reference to "a/kitchen". + */ + OCStackResult bindResource(const OCResourceHandle collectionHandle, + const OCResourceHandle resourceHandle); + + /** + * Add multiple resources to a collection resource. + * + * @param collectionHandle handle to the collection resource + * @param addedResourceHandleList reference to list of resource handles to be added to the + * collection resource + * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + * @note bindResources must be used only after the both collection resource and + * list of resources to add under a collection are created and respective handles + * obtained. + * + * @par Example: + * -# registerResource(homeResourceHandle, "a/home", "home", Link_Interface, + * homeEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, + * kitchenEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(roomResourceHandle, "a/room", "room", Link_Interface, + * roomEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# std::vector rList; rList.push_back(kitchenResourceHandle); + * rList.push_back(roomResourceHandle); + * -# bindResource(homeResourceHandle, rList); + * @par + * At the end of Step 5, resource "a/home" will contain a references to "a/kitchen" and + * "a/room" + */ + OCStackResult bindResources(const OCResourceHandle collectionHandle, + const std::vector& addedResourceHandleList); + + /** + * Unbind a resource from a collection resource. + * + * @param collectionHandle handle to the collection resource + * @param resourceHandle resource handle to be unbound from the collection resource + * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + * @note unbindResource must be used only after the both collection resource and + * resource to unbind from a collection are created and respective handles obtained + * + * @par Example: + * -# registerResource(homeResourceHandle, "a/home", "home", Link_Interface, + * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, + * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# bindResource(homeResourceHandle, kitchenResourceHandle); + * -# unbindResource(homeResourceHandle, kitchenResourceHandle); + * @par + * At the end of Step 4, resource "a/home" will no longer reference "a/kitchen". + */ + OCStackResult unbindResource(const OCResourceHandle collectionHandle, + const OCResourceHandle resourceHandle); + + /** + * Unbind resources from a collection resource. + * + * @param collectionHandle handle to the collection resource + * @param resourceHandleList List of resource handles to be unbound from the collection + * resource + * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + * @note unbindResources must be used only after the both collection resource and + * list of resources resource to unbind from a collection are created and respective handles + * obtained. + * + * @par Example: + * -# registerResource(homeResourceHandle, "a/home", "home", Link_Interface, + * homeEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, + * kitchenEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(roomResourceHandle, "a/room", "room", Link_Interface, + * roomEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# std::vector rList; rList.push_back(kitchenResourceHandle); + * rList.push_back(roomResourceHandle); + * -# bindResource(homeResourceHandle, rList); + * -# unbindResources(homeResourceHandle, rList); + * @par + * At the end of Step 6, resource "a/home" will no longer reference to "a/kitchen" and + * "a/room" + */ + OCStackResult unbindResources(const OCResourceHandle collectionHandle, + const std::vector& resourceHandleList); + + /** + * Binds a type to a particular resource + * @param resourceHandle handle to the resource + * @param resourceTypeName new typename to bind to the resource + * + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult bindTypeToResource(const OCResourceHandle& resourceHandle, + const std::string& resourceTypeName); + + /** + * Binds an interface to a particular resource + * @param resourceHandle handle to the resource + * @param resourceInterfaceName new interface to bind to the resource + * + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult bindInterfaceToResource(const OCResourceHandle& resourceHandle, + const std::string& resourceInterfaceName); + + + /** + * Start Presence announcements. + * + * @param ttl time to live + * @par + * If ttl is '0', then the default stack value will be used (60 Seconds). + * If ttl is greater than OC_MAX_PRESENCE_TTL_SECONDS, then the ttl will be set to + * OC_MAX_PRESENCE_TTL_SECONDS. + * @par + * @return Returns ::OC_STACK_OK if success. + * + * Server can call this function when it comes online for the + * first time, or when it comes back online from offline mode, + * or when it re enters network. + * + */ + OCStackResult startPresence(const unsigned int ttl); + + /** + * Stop Presence announcements. + * + * @return Returns ::OC_STACK_OK if success. + * + * Server can call this function when it is terminating, + * going offline, or when going away from network. + * + */ + OCStackResult stopPresence(); + + /** + * subscribes to a server's presence change events. By making this subscription, + * every time a server adds/removes/alters a resource, starts or is intentionally + * stopped (potentially more to be added later). + * + * @param presenceHandle a handle object that can be used to identify this subscription + * request. It can be used to unsubscribe from these events in the future. + * It will be set upon successful return of this method. + * @param host The IP address/addressable name of the server to subscribe to. + * This should be in the format coap://address:port + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * @param presenceHandler callback function that will receive notifications/subscription + * events + * + * @return Returns ::OC_STACK_OK if success. + * @copydoc subscribePresence(OCPresenceHandle&, const std::string&, resourceType, OCConnectivityType, SubscribeCallback) + */ + OCStackResult subscribePresence(OCPresenceHandle& presenceHandle, const std::string& host, + OCConnectivityType connectivityType, SubscribeCallback presenceHandler); + /** + * @overload + * + * @param presenceHandle a handle object that can be used to identify this subscription + * request. It can be used to unsubscribe from these events in the future. + * It will be set upon successful return of this method. + * @param host The IP address/addressable name of the server to subscribe to. + * This should be in the format coap://address:port + * @param resourceType a resource type specified as a filter for subscription callbacks. + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * @param presenceHandler callback function that will receive notifications/subscription + * events + * @see subscribePresence(OCPresenceHandle&, const std::string&, OCConnectivityType, SubscribeCallback) + */ + OCStackResult subscribePresence(OCPresenceHandle& presenceHandle, const std::string& host, + const std::string& resourceType, OCConnectivityType connectivityType, + SubscribeCallback presenceHandler); + + /** + * unsubscribes from a previously subscribed server's presence events. Note that + * you may for a short time still receive events from the server since it may take time + * for the unsubscribe to take effect. + * + * @param presenceHandle the handle object provided by the subscribePresence call that + * identifies this subscription. + * + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult unsubscribePresence(OCPresenceHandle presenceHandle); + +#ifdef WITH_CLOUD + /** + * Subscribes to a server's device presence change events. + * + * @param presenceHandle a handle object that can be used to identify this subscription + * request. It can be used to unsubscribe from these events in the future. + * It will be set upon successful return of this method. + * @param host The IP address/addressable name of the server to subscribe to. + * This should be in the format coap://address:port + * @param di Vector which can have the devices id. + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * @param observeHandler handles callback + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this observe operation + * This will have error codes + * + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult subscribeDevicePresence(OCPresenceHandle& presenceHandle, + const std::string& host, + const std::vector& di, + OCConnectivityType connectivityType, + ObserveCallback callback); +#endif + + /** + * Creates a resource proxy object so that get/put/observe functionality + * can be used without discovering the object in advance. Note that the + * consumer of this method needs to provide all of the details required to + * correctly contact and observe the object. If the consumer lacks any of + * this information, they should discover the resource object normally. + * Additionally, you can only create this object if OCPlatform was initialized + * to be a Client or Client/Server. Otherwise, this will return an empty + * shared ptr. + * + * @param host a string containing a resolvable host address of the server + * holding the resource. Currently this should be in the format + * coap://address:port, though in the future, we expect this to + * change to //address:port + * + * @param uri the rest of the resource's URI that will permit messages to be + * properly routed. Example: /a/light + * + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * if you want to use a specific Flag like IPv4, + * you should apply OR operation for the flag in here. + * Example: static_cast(CT_ADAPTER_TCP + * | OC_IP_USE_V4) + * + * @param isObservable a boolean containing whether the resource supports observation + * + * @param resourceTypes a collection of resource types implemented by the resource + * + * @param interfaces a collection of interfaces that the resource supports/implements + * @return OCResource::Ptr a shared pointer to the new resource object + */ + OCResource::Ptr constructResourceObject(const std::string& host, + const std::string& uri, + OCConnectivityType connectivityType, bool isObservable, + const std::vector& resourceTypes, + const std::vector& interfaces); + + /** + * Allows application entity handler to send response to an incoming request. + * + * @param pResponse OCResourceResponse pointer that will permit to set values related + * to resource response. + * + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult sendResponse(const std::shared_ptr pResponse); + + /** + * Find all the Direct Pairing capable devices. + * + * @param waittime timeoutbefore the callback is called + * @param callback function to callback with discovered devices after timeout + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult findDirectPairingDevices(unsigned short waittime, + GetDirectPairedCallback callback); + + /** + * Get all the Direct paired devices. + * + * @param callback function to callback with the list of paired devices + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult getDirectPairedDevices(GetDirectPairedCallback callback); + + /** + * Perform the Direct Pairing with the selected peer device + * + * @param peer device to direct pair with + * @param pmSel Selected pairing method + * @param pinNumber pin to validate peer & perform the direct pairing + * @param resultCallback callback function that will get the result of the operation + * + * @return Returns ::OC_STACK_OK if success + */ + OCStackResult doDirectPairing(std::shared_ptr peer, OCPrm_t pmSel, + const std::string& pinNumber, + DirectPairingCallback resultCallback); +#ifdef WITH_CLOUD + /** + * Create an account manager object that can be used for doing request to account server. + * You can only create this object if OCPlatform was initialized to be a Client or + * Client/Server. Otherwise, this will return an empty shared ptr. + * + * @note For now, OCPlatform SHOULD be initialized to be a Client/Server(Both) for the + * methods of this object to work since device id is not generated on Client mode. + * + * @param host Host IP Address of a account server. + * @param connectivityType ::OCConnectivityType type of connectivity indicating the + * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * if you want to use a specific Flag like IPv4, + * you should apply OR operation for the flag in here. + * Example: static_cast(CT_ADAPTER_TCP + * | OC_IP_USE_V4) + * + * @return OCAccountManager::Ptr a shared pointer to the new account manager object + */ + OCAccountManager::Ptr constructAccountManagerObject(const std::string& host, + OCConnectivityType connectivityType); +#endif // WITH_CLOUD + + /** + * gets the deviceId of the client + * + * @param deviceId pointer. + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult getDeviceId(OCUUIdentity *deviceId); + + /** + * sets the deviceId of the client + * + * @param deviceId pointer. + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult setDeviceId(const OCUUIdentity *deviceId); + } +} + +#endif // OC_PLATFORM_H_ diff --git a/inc/iotivity/OCPlatform_impl.h b/inc/iotivity/OCPlatform_impl.h new file mode 100644 index 0000000..6adefc7 --- /dev/null +++ b/inc/iotivity/OCPlatform_impl.h @@ -0,0 +1,305 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/** + * @file + * + * Implementation of the OCPlatform functionality. It contains a singleton + * interface that is used only by the OCPlatform namespace and is the + * central entrance to the stack. + */ + +#ifndef OC_PLATFORM_IMPL_H_ +#define OC_PLATFORM_IMPL_H_ + +#include + +#include "OCApi.h" +#include "OCResource.h" +#include "WrapperFactory.h" +#include "OCResourceRequest.h" +#include "OCResourceResponse.h" +#include "OCRepresentation.h" +#include "OCDirectPairing.h" + +#ifdef WITH_CLOUD +#include "OCAccountManager.h" +#endif + +#include "oc_logger.hpp" + +namespace OC +{ + class OCPlatform_impl + { + private: + static PlatformConfig& globalConfig(); + public: + static void Configure(const PlatformConfig& config); + + static OCPlatform_impl& Instance(); + + public: + // typedef for handle to cancel presence info with + typedef OCDoHandle OCPresenceHandle; + + virtual ~OCPlatform_impl(void); + + OCStackResult notifyAllObservers(OCResourceHandle resourceHandle); + + OCStackResult notifyAllObservers(OCResourceHandle resourceHandle, QualityOfService QoS); + + OCStackResult notifyListOfObservers( + OCResourceHandle resourceHandle, + ObservationIds& observationIds, + const std::shared_ptr responsePtr); + + OCStackResult notifyListOfObservers( + OCResourceHandle resourceHandle, + ObservationIds& observationIds, + const std::shared_ptr responsePtr, + QualityOfService QoS); + + OCStackResult findResource(const std::string& host, const std::string& resourceURI, + OCConnectivityType connectivityType, FindCallback resourceHandler); + + OCStackResult findResource(const std::string& host, const std::string& resourceURI, + OCConnectivityType connectivityType, FindCallback resourceHandler, + QualityOfService QoS); + + OCStackResult findResource(const std::string& host, const std::string& resourceURI, + OCConnectivityType connectivityType, FindCallback resourceHandler, + FindErrorCallback errorHandler); + + OCStackResult findResource(const std::string& host, const std::string& resourceURI, + OCConnectivityType connectivityType, FindCallback resourceHandler, + FindErrorCallback errorHandler, QualityOfService QoS); + + OCStackResult findResourceList(const std::string& host, const std::string& resourceURI, + OCConnectivityType connectivityType, FindResListCallback resourceHandler, + QualityOfService QoS); + + OCStackResult getDeviceInfo(const std::string& host, const std::string& deviceURI, + OCConnectivityType connectivityType, FindDeviceCallback deviceInfoHandler); + + OCStackResult getDeviceInfo(const std::string& host, const std::string& deviceURI, + OCConnectivityType connectivityType, FindDeviceCallback deviceInfoHandler, + QualityOfService QoS); + + OCStackResult getPlatformInfo(const std::string& host, const std::string& platformURI, + OCConnectivityType connectivityType, FindPlatformCallback platformInfoHandler); + + OCStackResult getPlatformInfo(const std::string& host, const std::string& platformURI, + OCConnectivityType connectivityType, FindPlatformCallback platformInfoHandler, + QualityOfService QoS); + + /** + * API for Device Discovery + * + * @param host Host IP Address. If null or empty, Multicast is performed. + * @param deviceURI Uri containing address to the virtual device in C Stack + * ("/oic/d") + * @param deviceInfoHandler device discovery callback + * @param QualityOfService the quality of communication + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + */ + OCStackResult getDeviceInfo(const std::string& host, const std::string& deviceURI, + FindDeviceCallback deviceInfoHandler); + OCStackResult getDeviceInfo(const std::string& host, const std::string& deviceURI, + FindDeviceCallback deviceInfoHandler, QualityOfService QoS); + + /** + * API for Platform Discovery + * + * @param host Host IP Address. If null or empty, Multicast is performed. + * @param platformURI Uri containing address to the virtual platform in C Stack + * ("/oic/p") + * @param platformInfoHandler platform discovery callback + * @param QualityOfService the quality of communication + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + */ + OCStackResult getPlatformInfo(const std::string& host, const std::string& platformURI, + FindPlatformCallback platformInfoHandler); + OCStackResult getPlatformInfo(const std::string& host, const std::string& platformURI, + FindPlatformCallback platformInfoHandler, QualityOfService QoS); + + OCStackResult setPropertyValue(OCPayloadType type, const std::string& tag, const std::string& value); + OCStackResult setPropertyValue(OCPayloadType type, const std::string& tag, const std::vector& value); + OCStackResult getPropertyValue(OCPayloadType type, const std::string& tag, std::string& value); + + /** + * This API registers a resource with the server + * @note This API applies to server side only. + * + * @param resourceHandle Upon successful registration, resourceHandle will be filled + * @param resourceURI The URI of the resource. Example: "a/light". See NOTE below + * @param resourceTypeName The resource type. Example: "light" + * @param resourceInterface The resource interface (whether it is collection etc). + * @param entityHandler entity handler callback. + * @param resourceProperty indicates the property of the resource. Defined in ocstack.h. + * setting resourceProperty as OC_DISCOVERABLE will allow Discovery of this resource + * setting resourceProperty as OC_OBSERVABLE will allow observation + * settings resourceProperty as OC_DISCOVERABLE | OC_OBSERVABLE will allow both discovery + * and observation + * + * @return Returns ::OC_STACK_OK if success. + * @note "a/light" is a relative URI. + * Above relative URI will be prepended (by core) with a host IP + namespace "oc" + * Therefore, fully qualified URI format would be //HostIP-Address/namespace/relativeURI" + * Example, a relative URI: 'a/light' will result in a fully qualified URI: + * //192.168.1.1/oic/a/light" + * First parameter can take a relative URI and core will take care of preparing the fully + * qualified URI OR + * first parameter can take fully qualified URI and core will take that as is for further + * operations + * @note OCStackResult is defined in ocstack.h. + */ + OCStackResult registerResource(OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler entityHandler, + uint8_t resourceProperty); + + OCStackResult registerResource(OCResourceHandle& resourceHandle, + const std::shared_ptr resource); + + /** + * This API registers all the device specific information + * + * @param deviceInfo Structure containing all the device related information + * + * @return Returns ::OC_STACK_OK if success + * @note OCDeviceInfo is defined in OCStack.h + */ + OCStackResult registerDeviceInfo(const OCDeviceInfo deviceInfo); + + /** + * This API registers all the platform specific information + * + * @param platformInfo Structure containing all the platform related information + * + * @return Returns ::OC_STACK_OK if success + * @note OCPlatformInfo is defined in OCStack.h + */ + OCStackResult registerPlatformInfo(const OCPlatformInfo platformInfo); + + OCStackResult setDefaultDeviceEntityHandler(EntityHandler entityHandler); + + OCStackResult unregisterResource(const OCResourceHandle& resourceHandle) const; + + OCStackResult bindResource(const OCResourceHandle collectionHandle, + const OCResourceHandle resourceHandle); + + OCStackResult bindResources(const OCResourceHandle collectionHandle, + const std::vector& addedResourceHandleList); + + OCStackResult unbindResource(const OCResourceHandle collectionHandle, + const OCResourceHandle resourceHandle); + + OCStackResult unbindResources(const OCResourceHandle collectionHandle, + const std::vector& resourceHandleList); + + OCStackResult bindTypeToResource(const OCResourceHandle& resourceHandle, + const std::string& resourceTypeName) const; + + OCStackResult bindInterfaceToResource(const OCResourceHandle& resourceHandle, + const std::string& resourceInterfaceName) const; + + OCStackResult startPresence(const unsigned int ttl); + + OCStackResult stopPresence(); + + OCStackResult subscribePresence(OCPresenceHandle& presenceHandle, const std::string& host, + OCConnectivityType connectivityType, SubscribeCallback presenceHandler); + + OCStackResult subscribePresence(OCPresenceHandle& presenceHandle, const std::string& host, + const std::string& resourceType, OCConnectivityType connectivityType, + SubscribeCallback presenceHandler); + OCStackResult unsubscribePresence(OCPresenceHandle presenceHandle); + +#ifdef WITH_CLOUD + OCStackResult subscribeDevicePresence(OCPresenceHandle& presenceHandle, + const std::string& host, + const std::vector& di, + OCConnectivityType connectivityType, + ObserveCallback callback); +#endif + + OCResource::Ptr constructResourceObject(const std::string& host, const std::string& uri, + OCConnectivityType connectivityType, bool isObservable, + const std::vector& resourceTypes, + const std::vector& interfaces); + OCStackResult sendResponse(const std::shared_ptr pResponse); + std::weak_ptr csdkLock(); + + OCStackResult findDirectPairingDevices(unsigned short waittime, + GetDirectPairedCallback callback); + + OCStackResult getDirectPairedDevices(GetDirectPairedCallback callback); + + OCStackResult doDirectPairing(std::shared_ptr peer, OCPrm_t pmSel, + const std::string& pinNumber, + DirectPairingCallback resultCallback); +#ifdef WITH_CLOUD + OCAccountManager::Ptr constructAccountManagerObject(const std::string& host, + OCConnectivityType connectivityType); +#endif // WITH_CLOUD + + OCStackResult getDeviceId(OCUUIdentity *myUuid); + + OCStackResult setDeviceId(const OCUUIdentity *myUuid); + + private: + PlatformConfig m_cfg; + + private: + std::unique_ptr m_WrapperInstance; + IServerWrapper::Ptr m_server; + IClientWrapper::Ptr m_client; + std::shared_ptr m_csdkLock; + + private: + /** + * Constructor for OCPlatform_impl. Constructs a new OCPlatform_impl from a given + * PlatformConfig with appropriate fields + * @param config PlatformConfig struct which has details such as modeType + * (server/client/both), in-proc/out-of-proc etc. + */ + OCPlatform_impl(const PlatformConfig& config); + + /** + * Private function to initialize the platform + */ + void init(const PlatformConfig& config); + + /** + * Private constructor/operators to prevent copying + * of this object + */ + OCPlatform_impl(const OCPlatform_impl& other)= delete; + OCPlatform_impl& operator=(const OCPlatform_impl&) = delete; + OCPlatform_impl& operator=(const OCPlatform_impl&&) = delete; + }; +} + +#endif //__OCPLATFORM_IMPL_H diff --git a/inc/iotivity/OCProvisioningManager.hpp b/inc/iotivity/OCProvisioningManager.hpp new file mode 100644 index 0000000..dd60ced --- /dev/null +++ b/inc/iotivity/OCProvisioningManager.hpp @@ -0,0 +1,445 @@ +//**************************************************************** +// +// Copyright 2015 Samsung Electronics All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_PROVISIONINGMANAGER_CXX_H_ +#define OC_PROVISIONINGMANAGER_CXX_H_ + +#include + +#include "pinoxmcommon.h" +#include "ocprovisioningmanager.h" +#include "OCApi.h" +#include "OCPlatform_impl.h" + +namespace OC +{ + class OCSecureResource; + + typedef std::vector> DeviceList_t; + typedef std::vector UuidList_t; + typedef std::vector PMResultList_t; + typedef std::function ResultCallBack; + typedef std::functionCertChainCallBack; + + struct ProvisionContext + { + ResultCallBack callback; + ProvisionContext(ResultCallBack cb) : callback(cb){} + }; + + struct TrustCertChainContext + { + CertChainCallBack callback; + TrustCertChainContext(CertChainCallBack cb) : callback(cb){} + }; + /** + * This class is for credential's to be set to devices. + * The types supported are + * 0: no security mode + * 1: symmetric pair-wise key + * 2: symmetric group key + * 4: asymmetric key + * 8: signed asymmetric key (aka certificate) + * 16: PIN /password + */ + class Credential + { + OicSecCredType_t type; + size_t keySize; + public: + Credential() = default; + Credential(OicSecCredType_t type, size_t size) : type(type), keySize(size) + {} + + /** + * API to get credential type of device. + * @return credential type of device. + */ + OicSecCredType_t getCredentialType() const + { + return type; + } + + /** + * API to get size of credential key type. + * @return size of credential key type. + */ + size_t getCredentialKeySize() const + { + return keySize; + } + + /** + * API to set credential type of device. + * Device can have following credential types + * - symmetric pair-wise key + * - symmetric group key + * - asymmetric key + * - signed asymmetric key (aka certificate) + * - PIN /password + * @param type credential type. + */ + void setCredentialType(OicSecCredType_t type) + { + this->type = type; + } + + /** + * API to set size of credential key type. + * @param keySize credential key size. + * @note can be either 128 or 256 for symmetric pair-wise key + */ + void setCredentialKeySize(size_t keySize) + { + this->keySize = keySize; + } + }; + + class OCSecure + { + public: + /** + * The API is responsible for initialization of the provisioning manager. It will load + * provisioning database which have owned device's list and their linked status. + * + * @param dbPath file path of the sqlite3 database. + * + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult provisionInit(const std::string& dbPath); + + /** + * API is responsible for discovery of devices in it's subnet. It will list + * all the device in subnet which are not yet owned. + * + * @param timeout Timeout in seconds, time until which function will listen to + * responses from server before returning the list of devices. + * @param list List of candidate devices to be provisioned. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult discoverUnownedDevices(unsigned short timeout, + DeviceList_t &list); + + /** + * API is responsible for discovery of devices in it's subnet. It will list + * all the device in subnet which are already owned by calling provisioning client. + * + * @param timeout Timeout in seconds, time until which function will listen to + * responses from server before returning the list of devices. + * @param list List of owned devices. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult discoverOwnedDevices(unsigned short timeout, + DeviceList_t &list); + + /** + * API is responsible for discovery of devices in specified endpoint/deviceID. + * And this function will only return the specified device's response. + * + * @param timeout Timeout in seconds, time until which function will listen to + * responses from server before returning the specified device. + * @param deviceID deviceID of target device + * @param foundDevice OCSecureResource object of found device. + * @return ::OC_STACK_OK in case of success and other value otherwise.\n + * ::OC_STACK_INVALID_PARAM when deviceID is NULL or ppFoundDevice is not + * initailized. + */ + static OCStackResult discoverSingleDevice(unsigned short timeout, + const OicUuid_t* deviceID, + std::shared_ptr &foundDevice); + + /** + * API for registering Ownership transfer methods for a particular transfer Type. + * + * @param oxm Ownership transfer method. + * @param callbackData CallbackData Methods for ownership transfer. + * @param inputPin Callback method to input pin for verification. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult setOwnerTransferCallbackData(OicSecOxm_t oxm, + OTMCallbackData_t* callbackData, InputPinCallback inputPin); + + /** + * API to get status of all the devices in current subnet. The status include endpoint + * information and doxm information which can be extracted during owned and unowned + * discovery. Along with this information, API will provide information about + * devices' status. + * Device can have following states + * - ON/OFF: Device is switched on or off. + * + * @param timeout Wait time for the API. + * @param ownedDevList List of owned devices. + * @param unownedDevList List of unowned devices. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult getDevInfoFromNetwork(unsigned short timeout, + DeviceList_t &ownedDevList, + DeviceList_t &unownedDevList); + /** + * Server API to register callback to display stack generated PIN. + * + * @param displayPin Callback Method to Display generated PIN. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult setDisplayPinCB(GeneratePinCallback displayPin); + + /** + * API to remove device credential and ACL from all devices in subnet. + * + * @param resultCallback Callback provided by API user, callback will be called when + * credential revocation is finished. + * @param uuid Device uuid to be revoked. + * @param waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device + * discovery in seconds. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult removeDeviceWithUuid(unsigned short waitTimeForOwnedDeviceDiscovery, + std::string uuid, + ResultCallBack resultCallback); + + /** + * API to save ACL which has several ACE into Acl of SVR. + * + * @param acl ACL to be saved in Acl of SVR. + * @return OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult saveACL(const OicSecAcl_t* acl); + +#if defined(__WITH_DTLS__) || defined(__WITH_TLS__) + /** + * API to save Trust certificate chain into Cred of SVR. + * + * @param[in] trustCertChain Trust certificate chain to be saved in Cred of SVR. + * @param[in] chainSize Size of trust certificate chain to be saved in Cred of SVR + * @param[in] encodingType Encoding type of trust certificate chain to be saved in Cred of SVR + * @param[out] credId CredId of saved trust certificate chain in Cred of SVR. + * @return OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult saveTrustCertChain(uint8_t *trustCertChain, size_t chainSize, + OicEncodingType_t encodingType, uint16_t *credId); + + /* + * API to read Trust certificate chain from SVR. + * Caller must free when done using the returned trust certificate + * @param[in] credId CredId of trust certificate chain in SVR. + * @param[out] trustCertChain Trust certificate chain. + * @param[out] chainSize Size of trust certificate chain + * @return OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult readTrustCertChain(uint16_t credId, uint8_t **trustCertChain, + size_t *chainSize); + + /** + * API to register Notifier for trustCertChain change. + * + * @param[in] TrustCertChainChangeCB trustCertChain Change will be + * notified asynchronously. User need to "delete[]" trustCertChain + * in the callback function. + * @return OC_STACK_OK in case of success and other value otherwise. + */ + static OCStackResult registerTrustCertChangeNotifier(CertChainCallBack); + + /** + * API to remove Already registered Notifier. + * + *@return OC_STACK_OK always, kept it for symmetry. + */ + static OCStackResult removeTrustCertChangeNotifier(); + + /** + * Notifier wrapper for trustCertChain change. + * + * @param[in] ctx User context returned in callback + * @param[in] credId trustCertChain changed for this ID + * @param[in] trustCertChain trustcertchain binary blob + * @param[in] chainSize size of trustCertChain + */ + static void certCallbackWrapper(void* ctx, uint16_t credId, uint8_t *trustCertChain, + size_t chainSize); +#endif // __WITH_DTLS__ || __WITH_TLS__ + + }; + + /** + * This class represents a secure virtual device, which can be provisioned by the + * provisioning client. + */ + class OCSecureResource + { + private: + std::weak_ptr m_csdkLock; + OCProvisionDev_t *devPtr; // pointer to device. + + public: + OCSecureResource(); + OCSecureResource(std::weak_ptr csdkLock, OCProvisionDev_t *dPtr); + + ~OCSecureResource(); + + /** + * API to provision credentials between two devices and ACLs for the devices who + * act as a server. + * + * @param cred Type of credentials & key size to be provisioned to the device. + * @param acl1 ACL for device 1. If this is not required set NULL. + * @param device2 Second device to be provisioned. + * @param acl2 ACL for device 2. If this is not required set NULL. + * @param resultCallback Callback will be called when provisioning request receives + * a response from first resource server. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + OCStackResult provisionPairwiseDevices(const Credential &cred, const OicSecAcl_t* acl1, + const OCSecureResource &device2, const OicSecAcl_t* acl2, + ResultCallBack resultCallback); + + /** + * API to do ownership transfer for un-owned device. + * + * @param resultCallback Result callback function to be invoked when + * ownership transfer finished. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + OCStackResult doOwnershipTransfer(ResultCallBack resultCallback); + + /** + * API to send ACL information to resource. + * + * @param acl ACL to provision. + * @param resultCallback Callback will be called when provisioning request + * receives a response from resource server. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + OCStackResult provisionACL(const OicSecAcl_t* acl, + ResultCallBack resultCallback); + + /** + * API to provision credential to devices. + * + * @param cred Type of credentials to be provisioned to the device. + * @param device2 Second device' instance, representing resource to be provisioned. + * @param resultCallback Callback will be called when provisioning request receives + * a response from first resource server. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + OCStackResult provisionCredentials(const Credential &cred, + const OCSecureResource &device2, + ResultCallBack resultCallback); + + /** + * API to remove the credential & relationship between the two devices. + * + * @param device2 Second device information to be unlinked. + * @param resultCallback Callback provided by API user, callback will be called when + * device unlink is finished. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + OCStackResult unlinkDevices(const OCSecureResource &device2, + ResultCallBack resultCallback); + + /** + * API to remove device credential from all devices in subnet. + * + * @param resultCallback Callback provided by API user, callback will be called when + * credential revocation is finished. + * @param waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device + * discovery in seconds. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + OCStackResult removeDevice(unsigned short waitTimeForOwnedDeviceDiscovery, + ResultCallBack resultCallback); + + /** + * API to provision DirectPairing to devices. + * + * @param pconf pointer to PCONF (Pairing Configuration). + * @param resultCallback Callback will be called when provisioning request receives + * a response from first resource server. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + OCStackResult provisionDirectPairing(const OicSecPconf_t *pconf, + ResultCallBack resultCallback); + +#if defined(__WITH_DTLS__) || defined(__WITH_TLS__) + /** + * API to provision cert. + * + * @param type type of cred. + * @param credId id of cert. + * @param resultCallback Callback will be called when provisioning request + * receives a response from resource server. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + OCStackResult provisionTrustCertChain(OicSecCredType_t type, uint16_t credId, + ResultCallBack resultCallback); + +#endif // __WITH_DTLS__ or __WITH_TLS__ + + /** + * This method is used to get linked devices' IDs. + * + * @param uuidList Information about the list of linked devices uuids. + * @return ::OC_STACK_OK in case of success and other value otherwise. + */ + OCStackResult getLinkedDevices(UuidList_t &uuidList); + + /** + * API to get the device ID of this resource. + * @return device ID. + */ + std::string getDeviceID(); + + /** + * API to get the information of device for provisioning. + * @return @ref OCProvisionDev_t Reference provides information of device for provisioning. + */ + OCProvisionDev_t* getDevPtr()const; + + /** + * This function returns the device's IP address. + * @return device address. + */ + std::string getDevAddr(); + + /** + * This function returns the device's Status. + * @return Device status (1 = ON and 2 = OFF). + */ + int getDeviceStatus(); + + /** + * This function provides the owned status of the device. + * @return Device owned status. + */ + bool getOwnedStatus(); + + + /** + * Common callback wrapper, which will be called from OC-APIs. + */ + static void callbackWrapper(void* ctx, int nOfRes, + OCProvisionResult_t *arr, bool hasError); + + private: + void validateSecureResource(); + }; + +} +#endif // OC_PROVISIONINGMANAGER_CXX_H_ diff --git a/inc/iotivity/OCRepresentation.h b/inc/iotivity/OCRepresentation.h new file mode 100644 index 0000000..309b3e5 --- /dev/null +++ b/inc/iotivity/OCRepresentation.h @@ -0,0 +1,512 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/** + * @file + * + * This file contains the declaration of classes and its members related + * to OCRepresentation. + */ + +#ifndef OC_REPRESENTATION_H_ +#define OC_REPRESENTATION_H_ + +#include +#include +#include +#include + +#include +#include + +#ifdef __ANDROID__ +#include "OCAndroid.h" +#endif + +#include + +namespace OC +{ + + enum class InterfaceType + { + None, + LinkParent, + BatchParent, + DefaultParent, + LinkChild, + BatchChild, + DefaultChild + }; + + class MessageContainer + { + public: + void setPayload(const OCPayload* rep); + + void setPayload(const OCRepPayload* rep); + + OCRepPayload* getPayload() const; + + const std::vector& representations() const; + + void addRepresentation(const OCRepresentation& rep); + + const OCRepresentation& operator[](int index) const + { + return m_reps[index]; + } + + const OCRepresentation& back() const + { + return m_reps.back(); + } + private: + std::vector m_reps; + }; + class OCRepresentation + { + public: + friend bool operator==(const OC::OCRepresentation&, const OC::OCRepresentation&); + // Note: Implementation of all constructors and destructors + // are all placed in the same location due to a crash that + // was observed in Android, where merely constructing/destructing + // an OCRepresentation object was enough to cause an invalid 'free'. + // It is believed that this is a result of incompatible compiler + // options between the gradle JNI and armeabi scons build, however + // this fix will work in the meantime. + OCRepresentation(): m_interfaceType(InterfaceType::None){} + +#if defined(_MSC_VER) && (_MSC_VER < 1900) + OCRepresentation(OCRepresentation&& o) + { + std::memmove(this, &o, sizeof(o)); + } +#else + OCRepresentation(OCRepresentation&&) = default; +#endif + + OCRepresentation(const OCRepresentation&) = default; + + OCRepresentation& operator=(const OCRepresentation&) = default; + +#if defined(_MSC_VER) && (_MSC_VER < 1900) + OCRepresentation& operator=(OCRepresentation&& o) + { + std::memmove(this, &o, sizeof(o)); + return *this; + } +#else + OCRepresentation& operator=(OCRepresentation&&) = default; +#endif + + virtual ~OCRepresentation(){} + + void setDevAddr(const OCDevAddr addr); + + const std::string getHost() const; + + OCRepPayload* getPayload() const; + + void addChild(const OCRepresentation&); + + void clearChildren(); + + const std::vector& getChildren() const; + + void setChildren(const std::vector& children); + + void setUri(const char* uri); + + void setUri(const std::string& uri); + + std::string getUri() const; + + const std::vector& getResourceTypes() const; + + const std::vector& getDataModelVersions() const; + + void setResourceTypes(const std::vector& resourceTypes); + + void addResourceType(const std::string& str); + + const std::vector& getResourceInterfaces() const; + + void setResourceInterfaces(const std::vector& resourceInterfaces); + + void addResourceInterface(const std::string& str); + + void addDataModelVersion(const std::string& str); + + bool emptyData() const; + + int numberOfAttributes() const; + + bool erase(const std::string& str); + + template + void setValue(const std::string& str, const T& val) + { + m_values[str] = val; + } + + // using R-value(or universal ref depending) to move string and vector + template + void setValue(const std::string& str, T&& val) + { + m_values[str] = std::forward(val); + } + + const std::map& getValues() const { + return m_values; + } + + /** + * Retrieve the attribute value associated with the supplied name + * + * @param str Name of the attribute + * @param val Value of the attribute + * @return The getValue method returns true if the attribute was + * found in the representation. Otherwise it returns false. + */ + template + bool getValue(const std::string& str, T& val) const + { + auto x = m_values.find(str); + + if(x!= m_values.end()) + { + try + { + val = boost::get(x->second); + return true; + } + catch (boost::bad_get& e) + { + val = T(); + return false; + } + } + else + { + val = T(); + return false; + } + } + + /** + * Return the attribute value associated with the supplied name + * + * @param str Name of the attribute + * @return When the representation contains the attribute, the + * the associated value is returned. Otherwise, getValue + * returns the default contructed value for the type. + */ + template + T getValue(const std::string& str) const + { + T val = T(); + auto x = m_values.find(str); + if(x != m_values.end()) + { + try + { + val = boost::get(x->second); + } + catch (boost::bad_get& e) + { + return val; + } + } + return val; + } + + /** + * Retrieve the attributevalue structure associated with the supplied name + * + * @param str Name of the attribute + * @param attrValue Attribute Value structure + * @return The getAttributeValue method returns true if the attribute was + * found in the representation. Otherwise it returns false. + */ + bool getAttributeValue(const std::string& str, AttributeValue& attrValue) const + { + auto x = m_values.find(str); + + if (x != m_values.end()) + { + attrValue = x->second; + return true; + } + else + { + return false; + } + } + + std::string getValueToString(const std::string& key) const; + bool hasAttribute(const std::string& str) const; + + void setNULL(const std::string& str); + + bool isNULL(const std::string& str) const; + + private: + std::string m_host; + + // STL Container stuff + public: + class iterator; + class const_iterator; + // Shim class to allow iterating and indexing of the OCRepresentation + // object. + class AttributeItem + { + friend class OCRepresentation; + friend class iterator; + friend class const_iterator; + public: + const std::string& attrname() const; + AttributeType type() const; + AttributeType base_type() const; + size_t depth() const; + template + T getValue() const + { + try + { + return boost::get(m_values[m_attrName]); + } + catch (boost::bad_get& e) + { + T val = T(); + return val; + } + } + + std::string getValueToString() const; + + template + AttributeItem& operator=(T&& rhs) + { + m_values[m_attrName] = std::forward(rhs); + return *this; + } + + AttributeItem& operator=(std::nullptr_t /*rhs*/) + { + NullType t; + m_values[m_attrName] = t; + return *this; + } + + // Enable-if required to prevent conversions to alternate types. This prevents + // ambigious conversions in the case where conversions can include a number of + // types, such as the string constructor. +#if (defined(_MSC_VER) ) || (defined(__GNUC__) && (__GNUC__ <= 5)) + template::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same>::value || + std::is_same>>::value || + std::is_same>>>::value || + std::is_same>::value || + std::is_same>>::value || + std::is_same>>>::value || + std::is_same>::value || + std::is_same>>::value || + std::is_same>>>::value || + std::is_same>::value || + std::is_same>>::value || + std::is_same>>>::value || + std::is_same>::value || + std::is_same>>::value || + std::is_same>>>::value || + std::is_same>::value || + std::is_same>>::value || + std::is_same>>>::value + , int>::type = 0// enable_if + > +#else + template::type + >::value + , int>::type = 0 + > +#endif + operator T() const + { + return this->getValue(); + } + + template::value + , int>::type = 0 + > + operator T() const + { + this->getValue(); + return nullptr; + } + + private: + AttributeItem(const std::string& name, + std::map& vals); + AttributeItem(const AttributeItem&) = default; + std::string m_attrName; + std::map& m_values; + }; + + // Iterator to allow iteration via STL containers/methods + class iterator + { + friend class OCRepresentation; + public: + typedef iterator self_type; + typedef AttributeItem value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef int difference_type; + + iterator(const iterator&) = default; + ~iterator() = default; + + bool operator ==(const iterator&) const; + bool operator !=(const iterator&) const; + + iterator& operator++(); + iterator operator++(int); + + reference operator*(); + pointer operator->(); + private: + iterator(std::map::iterator&& itr, + std::map& vals) + : m_iterator(std::move(itr)), + m_item(m_iterator != vals.end() ? m_iterator->first:"", vals){} + std::map::iterator m_iterator; + AttributeItem m_item; + }; + + class const_iterator + { + friend class OCRepresentation; + public: + typedef iterator self_type; + typedef const AttributeItem value_type; + typedef value_type& const_reference; + typedef value_type* const_pointer; + typedef std::forward_iterator_tag iterator_category; + typedef int difference_type; + + const_iterator(const iterator& rhs) + :m_iterator(rhs.m_iterator), m_item(rhs.m_item){} + const_iterator(const const_iterator&) = default; + ~const_iterator() = default; + + bool operator ==(const const_iterator&) const; + bool operator !=(const const_iterator&) const; + + const_iterator& operator++(); + const_iterator operator++(int); + + const_reference operator*() const; + const_pointer operator->() const; + private: + const_iterator(std::map::const_iterator&& itr, + std::map& vals) + : m_iterator(std::move(itr)), + m_item(m_iterator != vals.end() ? m_iterator->first: "", vals){} + std::map::const_iterator m_iterator; + AttributeItem m_item; + }; + + iterator begin(); + const_iterator begin() const; + const_iterator cbegin() const; + iterator end(); + const_iterator end() const; + const_iterator cend() const; + size_t size() const; + bool empty() const; + + AttributeItem operator[](const std::string& key); + const AttributeItem operator[](const std::string& key) const; + private: + friend class OCResourceResponse; + friend class MessageContainer; + + template + void payload_array_helper(const OCRepPayloadValue* pl, size_t depth); + template + T payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl); + void setPayload(const OCRepPayload* payload); + void setPayloadArray(const OCRepPayloadValue* pl); + void getPayloadArray(OCRepPayload* payload, + const OCRepresentation::AttributeItem& item) const; + // the root node has a slightly different JSON version + // based on the interface type configured in ResourceResponse. + // This allows ResourceResponse to set it, so that the save function + // doesn't serialize things that it isn't supposed to serialize. + void setInterfaceType(InterfaceType ift) + { + m_interfaceType = ift; + } + + // class used to wrap the 'prop' feature of the save/load + class Prop + { + public: + Prop(std::vector& resourceTypes, + std::vector& interfaces) + : m_types(resourceTypes), m_interfaces(interfaces) + {} + + /* Prop(const std::vector& resourceTypes, + const std::vector& interfaces) + :m_types(resourceTypes), + m_interfaces(interfaces) + {}*/ + private: + std::vector& m_types; + std::vector& m_interfaces; + }; + private: + std::string m_uri; + std::vector m_children; + mutable std::map m_values; + std::vector m_resourceTypes; + std::vector m_interfaces; + std::vector m_dataModelVersions; + + InterfaceType m_interfaceType; + }; + + std::ostream& operator <<(std::ostream& os, const OCRepresentation::AttributeItem& ai); +} // namespace OC + + +#endif // OC_REPRESENTATION_H_ diff --git a/inc/iotivity/OCResource.h b/inc/iotivity/OCResource.h new file mode 100644 index 0000000..2167ba6 --- /dev/null +++ b/inc/iotivity/OCResource.h @@ -0,0 +1,691 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/** + * @file + * + * This file contains the declaration of classes and its members related to + * Resource. + */ + +#ifndef OC_RESOURCE_H_ +#define OC_RESOURCE_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace OC +{ + class OCResource; + class OCResourceIdentifier; + std::ostream& operator <<(std::ostream& os, const OCResourceIdentifier& ri); + /** + * @brief OCResourceIdentifier represents the identity information for a server. This + * object combined with the OCResource's URI property uniquely identify an + * OCResource on or across networks. + * Equality operators are implemented. However, internal representation is subject + * to change and thus should not be accessed or depended on. + */ + class OCResourceIdentifier + { + friend class OCResource; + friend std::ostream& operator <<(std::ostream& os, const OCResourceIdentifier& ri); + + public: + OCResourceIdentifier() = delete; + + OCResourceIdentifier(const OCResourceIdentifier&) = default; + +#if defined(_MSC_VER) && (_MSC_VER < 1900) + OCResourceIdentifier(OCResourceIdentifier&& o): + m_resourceUri(std::move(o.m_resourceUri)), + m_representation(o.m_representation) + { + } +#else + OCResourceIdentifier(OCResourceIdentifier&&) = default; +#endif + + OCResourceIdentifier& operator=(const OCResourceIdentifier&) = delete; + + OCResourceIdentifier& operator=(OCResourceIdentifier&&) = delete; + + bool operator==(const OCResourceIdentifier &other) const; + + bool operator!=(const OCResourceIdentifier &other) const; + + bool operator<(const OCResourceIdentifier &other) const; + + bool operator>(const OCResourceIdentifier &other) const; + + bool operator<=(const OCResourceIdentifier &other) const; + + bool operator>=(const OCResourceIdentifier &other) const; + + private: + + OCResourceIdentifier(const std::string& wireServerIdentifier, + const std::string& resourceUri ); + + private: + std::string m_representation; + const std::string& m_resourceUri; + }; + + /** + * @brief OCResource represents an OC resource. A resource could be a light controller, + * temperature sensor, smoke detector, etc. A resource comes with a well-defined + * contract or interface onto which you can perform different operations, such as + * turning on the light, getting the current temperature or subscribing for event + * notifications from the smoke detector. A resource can be composed of one or + * more resources. + */ + class OCResource + { + friend class OCPlatform_impl; + friend class ListenOCContainer; + public: + typedef std::shared_ptr Ptr; + +#if defined(_MSC_VER) && (_MSC_VER < 1900) + OCResource(OCResource&& o): + m_clientWrapper(std::move(o.m_clientWrapper)), + m_uri(std::move(o.m_uri)), + m_resourceId(std::move(o.m_resourceId)), + m_devAddr(std::move(o.m_devAddr)), + m_useHostString(o.m_useHostString), + m_property(o.m_property), + m_isCollection(o.m_isCollection), + m_resourceTypes(std::move(o.m_resourceTypes)), + m_interfaces(std::move(o.m_interfaces)), + m_children(std::move(m_children)), + m_observeHandle(std::move(m_observeHandle)), + m_headerOptions(std::move(m_headerOptions)) + { + } +#else + OCResource(OCResource&&) = default; +#endif + // Explicitly delete the copy ctor since VS2013 would try to generate one, and + // the standard says that defaulting the move ctor should delete the copy ctor. + OCResource(const OCResource&) = delete; + + // We cannot support copy/move assigns since OCResourceIdentifier doesn't. + OCResource& operator=(OCResource&&) = delete; + OCResource& operator=(const OCResource&) = delete; + + /** + * Virtual destructor + */ + virtual ~OCResource(void); + + /** + * Function to get the attributes of a resource. + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler handles callback + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this Get operation + * This will have error codes + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + */ + OCStackResult get(const QueryParamsMap& queryParametersMap, GetCallback attributeHandler); + /** + * Function to get the attributes of a resource. + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler handles callback + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this Get operation + * This will have error codes + * @param QoS the quality of communication + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + */ + OCStackResult get(const QueryParamsMap& queryParametersMap, GetCallback attributeHandler, + QualityOfService QoS); + + /** + * Function to get the attributes of a resource. + * + * @param resourceType resourceType of the resource operate on + * @param resourceInterface interface type of the resource to operate on + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler handles callback + * The callback function will be invoked with a map of attribute name and values. + * The callback function will be invoked with a list of URIs if 'get' is invoked on a + * resource container (list will be empty if not a container) + * The callback function will also have the result from this Get operation. This will + * have error codes + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * @par Example: + * Consider resource "a/home" (with link interface and resource type as home) contains links + * to "a/kitchen" and "a/room". + * -# get("home", Link_Interface, &onGet) + * @par + * Callback onGet will receive a) Empty attribute map because there are no attributes for + * a/home b) list with + * full URI of "a/kitchen" and "a/room" resources and their properties c) error code for GET + * operation + * @note A resource may contain single or multiple resource types. Also, a resource may + * contain single or multiple interfaces. + * Currently, single GET request is allowed to do operate on single resource type or resource + * interface. In future, a single GET + * can operate on multiple resource types and interfaces. + * @note A client can traverse a tree or graph by doing successive GETs on the returned + * resources at a node. + * + */ + OCStackResult get(const std::string& resourceType, const std::string& resourceInterface, + const QueryParamsMap& queryParametersMap, GetCallback attributeHandler); + /** + * Function to get the attributes of a resource. + * + * @param resourceType resourceType of the resource operate on + * @param resourceInterface interface type of the resource to operate on + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler handles callback + * The callback function will be invoked with a map of attribute name and values. + * The callback function will be invoked with a list of URIs if 'get' is invoked on a + * resource container (list will be empty if not a container) + * The callback function will also have the result from this Get operation. This will + * have error codes + * @param QoS the quality of communication + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * note OCStackResult is defined in ocstack.h. + * @par Example: + * Consider resource "a/home" (with link interface and resource type as home) contains links + * to "a/kitchen" and "a/room". + * -# get("home", Link_Interface, &onGet) + * @par + * Callback onGet will receive a) Empty attribute map because there are no attributes for + * a/home b) list with + * full URI of "a/kitchen" and "a/room" resources and their properties c) error code for GET + * operation + * @note A resource may contain single or multiple resource types. Also, a resource may + * contain single or multiple interfaces. + * Currently, single GET request is allowed to do operate on single resource type or resource + * interface. In future, a single GET + * can operate on multiple resource types and interfaces. + * @note A client can traverse a tree or graph by doing successive GETs on the returned + * resources at a node. + * + */ + OCStackResult get(const std::string& resourceType, const std::string& resourceInterface, + const QueryParamsMap& queryParametersMap, GetCallback attributeHandler, + QualityOfService QoS); + + /** + * Function to set the representation of a resource (via PUT) + * + * @param representation which can either have all the attribute names and values + (which will represent entire state of the resource) or a + * set of attribute names and values which needs to be modified + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this Put operation + * This will have error codes + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler attribute handler + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult put(const OCRepresentation& representation, + const QueryParamsMap& queryParametersMap, PutCallback attributeHandler); + /** + * Function to set the representation of a resource (via PUT) + * + * @param representation which can either have all the attribute names and values + (which will represent entire state of the resource) or a + * set of attribute names and values which needs to be modified + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this Put operation + * This will have error codes + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler attribute handler + * @param QoS the quality of communication + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult put(const OCRepresentation& representation, + const QueryParamsMap& queryParametersMap, PutCallback attributeHandler, + QualityOfService QoS); + + /** + * Function to set the attributes of a resource (via PUT) + * + * @param resourceType resource type of the resource to operate on + * @param resourceInterface interface type of the resource to operate on + * @param representation representation of the resource + * @param queryParametersMap Map which can have the query parameter name and value + * @param attributeHandler attribute handler + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this Put operation + * This will have error codes. + * The Representation parameter maps which can either have all the attribute names + * and values + * (which will represent entire state of the resource) or a + * set of attribute names and values which needs to be modified + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult put(const std::string& resourceType, const std::string& resourceInterface, + const OCRepresentation& representation, const QueryParamsMap& queryParametersMap, + PutCallback attributeHandler); + /** + * Function to set the attributes of a resource (via PUT) + * @param resourceType resource type of the resource to operate on + * @param resourceInterface interface type of the resource to operate on + * @param representation representation of the resource + * @param queryParametersMap Map which can have the query parameter name and value + * @param attributeHandler attribute handler + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this Put operation + * This will have error codes. + * The Representation parameter maps which can either have all the attribute names + * and values + * (which will represent entire state of the resource) or a + * set of attribute names and values which needs to be modified + * @param QoS the quality of communication + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult put(const std::string& resourceType, const std::string& resourceInterface, + const OCRepresentation& representation, const QueryParamsMap& queryParametersMap, + PutCallback attributeHandler, QualityOfService QoS); + + /** + * Function to post on a resource + * + * @param representation which can either have all the attribute names and values + * (which will represent entire state of the resource) or a + * set of attribute names and values which needs to be modified + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this Put operation + * This will have error codes + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler attribute handler + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + */ + OCStackResult post(const OCRepresentation& representation, + const QueryParamsMap& queryParametersMap, PostCallback attributeHandler); + /** + * Function to post on a resource + * + * @param representation which can either have all the attribute names and values + * (which will represent entire state of the resource) or a + * set of attribute names and values which needs to be modified + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this Put operation + * This will have error codes + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler attribute handler + * @param QoS the quality of communication + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + */ + OCStackResult post(const OCRepresentation& representation, + const QueryParamsMap& queryParametersMap, PostCallback attributeHandler, + QualityOfService QoS); + + /** + * Function to post on a resource + * + * @param resourceType resource type of the resource to operate on + * @param resourceInterface interface type of the resource to operate on + * @param representation representation of the resource + * @param queryParametersMap Map which can have the query parameter name and value + * @param attributeHandler attribute handler + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this Put operation + * This will have error codes. + * The Representation parameter maps which can either have all the attribute names + * and values + * (which will represent entire state of the resource) or a + * set of attribute names and values which needs to be modified + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult post(const std::string& resourceType, const std::string& resourceInterface, + const OCRepresentation& representation, const QueryParamsMap& queryParametersMap, + PostCallback attributeHandler); + /** + * Function to post on a resource + * + * @param resourceType resource type of the resource to operate on + * @param resourceInterface interface type of the resource to operate on + * @param representation representation of the resource + * @param queryParametersMap Map which can have the query parameter name and value + * @param attributeHandler attribute handler + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this Put operation + * This will have error codes. + * The Representation parameter maps which can either have all the attribute names + * and values + * (which will represent entire state of the resource) or a + * set of attribute names and values which needs to be modified + * @param QoS the quality of communication + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult post(const std::string& resourceType, const std::string& resourceInterface, + const OCRepresentation& representation, const QueryParamsMap& queryParametersMap, + PostCallback attributeHandler, QualityOfService QoS); + + /** + * Function to perform DELETE operation + * + * @param deleteHandler handles callback + * The callback function will have headerOptions and result from this Delete + * operation. This will have error codes + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult deleteResource(DeleteCallback deleteHandler); + OCStackResult deleteResource(DeleteCallback deleteHandler, QualityOfService QoS); + + /** + * Function to set observation on the resource + * + * @param observeType allows the client to specify how it wants to observe. + * @param queryParametersMap map which can have the query parameter name and value + * @param observeHandler handles callback + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this observe operation + * This will have error codes + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult observe(ObserveType observeType, const QueryParamsMap& queryParametersMap, + ObserveCallback observeHandler); + /** + * Function to set observation on the resource + * + * @param observeType allows the client to specify how it wants to observe. + * @param queryParametersMap map which can have the query parameter name and value + * @param observeHandler handles callback + * The callback function will be invoked with a map of attribute name and values. + * The callback function will also have the result from this observe operation + * This will have error codes + * @param qos the quality of communication + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult observe(ObserveType observeType, const QueryParamsMap& queryParametersMap, + ObserveCallback observeHandler, QualityOfService qos); + + /** + * Function to cancel the observation on the resource + * + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult cancelObserve(); + OCStackResult cancelObserve(QualityOfService qos); + + /** + * Function to set header information. + * @param headerOptions std::vector where header information(header optionID and optionData + * is passed + * + * @note Once the headers information is set, it will be applicable to GET, PUT and observe + * request. + * setHeaderOptions can be used multiple times if headers need to be modifed by the client. + * Latest headers will be used to send in the request.
+ * @note Initial support is only for two headers. If headerMap consists of more than two + * header options, they will be ignored.
+ * Use unsetHeaderOptions API to clear the header information. + */ + void setHeaderOptions(const HeaderOptions& headerOptions); + + /** + * Function to unset header options. + */ + void unsetHeaderOptions(); + + /** + * Function to get the host address of this resource + * @return std::string host address + * @note This might or might not be exposed in future due to security concerns + */ + std::string host() const; + + /** + * Function to get the URI for this resource + * @return std::string resource URI + */ + std::string uri() const; + + /** + * Function to get the connectivity type of this resource + * @return enum connectivity type (flags and adapter) + */ + OCConnectivityType connectivityType() const; + + /** + * Function to provide ability to check if this resource is observable or not + * @return bool true indicates resource is observable; false indicates resource is + * not observable. + */ + bool isObservable() const; + +#ifdef WITH_MQ + /** + * Function to provide ability to check if this resource is publisher or not + * @return bool true indicates resource is publisher; false indicates resource is + * not publisher. + */ + bool isPublish() const; +#endif + + /** + * Function to get the list of resource types + * @return vector of resource types + */ + std::vector getResourceTypes() const; + + /** + * Function to get the list of resource interfaces + * @return vector of resource interface + */ + std::vector getResourceInterfaces(void) const; + + // TODO-CA Revisit this since we are exposing two identifiers + /** + * Function to get a unique identifier for this + * resource across network interfaces. This will + * be guaranteed unique for every resource-per-server + * independent of how this was discovered. + * @return OCResourceIdentifier object, which can + * be used for all comparison and hashing. + */ + OCResourceIdentifier uniqueIdentifier() const; + + /** + * Function to get a string representation of the resource's server ID. + * This is unique per- server independent on how it was discovered. + * @note The format of the return value is subject to change and will + * likely change both in size and contents in the future. + */ + std::string sid() const; + +#ifdef WITH_MQ + /** + * Function to discovery Topics from MQ Broker. + * + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler handles callback + * @param qos the quality of communication + * + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult discoveryMQTopics(const QueryParamsMap& queryParametersMap, + MQTopicCallback attributeHandler, + QualityOfService qos); + /** + * Function to create Topic into MQ Broker. + * SubTopic is also created through this method. + * + * @param rep representation of the topic + * @param topicUri new uri of the topic which want to create + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler handles callback + * @param qos the quality of communication + * + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult createMQTopic(const OCRepresentation& rep, + const std::string& topicUri, + const QueryParamsMap& queryParametersMap, + MQTopicCallback attributeHandler, + QualityOfService qos); +#endif +#ifdef MQ_SUBSCRIBER + /** + * Function to subscribe Topic to MQ Broker. + * + * @param observeType allows the client to specify how it wants to observe. + * @param queryParametersMap map which can have the query parameter name and value + * @param observeHandler handles callback + * @param qos the quality of communication + * + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult subscribeMQTopic(ObserveType observeType, + const QueryParamsMap& queryParametersMap, + ObserveCallback observeHandler, + QualityOfService qos); + + /** + * Function to unsubscribe Topic to MQ Broker. + * + * @param qos the quality of communication + * + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult unsubscribeMQTopic(QualityOfService qos); + + /** + * Function to request publish to MQ publisher. + * Publisher can confirm the request message as key:"req_pub" and value:"true". + * + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler handles callback + * @param qos the quality of communication + * + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult requestMQPublish(const QueryParamsMap& queryParametersMap, + PostCallback attributeHandler, + QualityOfService qos); +#endif +#ifdef MQ_PUBLISHER + /** + * Function to publish Topic information into MQ Broker. + * + * @param rep representation of the topic + * @param queryParametersMap map which can have the query parameter name and value + * @param attributeHandler handles callback + * @param qos the quality of communication + * + * @return Returns ::OC_STACK_OK on success, some other value upon failure. + * @note OCStackResult is defined in ocstack.h. + * + */ + OCStackResult publishMQTopic(const OCRepresentation& rep, + const QueryParamsMap& queryParametersMap, + PostCallback attributeHandler, + QualityOfService qos); +#endif + // overloaded operators allow for putting into a 'set' + // the uniqueidentifier allows for putting into a hash + bool operator==(const OCResource &other) const; + + bool operator!=(const OCResource &other) const; + + bool operator<(const OCResource &other) const; + + bool operator>(const OCResource &other) const; + + bool operator<=(const OCResource &other) const; + + bool operator>=(const OCResource &other) const; + + private: + void setHost(const std::string& host); + std::weak_ptr m_clientWrapper; + std::string m_uri; + OCResourceIdentifier m_resourceId; + OCDevAddr m_devAddr; + bool m_useHostString; + bool m_isCollection; + uint8_t m_property; + std::vector m_resourceTypes; + std::vector m_interfaces; + std::vector m_children; + OCDoHandle m_observeHandle; + HeaderOptions m_headerOptions; + + private: + OCResource(std::weak_ptr clientWrapper, + const OCDevAddr& devAddr, const std::string& uri, + const std::string& serverId, uint8_t property, + const std::vector& resourceTypes, + const std::vector& interfaces); + + OCResource(std::weak_ptr clientWrapper, + const std::string& host, const std::string& uri, + const std::string& serverId, + OCConnectivityType connectivityType, uint8_t property, + const std::vector& resourceTypes, + const std::vector& interfaces); + }; + +} // namespace OC + +#endif // OC_RESOURCE_H + diff --git a/inc/iotivity/OCResourceRequest.h b/inc/iotivity/OCResourceRequest.h new file mode 100644 index 0000000..8c7e1dc --- /dev/null +++ b/inc/iotivity/OCResourceRequest.h @@ -0,0 +1,268 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/** + * @file + * + * This file contains the declaration of classes and its members related to + * ResourceRequest. + */ + +#ifndef OC_RESOURCEREQUEST_H_ +#define OC_RESOURCEREQUEST_H_ + +#include "OCApi.h" +#include "OCRepresentation.h" + +void formResourceRequest(OCEntityHandlerFlag, + OCEntityHandlerRequest*, + std::shared_ptr); + + +namespace OC +{ + /** + * @brief OCResourceRequest provides APIs to extract details from a request URI + */ + class OCResourceRequest + { + public: + typedef std::shared_ptr Ptr; + + OCResourceRequest(): + m_requestType(""), + m_resourceUri(""), + m_queryParameters(QueryParamsMap()), + m_requestHandlerFlag(0), + m_messageID(0), + m_representation(OCRepresentation()), + m_headerOptions(HeaderOptions()), + m_requestHandle(0), + m_resourceHandle(nullptr) + { + m_observationInfo.action = ObserveAction::ObserveRegister; + m_observationInfo.obsId = 0; + m_observationInfo.connectivityType = OCConnectivityType::CT_DEFAULT; + m_observationInfo.address = ""; + m_observationInfo.port = 0; + } + +#if defined(_MSC_VER) && (_MSC_VER < 1900) + OCResourceRequest(OCResourceRequest&& o): + m_requestType(std::move(o.m_requestType)), + m_resourceUri(std::move(o.m_resourceUri)), + m_queryParameters(std::move(o.m_queryParameters)), + m_requestHandlerFlag(o.m_requestHandlerFlag), + m_representation(std::move(o.m_representation)), + m_observationInfo(std::move(o.m_observationInfo)), + m_headerOptions(std::move(o.m_headerOptions)), + m_requestHandle(std::move(o.m_requestHandle)), + m_resourceHandle(std::move(o.m_resourceHandle)) + { + } + OCResourceRequest& operator=(OCResourceRequest&& o) + { + m_requestType = std::move(o.m_requestType); + m_resourceUri = std::move(o.m_resourceUri); + m_queryParameters = std::move(o.m_queryParameters); + m_requestHandlerFlag = o.m_requestHandlerFlag; + m_representation = std::move(o.m_representation); + m_observationInfo = std::move(o.m_observationInfo); + m_headerOptions = std::move(o.m_headerOptions); + m_requestHandle = std::move(o.m_requestHandle); + m_resourceHandle = std::move(o.m_resourceHandle); + } +#else + OCResourceRequest(OCResourceRequest&&) = default; + OCResourceRequest& operator=(OCResourceRequest&&) = default; +#endif + + /** + * Virtual destructor + */ + virtual ~OCResourceRequest(void) + { + } + + /** + * Retrieves the type of request string for the entity handler function to operate + * @return std::string request type. This could be 'GET'/'PUT'/'POST'/'DELETE' + */ + std::string getRequestType() const {return m_requestType;} + + /** + * Retrieves the query parameters from the request + * @return std::string query parameters in the request + */ + const QueryParamsMap& getQueryParameters() const {return m_queryParameters;} + + /** + * Retrieves the request handler flag type. This can be either INIT flag or + * REQUEST flag or OBSERVE flag. + * NOTE: + * INIT indicates that the vendor's entity handler should go and perform + * initialization operations + * REQUEST indicates that it is a request of certain type (GET/PUT/POST/DELETE) + * and entity handler needs to perform corresponding operations + * OBSERVE indicates that the request is of type Observe and entity handler + * needs to perform corresponding operations + * @return int type of request flag + */ + int getRequestHandlerFlag() const {return m_requestHandlerFlag;} + + /** + * Provides the entire resource attribute representation + * @return OCRepresentation reference containing the name value pairs + * representing the resource's attributes + */ + const OCRepresentation& getResourceRepresentation() const {return m_representation;} + + /** + * @return ObservationInfo reference provides observation information + */ + const ObservationInfo& getObservationInfo() const {return m_observationInfo;} + + /** + * sets resource uri + * @param resourceUri specifies the resource uri + */ + void setResourceUri(const std::string resourceUri) + { + m_resourceUri = resourceUri; + } + + /** + * gets resource uri + * @return std::string resource uri + */ + std::string getResourceUri(void) + { + return m_resourceUri; + } + + /** + * This API retrieves headerOptions which was sent from a client + * + * @return std::map HeaderOptions with the header options + */ + const HeaderOptions& getHeaderOptions() const + { + return m_headerOptions; + } + + /** + * This API retrieves the request handle + * + * @return OCRequestHandle + */ + const OCRequestHandle& getRequestHandle() const + { + return m_requestHandle; + } + + /** + * This API retrieves the resource handle + * + * return OCResourceHandle + */ + const OCResourceHandle& getResourceHandle() const + { + return m_resourceHandle; + } + + /** + * This API retrieves the request message ID + * + * @return int16_t value of message ID + */ + int16_t getMessageID() const {return m_messageID;} + + private: + std::string m_requestType; + std::string m_resourceUri; + QueryParamsMap m_queryParameters; + int m_requestHandlerFlag; + int16_t m_messageID; + OCRepresentation m_representation; + ObservationInfo m_observationInfo; + HeaderOptions m_headerOptions; + OCRequestHandle m_requestHandle; + OCResourceHandle m_resourceHandle; + + + private: + friend void (::formResourceRequest)(OCEntityHandlerFlag, OCEntityHandlerRequest*, + std::shared_ptr); + void setRequestType(const std::string& requestType) + { + m_requestType = requestType; + } + + void setPayload(OCPayload* requestPayload); + + void setQueryParams(QueryParamsMap& queryParams) + { + m_queryParameters = queryParams; + } + + void setRequestHandlerFlag(int requestHandlerFlag) + { + m_requestHandlerFlag = requestHandlerFlag; + } + + void setMessageID(int16_t messageID) + { + m_messageID = messageID; + } + + void setObservationInfo(const ObservationInfo& observationInfo) + { + m_observationInfo = observationInfo; + } + + void setHeaderOptions(const HeaderOptions& headerOptions) + { + m_headerOptions = headerOptions; + } + + /** + * This API allows to set request handle + * @param requestHandle - OCRequestHandle type used to set the + * request handle + */ + void setRequestHandle(const OCRequestHandle& requestHandle) + { + m_requestHandle = requestHandle; + } + + /** + * This API allows to set the resource handle + * @param resourceHandle - OCResourceHandle type used to set the + * resource handle + */ + void setResourceHandle(const OCResourceHandle& resourceHandle) + { + m_resourceHandle = resourceHandle; + } + + }; + }// namespace OC + +#endif // OC_RESOURCEREQUEST_H_ diff --git a/inc/iotivity/OCResourceResponse.h b/inc/iotivity/OCResourceResponse.h new file mode 100644 index 0000000..754f1ac --- /dev/null +++ b/inc/iotivity/OCResourceResponse.h @@ -0,0 +1,303 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/** + * @file + * + * This file contains the declaration of classes and its members related to + * ResourceResponse. + */ + +#ifndef OC_RESOURCERESPONSE_H_ +#define OC_RESOURCERESPONSE_H_ + +#include "OCApi.h" +#include +#include +#include + +namespace OC +{ + class InProcServerWrapper; + + /** + * @brief OCResourceResponse provides APIs to set the response details + */ + class OCResourceResponse + { + public: + typedef std::shared_ptr Ptr; + + OCResourceResponse(): + m_newResourceUri{}, + m_errorCode{}, + m_headerOptions{}, + m_interface{}, + m_representation{}, + m_requestHandle{0}, + m_resourceHandle{nullptr}, + m_responseResult{} + { + } + +#if defined(_MSC_VER) && (_MSC_VER < 1900) + OCResourceResponse(OCResourceResponse&& o): + m_newResourceUri(std::move(o.m_newResourceUri)), + m_errorCode(o.m_errorCode), + m_headerOptions(std::move(o.m_headerOptions)), + m_interface(std::move(o.m_interface)), + m_representation(std::move(o.m_representation)), + m_requestHandle(std::move(o.m_requestHandle)), + m_resourceHandle(std::move(o.m_resourceHandle)), + m_responseResult(std::move(o.m_responseResult)) + { + } + OCResourceResponse& operator=(OCResourceResponse&& o) + { + m_newResourceUri = std::move(o.m_newResourceUri); + m_errorCode = o.m_errorCode; + m_headerOptions = std::move(o.m_headerOptions); + m_interface = std::move(o.m_interface); + m_representation = std::move(o.m_representation); + m_requestHandle = std::move(o.m_requestHandle); + m_resourceHandle = std::move(o.m_resourceHandle); + m_responseResult = std::move(o.m_responseResult); + } +#else + OCResourceResponse(OCResourceResponse&&) = default; + OCResourceResponse& operator=(OCResourceResponse&&) = default; +#endif + virtual ~OCResourceResponse(void) {} + + /** + * This API sets the error code for this response + * @param eCode error code to set + */ + void setErrorCode(const int eCode) { m_errorCode = eCode; } + + /** + * gets new resource uri + * @return std::string new resource uri + */ + std::string getNewResourceUri(void) + { + return m_newResourceUri; + } + + /** + * sets new resource uri + * @param newResourceUri specifies the resource uri of the resource created + */ + void setNewResourceUri(const std::string newResourceUri) + { + m_newResourceUri = newResourceUri; + } + + /** + * This API allows to set headerOptions in the response + * @param headerOptions HeaderOptions vector consisting of OCHeaderOption objects + */ + void setHeaderOptions(const HeaderOptions& headerOptions) + { + m_headerOptions = headerOptions; + } + + /** + * This API allows to set request handle + * + * @param requestHandle - OCRequestHandle type used to set the request handle + */ + void setRequestHandle(const OCRequestHandle& requestHandle) + { + m_requestHandle = requestHandle; + } + + /** + * This API allows to set the resource handle + * + * @param resourceHandle - OCResourceHandle type used to set the resource handle + */ + void setResourceHandle(const OCResourceHandle& resourceHandle) + { + m_resourceHandle = resourceHandle; + } + + /** + * This API allows to set the EntityHandler response result + * + * @param responseResult - OCEntityHandlerResult type to set the result value + */ + void setResponseResult(const OCEntityHandlerResult& responseResult) + { + m_responseResult = responseResult; + } + + /** + * API to set the entire resource attribute representation + * @param rep reference to the resource's representation + * @param interface specifies the interface + */ + void setResourceRepresentation(OCRepresentation& rep, std::string iface) { + m_interface = iface; + m_representation = rep; + } + + /** + * API to set the entire resource attribute representation + * @param rep rvalue reference to the resource's representation + * @param interface specifies the interface + */ + void setResourceRepresentation(OCRepresentation&& rep, std::string iface) { + setResourceRepresentation(rep, iface); + } + + /** + * API to set the entire resource attribute representation + * @param rep reference to the resource's representation + */ + void setResourceRepresentation(OCRepresentation& rep) { + // Call the default + m_interface = DEFAULT_INTERFACE; + m_representation = rep; + } + + /** + * API to set the entire resource attribute representation + * @param rep rvalue reference to the resource's representation + */ + void setResourceRepresentation(OCRepresentation&& rep) { + // Call the above function + setResourceRepresentation(rep); + } + private: + std::string m_newResourceUri; + int m_errorCode; + HeaderOptions m_headerOptions; + std::string m_interface; + OCRepresentation m_representation; + OCRequestHandle m_requestHandle; + OCResourceHandle m_resourceHandle; + OCEntityHandlerResult m_responseResult; + + private: + friend class InProcServerWrapper; + + OCRepPayload* getPayload() const + { + MessageContainer inf; + OCRepresentation first(m_representation); + + if(m_interface==LINK_INTERFACE) + { + first.setInterfaceType(InterfaceType::LinkParent); + } + else if(m_interface==BATCH_INTERFACE) + { + first.setInterfaceType(InterfaceType::BatchParent); + } + else + { + first.setInterfaceType(InterfaceType::DefaultParent); + } + + inf.addRepresentation(first); + + for(const OCRepresentation& rep : m_representation.getChildren()) + { + OCRepresentation cur(rep); + + if(m_interface==LINK_INTERFACE) + { + cur.setInterfaceType(InterfaceType::LinkChild); + } + else if(m_interface==BATCH_INTERFACE) + { + cur.setInterfaceType(InterfaceType::BatchChild); + } + else + { + cur.setInterfaceType(InterfaceType::DefaultChild); + } + + inf.addRepresentation(cur); + + } + + return inf.getPayload(); + } + public: + + /** + * Get error code + */ + int getErrorCode() const + { + return m_errorCode; + } + + /** + * Get the Response Representation + */ + const OCRepresentation& getResourceRepresentation() const + { + return m_representation; + } + /** + * This API allows to retrieve headerOptions from a response + */ + const HeaderOptions& getHeaderOptions() const + { + return m_headerOptions; + } + + /** + * This API retrieves the request handle + * + * @return OCRequestHandle value + */ + const OCRequestHandle& getRequestHandle() const + { + return m_requestHandle; + } + + /** + * This API retrieves the resource handle + * + * @return OCResourceHandle value + */ + const OCResourceHandle& getResourceHandle() const + { + return m_resourceHandle; + } + + /** + * This API retrieves the entity handle response result + * + * @return OCEntityHandler result value + */ + OCEntityHandlerResult getResponseResult() const + { + return m_responseResult; + } + }; + +} // namespace OC + +#endif // OC_RESOURCERESPONSE_H_ diff --git a/inc/iotivity/OCSerialization.h b/inc/iotivity/OCSerialization.h new file mode 100644 index 0000000..b7ba781 --- /dev/null +++ b/inc/iotivity/OCSerialization.h @@ -0,0 +1,164 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#include +#include "ocpayload.h" +#include "ocrandom.h" +#include "oic_string.h" + +namespace OC +{ + class ListenOCContainer + { + private: + static std::vector StringLLToVector(OCStringLL* ll) + { + std::vector strs; + while(ll) + { + strs.push_back(ll->value); + ll = ll->next; + } + return strs; + } + + public: + ListenOCContainer(std::weak_ptr cw, + OCDevAddr& devAddr, OCDiscoveryPayload* payload) + : m_clientWrapper(cw), m_devAddr(devAddr) + { + while (payload) + { + OCResourcePayload* res = payload->resources; + while (res) + { + if (res->secure) + { + m_devAddr.flags = + (OCTransportFlags)(OC_FLAG_SECURE | m_devAddr.flags); + } + + if (res->port != 0) + { + m_devAddr.port = res->port; + } + + if (payload->baseURI) + { + OCDevAddr rdPubAddr = m_devAddr; + + std::string baseURI = std::string(payload->baseURI); + size_t len = baseURI.length(); + int addressLen = baseURI.find_first_of(":"); + std::string ipaddress = baseURI.substr(0, addressLen); + int port = atoi(baseURI.substr(addressLen + 1, len).c_str()); + OICStrcpy(rdPubAddr.addr, addressLen + 1, ipaddress.c_str()); + rdPubAddr.port = port; + m_resources.push_back(std::shared_ptr( + new OC::OCResource(m_clientWrapper, rdPubAddr, + std::string(res->uri), + std::string(payload->sid), + res->bitmap, + StringLLToVector(res->types), + StringLLToVector(res->interfaces) + ))); + } + else + { + m_resources.push_back(std::shared_ptr( + new OC::OCResource(m_clientWrapper, m_devAddr, + std::string(res->uri), + std::string(payload->sid), + res->bitmap, + StringLLToVector(res->types), + StringLLToVector(res->interfaces) + ))); + +#ifdef TCP_ADAPTER + if (res->tcpPort != 0) + { + OCDevAddr tcpDevAddr = m_devAddr; + tcpDevAddr.port = res->tcpPort; + tcpDevAddr.adapter = OC_ADAPTER_TCP; + m_resources.push_back(std::shared_ptr( + new OC::OCResource(m_clientWrapper, tcpDevAddr, + std::string(res->uri), + std::string(payload->sid), + res->bitmap, + StringLLToVector(res->types), + StringLLToVector(res->interfaces) + ))); + } +#endif + } + res = res->next; + } + payload = payload->next; + } + } + +#ifdef WITH_MQ + ListenOCContainer(std::weak_ptr cw, + OCDevAddr& devAddr, OCRepPayload* payload) + : m_clientWrapper(cw), m_devAddr(devAddr) + { + if (payload) + { + char**topicList = nullptr; + size_t dimensions[MAX_REP_ARRAY_DEPTH] = {0}; + OCRepPayloadGetStringArray(payload, "topiclist", &topicList, dimensions); + + for(size_t idx = 0; idx < dimensions[0]; idx++) + { + m_resources.push_back(std::shared_ptr( + new OC::OCResource(m_clientWrapper, m_devAddr, + std::string(topicList[idx]), + "", + OC_OBSERVABLE, + {OC_RSRVD_RESOURCE_TYPE_MQ_TOPIC}, + {DEFAULT_INTERFACE}))); + } + } + } + + ListenOCContainer(std::weak_ptr cw, + OCDevAddr& devAddr, const std::string& topicUri) + : m_clientWrapper(cw), m_devAddr(devAddr) + { + m_resources.push_back(std::shared_ptr( + new OC::OCResource(m_clientWrapper, m_devAddr, + topicUri, + "", + OC_OBSERVABLE, + {OC_RSRVD_RESOURCE_TYPE_MQ_TOPIC}, + {DEFAULT_INTERFACE}))); + } +#endif + + const std::vector>& Resources() const + { + return m_resources; + } + private: + std::vector> m_resources; + std::weak_ptr m_clientWrapper; + OCDevAddr& m_devAddr; + }; +} diff --git a/inc/iotivity/OCUtilities.h b/inc/iotivity/OCUtilities.h new file mode 100644 index 0000000..85039d0 --- /dev/null +++ b/inc/iotivity/OCUtilities.h @@ -0,0 +1,148 @@ +//****************************************************************** +// +// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#ifndef OC_UTILITIES_H_ +#define OC_UTILITIES_H_ + +#include +#include +#include +#include +#include + +#include +#include + +namespace OC { + namespace Utilities { + + typedef std::map QueryParamsKeyVal; + + /* + * @brief helper function that parses the query parameters component + * of a URI into a key-value map. This function expects the uri + * parameter to contain the query parameters component of a URI + * (everything after the '?', excluding anything anchors). + * + * Note that output will not perform URL decoding + */ + QueryParamsKeyVal getQueryParams(const std::string& uri); + } +} + +/* The C++11 standard unfortunately forgot to provide make_unique<>! However, if we're +using C++14 or later, we want to take the standard library's implementation: */ +namespace OC { +#if defined(__cplusplus) && __cplusplus < 201300 + + template + std::unique_ptr make_unique(XS&& ...xs) + { + return std::unique_ptr(new T(std::forward(xs)...)); + } + +#else + using std::make_unique; +#endif +} // namespace OC + +namespace OC { + + /* Examine an OCStackResult, and either forward its value or raise an exception: */ + OCStackResult result_guard(const OCStackResult r); + + /* Check for a nullptr, and throw an exception if we see one; otherwise, return the + result of the function call: */ + template + auto nil_guard(PtrT&& p, FnT&& fn, ParamTs&& ...params) -> OCStackResult + { + if(nullptr == p) + { + throw OCException(OC::Exception::NIL_GUARD_NULL, OC_STACK_INVALID_PARAM); + } + + // Note that the parameters are being passed by reference to std::bind. This is not an + // issue, as it is this function's parameters that are being passed by reference. So, + // unless the parameters are being passed by reference to here (or to checked_guard), + // they won't be modified. + return std::bind(fn, p, std::ref(params)...)(); + } + + /* Check for nullptr and forward the result of an OC function call on success; raise + an exception on failure or exceptional result: */ + template + auto checked_guard(PtrT&& p, FnT&& fn, ParamTs&& ...params) -> OCStackResult + { + return result_guard(nil_guard(p, fn, std::forward(params)...)); + } + +} // namespace OC + +namespace OC +{ + template + struct is_vector + { + BOOST_STATIC_CONSTEXPR bool value = false; + }; + + template + struct is_vector >::value + >::type + > + { + BOOST_STATIC_CONSTEXPR bool value = true; + }; + + // type trait to remove the first type from a parameter-packed list + template + struct remove_first; + + // specialization that does all the work + template