diff --git a/SConstruct b/SConstruct index 0da7e319c63a5bfe031be0a772ac2a094a61feda..c41b534a3d6ddd6477a09ccb37aace19bcccc373 100644 --- a/SConstruct +++ b/SConstruct @@ -65,6 +65,8 @@ SConscript(build_dir + 'resource/SConscript') if target_os not in ['arduino','darwin','ios', 'android', 'msys_nt', 'windows']: SConscript(build_dir + 'examples/OICMiddle/SConscript') + if env.get('SECURED') == '1': + SConscript(build_dir + 'examples/OCFSecure/SConscript') java_build = None if (env.get('BUILD_JAVA') and env.get('JAVA_HOME')) or target_os == 'android': diff --git a/examples/OCFSecure/PICS_server_OCF10_vprime.json b/examples/OCFSecure/PICS_server_OCF10_vprime.json new file mode 100644 index 0000000000000000000000000000000000000000..f2b9d98678893c0071955a1f873772358c1a529a --- /dev/null +++ b/examples/OCFSecure/PICS_server_OCF10_vprime.json @@ -0,0 +1,26 @@ +{ + "role": "Server", + "supportedVerticalProfile": ["Smart Home"], + "supportedDeviceTypes": ["oic.d.switch"], + "icv": "ocf.1.0.0", + "dmv": "ocf.res.1.0.0, ocf.sh.1.0.0", + "resources": ["oic.r.switch.binary", "oic.r.csr", "oic.r.crl", "oic.r.roles"], + "jurisdictionSwitch": false, + "OTM":["oic.sec.doxm.jw"], + "contentFormatVersion": ["1.0.0"], + "acceptVersion": ["1.0.0"], + "observableOICRES": false, + "sct": 9, + "persistentDeviceuuid": false, + "RDPublishCapability": false, + "SSIDSoftAP": "", + "PasswordSoftAP": "", + "canTurnOnSoftApManually": true, + "minNotifyPeriod": [0,10], + "maxNotifyPeriod": [0,10], + "threshold": [0,5], + "threshold_recommended_value": 2, + "company": "Vprime", + "device": "OCF Developer kit", + "multiValueQuerySupport": true +} \ No newline at end of file diff --git a/examples/OCFSecure/README.md b/examples/OCFSecure/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2cda31486f4d376b9b89f9e7b2eec9eb895cc2a6 --- /dev/null +++ b/examples/OCFSecure/README.md @@ -0,0 +1,363 @@ +# Introduction +This is a sample secure application using the "justworks" security model +There are 2 applications; server and client, which need to be running from 2 +different terminals regardless whether those 2 terminals are running within +the same machine or not as long as they can discover each other. +These 2 applications are verified on +* a regular Ubuntu machine +* Ubuntu running on Intel Joule +* Raspbian running on Raspberry Pi 3 and Raspberry Pi Zero W + +These applications can be used to verify the build environment is setup +properly. They can serve as a baseline and a reference for new developers to +learn how to write simple server and client applications and implement OCF +security and pass the OCF certification test tool. + +# Building the applications + +To build the applications, type the following scons command from the root +directory of IoTivity + +``` +$ scons examples/OCFSecure TARGET_TRANSPORT=IP +``` + +To speed up the build procerss and utilize more than a single core, you can +add the -j option followed by the number of cores to utilize for building +the applications + +To build the applications in the debug mode, you can add the following option +to the scons command RELEASE=0 + +# Running the applications + +To run the applications on a regular machine with Ubuntu, change the directory +to out/linux/x86_64/release/examples/OCFSecure with the following command +``` +$ cd out/linux/x86_64/release/examples/OCFSecure/ +``` +Next, run the server application with the following command +``` +$ ./server +``` +open up another terminal window within the same directory +(shortcut:Ctrl+Shift+n) and run the client application with the following +command. +``` +$ ./client +``` +Since there is no physical led attached to a regular machine with Ubuntu, the +led resource will be simulated. Otherwise, if you are running these +applications on a Raspberry Pi or Intel Joule board then you would need to +run the server application with the sudo command so the server application +can have access to the hardware of the board. + +If successful, you should be able to see the list of discovered resources +in the client terminal as shown below. +``` +Discovered Resources: + #0: /oic/res @224.0.1.187:5683 resource type: nil + #1: /oic/sec/doxm @fe80::3749:e171:d50f:966d%enp0s3:42825 resource type + #2: /oic/sec/pstat @fe80::3749:e171:d50f:966d%enp0s3:0 resource type + #3: /oic/sec/acl2 @10.0.2.15:47132 resource type: oic.r.acl2 + #4: /oic/sec/cred @10.0.2.15:47132 resource type: oic.r.cred + #5: /oic/sec/crl @10.0.2.15:47132 resource type: oic.r.crl + #6: /oic/sec/csr @10.0.2.15:47132 resource type: oic.r.csr + #7: /oic/sec/roles @10.0.2.15:47132 resource type: oic.r.roles + #8: /oic/d @10.0.2.15:47132 resource type: oic.wk.d + #9: /oic/p @10.0.2.15:0 resource type: oic.wk.p + #10: /introspection @10.0.2.15:0 resource type: oic.wk.introspection + +Request Methods: 1: GET 4: POST +Usage:\ \ : +``` +Usually, you might need to press enter a couple of times to refresh the stdout +to finally see the complete list like so. +``` +Discovered Resources: + #0: /oic/res @224.0.1.187:5683 resource type: nil + #1: /oic/sec/doxm @fe80::3749:e171:d50f:966d%enp0s3:42825 resource type + #2: /oic/sec/pstat @fe80::3749:e171:d50f:966d%enp0s3:0 resource type + #3: /oic/sec/acl2 @10.0.2.15:47132 resource type: oic.r.acl2 + #4: /oic/sec/cred @10.0.2.15:47132 resource type: oic.r.cred + #5: /oic/sec/crl @10.0.2.15:47132 resource type: oic.r.crl + #6: /oic/sec/csr @10.0.2.15:47132 resource type: oic.r.csr + #7: /oic/sec/roles @10.0.2.15:47132 resource type: oic.r.roles + #8: /oic/d @10.0.2.15:47132 resource type: oic.wk.d + #9: /oic/p @10.0.2.15:0 resource type: oic.wk.p + #10: /introspection @10.0.2.15:0 resource type: oic.wk.introspection + #11: /oic/sec/doxm @fe80::5c79:f160:691d:40bd%enp0s8:42825 resource type + #12: /oic/sec/pstat @fe80::5c79:f160:691d:40bd%enp0s8:0 resource type + #13: /oic/sec/acl2 @192.168.56.101:47132 resource type: oic.r.acl2 + #14: /oic/sec/cred @192.168.56.101:47132 resource type: oic.r.cred + #15: /oic/sec/crl @192.168.56.101:47132 resource type: oic.r.crl + #16: /oic/sec/csr @192.168.56.101:47132 resource type: oic.r.csr + #17: /oic/sec/roles @192.168.56.101:47132 resource type: oic.r.roles + #18: /oic/d @192.168.56.101:47132 resource type: oic.wk.d + #19: /oic/p @192.168.56.101:0 resource type: oic.wk.p + #20: /introspection @192.168.56.101:0 resource type: oic.wk.introspection + #21: /oic/sec/doxm @fe80::3749:e171:d50f:966d%enp0s3:59488 resource type + #22: /oic/sec/pstat @fe80::3749:e171:d50f:966d%enp0s3:0 resource type + #23: /oic/sec/acl2 @10.0.2.15:50400 resource type: oic.r.acl2 + #24: /oic/sec/cred @10.0.2.15:50400 resource type: oic.r.cred + #25: /oic/sec/crl @10.0.2.15:50400 resource type: oic.r.crl + #26: /oic/sec/csr @10.0.2.15:50400 resource type: oic.r.csr + #27: /oic/sec/roles @10.0.2.15:50400 resource type: oic.r.roles + #28: /oic/d @10.0.2.15:50400 resource type: oic.wk.d + #29: /oic/p @10.0.2.15:0 resource type: oic.wk.p + #30: /introspection @10.0.2.15:0 resource type: oic.wk.introspection + #31: /switch @10.0.2.15:50400 resource type: oic.r.switch.binary + #32: /oic/sec/doxm @fe80::5c79:f160:691d:40bd%enp0s8:59488 resource type + #33: /oic/sec/pstat @fe80::5c79:f160:691d:40bd%enp0s8:0 resource type + #34: /oic/sec/acl2 @192.168.56.101:50400 resource type: oic.r.acl2 + #35: /oic/sec/cred @192.168.56.101:50400 resource type: oic.r.cred + #36: /oic/sec/crl @192.168.56.101:50400 resource type: oic.r.crl + #37: /oic/sec/csr @192.168.56.101:50400 resource type: oic.r.csr + #38: /oic/sec/roles @192.168.56.101:50400 resource type: oic.r.roles + #39: /oic/d @192.168.56.101:50400 resource type: oic.wk.d + #40: /oic/p @192.168.56.101:0 resource type: oic.wk.p + #41: /introspection @192.168.56.101:0 resource type: oic.wk.introspection + #42: /switch @192.168.56.101:50400 resource type: oic.r.switch.binary + +Request Methods: 1: GET 4: POST +Usage:\ \ : +``` +Notice the "/switch" uri on resources #31 and #42. This is a known issue will +be fixed at the soonest chance. be aware, the "/switch" uri might occure more +than twice and not all of them are going to work. However, one of them will +work. + +As instructed in the client application. you can enter the number of the +discovered resource you want to interact with (which is either 31 or 42 in this +case) followed by 1 for issuing a GET request or 4 for a POST request. +If you decided to issue a GET request, you should see the following GET +response if everything went OK. + +``` +========================================================= +Result: (0) - OC_STACK_OK +07:12.062 INFO: PayloadLog: Payload Type: Representation +07:12.062 INFO: PayloadLog: Resource #1 +07:12.062 INFO: PayloadLog: Resource Types: +07:12.062 INFO: PayloadLog: oic.r.switch.binary +07:12.062 INFO: PayloadLog: Interfaces: +07:12.062 INFO: PayloadLog: oic.if.baseline +07:12.062 INFO: PayloadLog: oic.if.a +07:12.062 INFO: PayloadLog: Values: +07:12.062 INFO: PayloadLog: value(bool):false +========================================================== +``` +If you decided to issue a POST request, you will be prompted to create a custom +payload to be attached to the POST request. As of right now, the only supported +feature is turning the led on and off. As a result, type 0 to select the +boolean data type then follow it with the name of the property (the key) which +is "value" (without quotes as it is writing in the GET response above) +and then follow that with (the value) either 1 to turn the led on +or 0 to turn the led off. Next press ENTER twice; once to end the first +key-value pair entry and once again for completing the custom payload creation. + +Below is a copy of an example usage. +``` + #42: /switch @192.168.56.101:50400 resource type: oic.r.switch.binary + +Request Methods: 1: GET 4: POST +Usage: :42 4 + +Need to create a custom POST payload +Enter key value pairs as: +Type: 0:bool 1:int 2:double 3:string +press ENTER to finish :0 value 1 +press ENTER to finish : +``` + +If successful, you should see the following POST response +``` +========================================================== +Result: (4) - OC_STACK_RESOURCE_CHANGED +08:24.366 INFO: PayloadLog: Payload Type: Representation +08:24.366 INFO: PayloadLog: Resource #1 +08:24.366 INFO: PayloadLog: Resource Types: +08:24.366 INFO: PayloadLog: oic.r.switch.binary +08:24.366 INFO: PayloadLog: Interfaces: +08:24.366 INFO: PayloadLog: oic.if.baseline +08:24.366 INFO: PayloadLog: oic.if.a +08:24.366 INFO: PayloadLog: Values: +08:24.366 INFO: PayloadLog: value(bool):true +========================================================== +``` +If for whatever reason you noticed the following response instead, then there +is a security issue. Hopefully, you will not see this! +``` +========================================================== +Result: (46) - OC_STACK_UNAUTHORIZED_REQ +10:16.370 INFO: PayloadLog: NULL Payload +========================================================== +``` +To run the applications on either the Intel Joule or the Raspberry Pi, the mraa +library must be installed! this is the library that is used to control the +physical hardware. Without it, you will still get the simulated led but it is +not as fun as the real led turning on and off in the physical world that you +can control with your own software! Install it, it is worth it ;) + +Installing mraa on the intel joule. From the home directory, type commands +* $sudo add-apt-repository ppa:mraa/mraa +* $sudo apt-get update +* $sudo apt-get install libmraa1 libmraa-dev mraa-tools python-mraa python3-mraa + +Installing mraa on the raspberry pi, from the parent directory of IoTivity's +root directory, type the following commands. +* $ git clone https://github.com/intel-iot-devkit/mraa.git +* $ cd mraa && mkdir build && cd build && cmake .. && make +* $ sudo make install + +To run the applications on Intel Joule running ubuntu then the built-in +led on gpio 100 will be connected to the server and you would be able to +control it with the client application. It is important to remember to run the +server applications in sudo mode as hardware access is a super user privilege! +``` +$ sudo ./server +``` +Otherwise, you would get an error with unknown gpio or sometimes you will not +get any errors but the built-in led will not respond to your control. It is the +same usage as running the applications on a regular machine with Ubuntu which +should be described above. + +To run the applications on Raspberry Pi with Raspian then make sure to connect +an LED on hardware pin 4 which is gpio 7! The pin mapping of raspberry pi is +just messed up like that! Google raspberry pi pinout +This pin has all the following names +* BCM pin 4 +* Physical pin 7 +* Wiring Pi pin 7 + +Anyways, have a jumper wire from GPIO 7 to the positive terminal of the led. +Then connect a resistor from the negative terminal of the led to ground. + +Also, it is important to remember to run the server application in sudo mode as +hardware access is a super user privilege. Otherwise, you might get an error of +unknown gpio or the app might run but will not control the led and you might +think you connected the led on the wrong pin which may not be the case. + +You can also connect the Enviro pHat sensor board if you have it. Its LED is +already connected to gpio 7. + +# Testing the server app against CTT +You need to install the OCF Certification Test Tool 2.0 on a Windows machine +and start it and if the windows machine on the same network as the server and +the server app is running then the CTT should discover the server. If not, +please check the correct network interface from the options menu and then +press the Select IUT button or from the File menu. A pop-up window will +show the discovered devices and you should be able to see the server device +as 12345678-1234-1234-1234-123456789012 and in the details section, you +should be able to see the /switch uri. click on Next. Now, browse to select +the PICS file which should be included in this example named +PICS_server_OCF10_vprime.json then click on Next. From the Testing Profiles +uncheck everything and check OCF 1.0 Server. Next, click on +Run All Test Cases button. Most likely, you will get a prompt saying +"Please initiate device to revert to "ready for OTM" state" and there are +2 options to click on; OK and Cancel because this sample is shipped in the +"Ready for Normal Operation" state. In this case, kill the server with +Ctrl+C and from the output directory where the server is running, copy the +ocf_svr_db_server_RFOTM.dat from the project directory to the project output +directory and name it as ocf_svr_db_server.dat as shown in the following +command then re-run the server app then press OK on the prompt once the +server is running again. +``` +cp ~/iot/iotivity/examples/OCFSecure/ocf_svr_db_server_RFOTM.dat ocf_svr_db_server.dat +``` +You might get this prompt again since the CTT does not un-onboard the device +but now you know what to do! +Also, you will be prompt to power cycle the device. In this case, you can +either kill the server app and restart it again or literally power cycle +your device and re-run the server app once your device is back up and +connected to the same network. +Please note, you might see tests passing with warnings and CT1.7.8.11 test +Case failing but that is OK. + +# Known issues + +1. Sometimes, the applications will not run because of not finding some library. +In this case, you would need to export the LD_LIBRARY_PATH to the environment. + ``` + export LD_LIBRARY_PATH= + ``` + Also, since you would need to run the server application in sudo mode, you +would need to type this command + ``` + $sudo ldconfig + ``` +and you might also need to type + ``` + $sudo env LD_LIBRARY_PATH= + ``` +Hopefully, you will not run into any library issues but if you run into any +issue with this application, please send me an e-mail at ralshafi@vprime.com +and file a bug in JIRA and assign it to me (username: alshafi). + +2. Multiple endpoints get discovered and they need to be filtered out +eventually. In the meantime, there will be multiple /switch links and only one +of them works and the user will need to issues GET requests to all of them +until the good one is found. The wrong /switch links will result in +Result: (255) - OC_STACK_ERROR. +The correct /a/led link will result in Result: (0) - OC_STACK_OK + +# Example Directory + +There are 16 files in the example directory. +* client.c + * This is the client program +* device_properties.dat + * This is a file storing the device properties in cbor format which is +generated automatically by the server application +* ocf_svr_db_client.dat + * This is the cbor format of the secure virtual resource database, defined +by the human-readable version ocf_svr_db_client.json file, and it is used by +the client application +* ocf_svr_db_client.json + * This is the human-readable version of ocf_svr_db_client.dat +* ocf_svr_db_server.dat + * This is the cbor format of the secure virtual resource database and it is +an exact copy from the ocf_svr_db_server_RFNOP.dat which is the cbor version of +the human-readable version ocf_svr_db_server_RFNOP.json file. This is the case +because the client application does not support the onboarding and provisioning +process currently and we need to set the state in the "Ready For Normal +Operation" manually. +We also need to set the state in the "Ready For Ownership Method Transfer" +when testing the application with the OCF Certification Test Tool (CTT). +In this case, you would need to copy ocf_svr_db_server_RFOTM.dat into +ocf_svr_db_server.dat since that is the file that will be read by the server. +* ocf_svr_db_server_RFNOP.dat + * This is the cbor format of the secure virtual resource database, defined +by the human-readable version ocf_svr_db_server_RFNOP.json file and it is *NOT* +used by the server application. Rename it without the _RFNOP suffix to be read +by the server +* ocf_svr_db_server_RFNOP.json + * This is the human-readable version of ocf_svr_db_server_RFNOP.dat +* ocf_svr_db_server_RFOTM.dat + * This is the cbor format of the secure virtual resource database, defined +by the human-readable version ocf_svr_db_server_RFOTM.json file and it is *NOT* +used by the server application. Rename it without the _RFOTM suffix to be read +by the server +* ocf_svr_db_server_RFOTM.json + * This is the human-readable version of ocf_svr_db_server_RFOTM.dat +* PICS_server_OCF10_vprime.json + * This is the file that was used as the input to the OCF Certification +Test Tool. +* README.md + * This is this file :) +* SConscript + * This is the script that is being used by the scons tool to know how +to build the sample applications and what needs to be copied to the output +directory. +* server.cpp + * This is the server program. +* switch_introspection.dat + * This is the cbor format of the introspection file (also known as +Introspection Device Data IDD) the server needs to read to implement +the introspection feature. +* switch_introspection.json + * This is the human-readable version of switch_introspection.dat file +which is also know as the "swagger" file. +* utilities.c + * this is a supplementary program containing custom utility c functions +that help with reporting log messages mainly as of current. diff --git a/examples/OCFSecure/SConscript b/examples/OCFSecure/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..97ab880d7a0ebc4624814e221a2a27f60bb6adb5 --- /dev/null +++ b/examples/OCFSecure/SConscript @@ -0,0 +1,117 @@ +# /****************************************************************** +# * +# * Copyright 2017 Vprime 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. +# * +# ***************************************************************** +# \author Rami Alshafi +# */ + +Import('env') +import os +import os.path +import platform as p +target_os = env.get('TARGET_OS') +target_arch = env.get('TARGET_ARCH') +samples_env = env.Clone() +src_dir = env.get('SRC_DIR') +build_dir = env.get('BUILD_DIR') + +###################################################################### +# Build flags +###################################################################### +samples_env.PrependUnique(CPPPATH=[ + '#/resource/include/', + '#/resource/csdk/include', + '#/resource/csdk/stack/include', + '#/resource/csdk/stack/include/experimental', + '#/resource/csdk/security/include', + '#/resource/csdk/connectivity/api', + '#/resource/oc_logger/include', + '#/resource/csdk/logger/include/experimental' +]) +cpp_defines = ['__WITH_DTLS__', 'TB_LOG'] +libraries = ['octbstack', 'oc'] +# identify which hardware the samples will be running on. +platform_info = p.platform() +joule = 'Linux' in platform_info and 'joule' in platform_info and \ +'Ubuntu' in platform_info +raspberry_pi = 'Linux' in platform_info and \ +('armv7l' in platform_info or 'armv6l' in platform_info) and \ +'debian' in platform_info +if joule or raspberry_pi: + conf = Configure(env) + if not conf.CheckCXXHeader('mraa.hpp'): + print("required library mraa not installed! ") + if joule and not raspberry_pi: + print(" To install mraa\n\ + $sudo add-apt-repository ppa:mraa/mraa\n\ + $sudo apt-get update\n\ + $sudo apt-get install libmraa1 libmraa-dev\ + mraa-tools python-mraa python3-mraa\n") + elif not joule and raspberry_pi: + print("to install mraa\n\ + $git clone https://github.com/intel-iot-devkit/\ + mraa.git ../mraa\n\ + $mkdir ../mraa/build && cd ../mraa/build && cmake .. && make\n\ + $sudo make install") + else: + print("please install mraa") + else: + cpp_defines.append('WITH_MRAA') + libraries.append('mraa') + if joule and not raspberry_pi: + cpp_defines.append('JOULE') + elif not joule and raspberry_pi: + cpp_defines.append('RASPBERRY') + else: + print "ERROR: unknown board" + conf.Finish() +samples_env.AppendUnique(RPATH=[build_dir]) +samples_env.AppendUnique(CPPDEFINES=cpp_defines) +samples_env.AppendUnique(CFLAGS=['-std=c99']) +samples_env.AppendUnique(CXXFLAGS=['-std=c++0x', '-Wall', '-Wextra', '-Werror', + '-pthread', '-fpermissive']) +samples_env.PrependUnique(LIBS=libraries) +if target_arch in ['x86_64', 'arm64']: + samples_env.AppendUnique(CPPFLAGS=['-Llib64']) +else: + samples_env.AppendUnique(CPPFLAGS=['-Llib']) +if env.get('SECURED') == '1': + samples_env.AppendUnique(LIBS=['mbedtls', 'mbedx509', 'mbedcrypto']) +if target_os in ['linux']: + samples_env.ParseConfig('pkg-config --cflags --libs sqlite3') + +###################################################################### +# Source files and Targets +###################################################################### +client = samples_env.Program('client', ['client.c']) +server = samples_env.Program('server', ['server.cpp']) +examples_dir = '/examples/OCFSecure/' +client_dat = samples_env.Install( + build_dir + examples_dir, src_dir + examples_dir + 'ocf_svr_db_client.dat') +client_dev = samples_env.Install( + build_dir + examples_dir, src_dir + examples_dir + 'device_properties.dat') +server_dat = samples_env.Install( + build_dir + examples_dir, src_dir + examples_dir + 'ocf_svr_db_server.dat') +introspection_dat = samples_env.Install( + build_dir + examples_dir, src_dir + examples_dir + 'switch_introspection.dat') + +list_of_samples = [client, client_dat, client_dev, server, server_dat] + +Alias("secureExamples", list_of_samples) + +env.AppendTarget('secureExamples') diff --git a/examples/OCFSecure/client.c b/examples/OCFSecure/client.c new file mode 100644 index 0000000000000000000000000000000000000000..d161b3b7734b8113643b7cfd442f515eaa74b34c --- /dev/null +++ b/examples/OCFSecure/client.c @@ -0,0 +1,585 @@ +/****************************************************************** +* +* Copyright 2018 Vprime 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. +* +***************************************************************** +\author Rami Alshafi +*/ +/////////////////////////////////////////////////////////////////////// +//NOTE : This sample server is generated based on IotivityandZigbeeClient.c +/////////////////////////////////////////////////////////////////////// + + +#include +#include +#include "payload_logging.h" +#include "utilities.c" +#include "ocstackconfig.h" + +#define DEFAULT_CONTEXT_VALUE (0x99) +#define MAX_RESOURCE_TYPE_SIZE (32) +#define MAX_RESOURCES_REMEMBERED (100) +#define MAX_USER_INPUT (100) +#define TAG "CLIENT_APP" + +static uint32_t DISC_RES_COUNTER = 0; +static bool PROMPT_USER = false; +static char SVR_DB[] = "./ocf_svr_db_client.dat"; +static char DEV_PROP[] = "./device_properties.dat"; + +static bool STOP = false; +typedef struct +{ + char uri[MAX_URI_LENGTH]; + char resourceType[MAX_RESOURCE_TYPE_SIZE]; + OCDevAddr address; + +} DiscoveredResourceInfo; + +static DiscoveredResourceInfo DISC_RES[MAX_RESOURCES_REMEMBERED]; + + +/** +* Utility method to print the list of discovered resources to the stdout +*/ +static void +PrintDiscoveredResources(void) +{ + printf("=============================================================\n"); + printf("Discovered Resources:\n"); + for(uint32_t i = 0; i < DISC_RES_COUNTER; ++i) + { + DiscoveredResourceInfo currentResource = DISC_RES[i]; + + printf("\t#%u: uri:%s\taddr:%s\tport: %u\tresource type: %s\n", + i, + currentResource.uri, + currentResource.address.addr, + currentResource.address.port, + currentResource.resourceType); + } +} + + +/** +* Utility method to format and print the response result to the stdout. +* +* @param[in] clientResponse contains the content to be printed. +*/ +void +PrintFormattedResult(OCClientResponse *clientResponse) +{ + OCStackResult clientResult = clientResponse->result; + printf("==========================================================\n"); + printf("Result: (%d) - %s\n", clientResult, + decode_oc_stack_result(clientResult)); + OIC_LOG_PAYLOAD(INFO, clientResponse->payload); + printf("==========================================================\n"); +} + + +/** +* Method to register the discovered resources. +* +* @param[in] clientResponse containing info about discovered resources. +*/ +void +RegisterDiscoveredResources(OCClientResponse *clientResponse) +{ + if (!(OCDiscoveryPayload*)clientResponse->payload) + { + OIC_LOG_V(INFO, TAG, + "[%s] Could not discover any resources.", __func__); + return; + } + OCResourcePayload* discoveredResource = + ((OCDiscoveryPayload*)(clientResponse->payload))->resources; + while (discoveredResource && discoveredResource != discoveredResource->next) + { + if (DISC_RES_COUNTER == MAX_RESOURCES_REMEMBERED) + { + OIC_LOG_V(WARNING, TAG, + "[%s] Max of %u resources reached. Ignoring the rest.", + __func__, MAX_RESOURCES_REMEMBERED); + break; + } + // 'oic/res' must be 1st resource to test out queries and its responses. + if (DISC_RES_COUNTER == 0) + { + strncpy(DISC_RES[DISC_RES_COUNTER].uri, + clientResponse->resourceUri, MAX_URI_LENGTH - 1); + strncpy(DISC_RES[DISC_RES_COUNTER].resourceType, + OC_RSRVD_RESOURCE_TYPE_RES, MAX_RESOURCE_TYPE_SIZE - 1); + DISC_RES[DISC_RES_COUNTER].address = clientResponse->devAddr; + ++DISC_RES_COUNTER; + } + + strncpy(DISC_RES[DISC_RES_COUNTER].uri, + discoveredResource->uri, MAX_URI_LENGTH - 1); + + strncpy(DISC_RES[DISC_RES_COUNTER].resourceType, + discoveredResource->types->value, MAX_RESOURCE_TYPE_SIZE - 1); + DISC_RES[DISC_RES_COUNTER].address = clientResponse->devAddr; + // secure the endpoint of the discovered secure resource. + if (discoveredResource->eps->family & OC_FLAG_SECURE) + { + if (0 == strcmp(discoveredResource->eps->tps, "coaps")) + { + strncpy(clientResponse->devAddr.addr, + discoveredResource->eps->addr, + sizeof(clientResponse->devAddr.addr)); + clientResponse->devAddr.port = discoveredResource->eps->port; + clientResponse->devAddr.flags = + (OCTransportFlags)(discoveredResource->eps->family | OC_SECURE); + OIC_LOG_V(INFO, TAG, "[%s] DTLS port: %d", + __func__, + clientResponse->devAddr.port); + } + } + ++DISC_RES_COUNTER; + discoveredResource = discoveredResource->next; + } + +} + + +/** +* Internal method to invoke the OCDoRequest API +* +* @param[in] requestUri resource URI used to invoke the request. +* @param[in] payload payload used to invoke the request +* @param[in] method the desired method to be used to invoke the request +* @param[in] cb the call back handler to be used to invoke the request +* @param[in] address the address to be used to invoke the request +* +* @return stack result +*/ +OCStackResult +InvokeOCDoRequest(const char *requestUri, + OCPayload *payload, + OCMethod method, + OCClientResponseHandler cb, + OCDevAddr *address) +{ + OCCallbackData cbData = { + .context = (void*)DEFAULT_CONTEXT_VALUE, + .cb = cb + }; + + OCConnectivityType connType = CT_ADAPTER_IP; + OCQualityOfService qos = OC_LOW_QOS; + OCDoHandle handle = NULL; + uint8_t numOptions = 0; + + OCStackResult ret = OCDoRequest(&handle, + method, + requestUri, + address, + payload, + connType, + qos, + &cbData, + NULL, + numOptions); + if (ret != OC_STACK_OK) + { + PROMPT_USER = true; + OIC_LOG_V(ERROR, TAG, + "[%s] OCDoRequest with method %s returns error (%d): %s", + __func__, + decode_oc_method(method), + ret, + decode_oc_stack_result(ret)); + } + return ret; +} + + +/** +* The response call back method which prints the response to the stdout +* @param[in] ctx unused +* @param[in] handle unused +* @param[in] clientResponse the response that need to be printed +* +* @return stack application result +*/ +OCStackApplicationResult +ResponseCallbacks(void* ctx, + OCDoHandle handle, + OCClientResponse * clientResponse) +{ + OC_UNUSED(handle); + OC_UNUSED(ctx); + if (clientResponse == NULL) + { + OIC_LOG_V(INFO, TAG, "[%s] Client request response is NULL", __func__); + return OC_STACK_DELETE_TRANSACTION; + } + PrintFormattedResult(clientResponse); + PROMPT_USER = true; + return OC_STACK_KEEP_TRANSACTION; +} + + +/** +* Call back method for discovery request that logs the response payload +* and registers the discovered resources. +* +* @param[in] ctx unused. +* @param[in] handle unused. +* @param[in] clientResponse discovery response with discovered resources info. +* +* @return stack application result +*/ +OCStackApplicationResult +DiscoveryRequestCallBack(void* ctx, + OCDoHandle handle, + OCClientResponse * clientResponse) +{ + OC_UNUSED(handle); + OC_UNUSED(ctx); + if (!clientResponse) + { + OIC_LOG_V(INFO, TAG, "[%s] Client discovery response is NULL", + __func__); + return OC_STACK_KEEP_TRANSACTION; + } + OIC_LOG_V(INFO, TAG, "[%s] Discovered addr:%s\tport:%d", + __func__, + clientResponse->devAddr.addr, + clientResponse->devAddr.port); + PrintFormattedResult(clientResponse); + RegisterDiscoveredResources(clientResponse); + + PROMPT_USER = true; + + return OC_STACK_KEEP_TRANSACTION; +} + + +/** +* allows the user to create their own custom payload with however many +* key value pairs. +* +* @return payload +*/ +OCPayload* +GetCustomPostPayload(void) +{ + OCRepPayload* payload = OCRepPayloadCreate(); + if (!payload) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to create payload object", __func__); + exit(1); + } + + char key[MAX_USER_INPUT] = {0}; + char input[MAX_USER_INPUT] = {0}; + char valueString[MAX_USER_INPUT] = {0}; + int value = 0; + double valueDouble = 0.0; + int type = -1; + printf("\nNeed to create a custom POST payload"); + printf("\nEnter key value pairs as:\t "); + printf("\nType: 0:bool \t 1:int \t 2:double \t 3:string\n"); + while (true) + { + printf("press ENTER to finish :"); + char *ret = fgets(input, sizeof(input), stdin); + (void) ret; + int inCount = sscanf(input, "%d %s %s", &type, key, valueString); + + if (inCount <= 0) + { + break; + } + if (inCount != 3) + { + printf("Invalid input\n"); + OCRepPayloadDestroy(payload); + PROMPT_USER = true; + return NULL; + } + + if (type == 0) //bool + { + if (sscanf(valueString, "%d", &value) == 1) + { + OCRepPayloadSetPropBool(payload, key, value); + } + } + else if (type == 1) //int + { + if (sscanf(valueString, "%d", &value) == 1) + { + OCRepPayloadSetPropInt(payload, key, value); + } + } + else if (type == 2) //double + { + if (sscanf(valueString, "%lf", &valueDouble) == 1) + { + OCRepPayloadSetPropDouble(payload, key, valueDouble); + } + } + else if (type == 3) //string + { + OCRepPayloadSetPropString(payload, key, valueString); + } + else + { + OIC_LOG_V(ERROR, TAG, + "[%s] Invalid entry. stopping accepting key-values", + __func__); + OCRepPayloadDestroy(payload); + PROMPT_USER = true; + return NULL; + } + memset(input, 0, sizeof (input)); + memset(key, 0, sizeof (key)); + memset(valueString, 0, sizeof (valueString)); + } + + if (payload->values) + { + return (OCPayload *) payload; + } + else + { + OCRepPayloadDestroy(payload); + return NULL; + } +} + + +/** +* Processes the user input to figure out which request to initialize. +* +* @param[in] resourceNo the number of discovered resource. +* @param[in] clientMethod the method the user wants to initiate. +*/ +void +ProcessUserInput(int resourceNo, int clientMethod) +{ + const char *resourceUri = DISC_RES[resourceNo].uri; + OCDevAddr resourceAddr = DISC_RES[resourceNo].address; + switch (clientMethod) + { + case OC_REST_GET: + OIC_LOG_V(INFO, TAG, + "[%s] Initializing GET request for resource: %s", + __func__, + resourceUri); + InvokeOCDoRequest(resourceUri, + NULL, + OC_REST_GET, + ResponseCallbacks, + &resourceAddr); + break; + + case OC_REST_POST: + { + OIC_LOG_V(INFO, TAG, + "[%s] Initializing POST request for resource: %s", + __func__, + resourceUri); + OCPayload *payload = GetCustomPostPayload(); + if (payload) + { + InvokeOCDoRequest(resourceUri, + payload, + OC_REST_POST, + ResponseCallbacks, + &resourceAddr); + } + else + { + OIC_LOG_V(ERROR, TAG, + "[%s] Error creating POST payload. Aborting", + __func__); + PROMPT_USER = true; + } + break; + } + + default: + PROMPT_USER = true; + OIC_LOG_V(INFO, TAG, "[%s] Invalid client request method (%d) %s", + __func__, + clientMethod, + decode_oc_method(clientMethod)); + } +} + + +/** +* Utility method to capture the user input. +*/ +void +GetUserInput(void) +{ + PrintDiscoveredResources(); + printf("\nRequest Methods:\t%d: GET\t%d: POST", OC_REST_GET, OC_REST_POST); + printf("\nUsage: :"); + + char input[10] = {0}; + uint32_t resourceNo = 0; + int requestMethod = 0; + + char * ret = fgets(input, sizeof(input), stdin); + (void) ret; + int inCount = sscanf(input, "%d %d", &resourceNo, &requestMethod); + + if (inCount != 2) + { + printf("Invalid input\n"); + PROMPT_USER = true; + return; + } + if (resourceNo >= DISC_RES_COUNTER) + { + printf("Invalid resource\n"); + PROMPT_USER = true; + return; + } + ProcessUserInput(resourceNo, requestMethod); +} + + +/** +* SIGINT handler call back method to update the STOP flag to exit the main loop. +* +* @param[in] signalNumber +*/ +void +SIGINTHandlerCallBack(int signalNumber) +{ + OIC_LOG_V(INFO, TAG, "[%s] Received SIGINT", __func__); + if (signalNumber == SIGINT) + { + STOP = true; + } +} + + +/** +* Custom fopen method to open the secure virtual resource database and +* the device properties. +* +* @param[in] file file name to be opened +* @param[in] mode the mode in which the file will be opened +* +* @return opened file +*/ +FILE* +ClientFOpen(const char *file, const char *mode) +{ + if (0 == strcmp(file, DEV_PROP)) + { + return fopen(DEV_PROP, mode); + } + else if (0 == strcmp(file, OC_SECURITY_DB_DAT_FILE_NAME)) + { + return fopen(SVR_DB, mode); + } + else + { + return fopen(file, mode); + } +} + + +/** +* main function +*/ +int +main(void) +{ + + OCStackResult stack_res; + OIC_LOG_V(DEBUG, TAG, + "[%s] Initializing and registering persistent storage", + __func__); + OCPersistentStorage ps = {ClientFOpen, fread, fwrite, fclose, unlink}; + OCRegisterPersistentStorageHandler(&ps); + OIC_LOG_V(DEBUG, TAG, + "[%s] Initializing IoTivity stack for client_server", + __func__); + stack_res = OCInit(NULL, 0, OC_CLIENT_SERVER); + // notice you need client_server, not client in order to enable security. + if (stack_res != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, + "[%s] Failed to initialize IoTivity stack (%d): %s", + __func__, + stack_res, + decode_oc_stack_result(stack_res)); + return -1; + } + // initiate discovery request + stack_res = InvokeOCDoRequest(OC_RSRVD_WELL_KNOWN_URI, + 0, + OC_REST_DISCOVER, + DiscoveryRequestCallBack, + 0); + if (stack_res != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, + "[%s] Failed to initiate discovery request (%d): %s", + __func__, + stack_res, + decode_oc_stack_result(stack_res)); + return -1; + } + OIC_LOG_V(INFO, TAG, + "[%s] Client is running, press ctrl+c to STOP...", + __func__); + signal(SIGINT, SIGINTHandlerCallBack); + while (!STOP) + { + stack_res = OCProcess(); + if (stack_res != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, + "[%s] IoTivity stack process failure (%d): %s", + __func__, + stack_res, + decode_oc_stack_result(stack_res)); + return -1; + } + + if (PROMPT_USER) + { + PROMPT_USER = false; + GetUserInput(); + } + } + + OIC_LOG_V(INFO, TAG, "[%s] stopping IoTivity client...", __func__); + stack_res = OCStop(); + if (stack_res != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, + "[%s] Failed to STOP IoTivity client (%d): %s", + __func__, + stack_res, + decode_oc_stack_result(stack_res)); + return -1; + } + + return 0; +} diff --git a/examples/OCFSecure/device_properties.dat b/examples/OCFSecure/device_properties.dat new file mode 100644 index 0000000000000000000000000000000000000000..06431f5e9cf0858868a620f3a65fc7582fed2334 Binary files /dev/null and b/examples/OCFSecure/device_properties.dat differ diff --git a/examples/OCFSecure/ocf_svr_db_client.dat b/examples/OCFSecure/ocf_svr_db_client.dat new file mode 100644 index 0000000000000000000000000000000000000000..9cabf63d9142f331bad96c764f4d43017a470b04 Binary files /dev/null and b/examples/OCFSecure/ocf_svr_db_client.dat differ diff --git a/examples/OCFSecure/ocf_svr_db_client.json b/examples/OCFSecure/ocf_svr_db_client.json new file mode 100644 index 0000000000000000000000000000000000000000..0b6a9076cc4fedba891e7a08ebe61103170bd8f5 --- /dev/null +++ b/examples/OCFSecure/ocf_svr_db_client.json @@ -0,0 +1,60 @@ +{ + "acl": { + "aclist2": [ + { + "aceid": 1, + "subject": { "conntype": "anon-clear" }, + "resources": [ + { "href": "/oic/res" }, + { "href": "/oic/d" }, + { "href": "/oic/p"}, + { "href": "/oic/sec/doxm"} + ], + "permission": 2 + }, + { + "aceid": 2, + "subject": { "conntype": "auth-crypt" }, + "resources": [ + { "href": "/oic/res" }, + { "href": "/oic/d" }, + { "href": "/oic/p"}, + { "href": "oic/sec/doxm"} + ], + "permission": 2 + } + ], + "rowneruuid": "32323232-3232-3232-3232-323232323232" + }, + "pstat": { + "dos": { "s": 3, "p": false }, + "isop": true, + "cm": 0, + "tm": 0, + "om": 4, + "sm": 4, + "rowneruuid": "32323232-3232-3232-3232-323232323232" + }, + "doxm": { + "oxms": [0], + "oxmsel": 0, + "sct": 1, + "owned": true, + "deviceuuid": "32323232-3232-3232-3232-323232323232", + "devowneruuid": "32323232-3232-3232-3232-323232323232", + "rowneruuid": "32323232-3232-3232-3232-323232323232" + }, + "cred":{ + "creds": [ + { + "credid": 1, + "subjectuuid": "12345678-1234-1234-1234-123456789012", + "credtype": 1, + "privatedata":{ + "data":"AAAAAAAAAAAAAAAA", + "encoding": "oic.sec.encoding.raw" + } + }], + "rowneruuid": "32323232-3232-3232-3232-323232323232" + } +} diff --git a/examples/OCFSecure/ocf_svr_db_server.dat b/examples/OCFSecure/ocf_svr_db_server.dat new file mode 100644 index 0000000000000000000000000000000000000000..ab78ab9f018d6d7ae3a7aa846bdd8465de6cf2e8 Binary files /dev/null and b/examples/OCFSecure/ocf_svr_db_server.dat differ diff --git a/examples/OCFSecure/ocf_svr_db_server_RFNOP.dat b/examples/OCFSecure/ocf_svr_db_server_RFNOP.dat new file mode 100644 index 0000000000000000000000000000000000000000..ab78ab9f018d6d7ae3a7aa846bdd8465de6cf2e8 Binary files /dev/null and b/examples/OCFSecure/ocf_svr_db_server_RFNOP.dat differ diff --git a/examples/OCFSecure/ocf_svr_db_server_RFNOP.json b/examples/OCFSecure/ocf_svr_db_server_RFNOP.json new file mode 100644 index 0000000000000000000000000000000000000000..34bc43132c8f63d221e7b222f36659bf7d3f04db --- /dev/null +++ b/examples/OCFSecure/ocf_svr_db_server_RFNOP.json @@ -0,0 +1,78 @@ +{ + "acl": { + "aclist2": [ + { + "aceid": 1, + "subject": { "conntype": "anon-clear" }, + "resources": [ + { "href": "/oic/res" }, + { "href": "/oic/d" }, + { "href": "/oic/p" }, + { "href": "/oic/sec/doxm" } + ], + "permission": 2 + }, + { + "aceid": 2, + "subject": { "conntype": "auth-crypt" }, + "resources": [ + { "href": "/oic/res" }, + { "href": "/oic/d" }, + { "href": "/oic/p" }, + { "href": "/oic/sec/doxm" } + ], + "permission": 2 + }, + { + "aceid": 5, + "subject": {"uuid": "32323232-3232-3232-3232-323232323232"}, + "resources":[ + { "href":"/switch", + "rt" : ["oic.r.switch.binary"], + "if" : ["oic.if.baseline", "oic.if.a"]} + ], + "permission": 7 + } + ], + "rowneruuid": "32323232-3232-3232-3232-323232323232", + "rt": ["oic.r.acl"], + "if": ["oic.if.baseline"] + }, + "pstat": { + "dos": { "s": 3, "p": false }, + "isop": true, + "cm": 0, + "tm": 0, + "om": 4, + "sm": 4, + "rowneruuid": "32323232-3232-3232-3232-323232323232", + "rt": ["oic.r.pstat"], + "if": ["oic.if.baseline"] + }, + "doxm": { + "oxms": [0], + "oxmsel": 0, + "sct": 9, + "owned": true, + "deviceuuid": "12345678-1234-1234-1234-123456789012", + "devowneruuid": "32323232-3232-3232-3232-323232323232", + "rowneruuid": "32323232-3232-3232-3232-323232323232", + "rt": ["oic.r.doxm"], + "if": ["oic.if.baseline"] + }, + "cred":{ + "creds": [ + { + "credid": 1, + "subjectuuid": "32323232-3232-3232-3232-323232323232", + "credtype": 1, + "privatedata":{ + "data":"AAAAAAAAAAAAAAAA", + "encoding": "oic.sec.encoding.raw" + } + }], + "rowneruuid": "32323232-3232-3232-3232-323232323232", + "rt": ["oic.r.cred"], + "if": ["oic.if.baseline"] + } +} diff --git a/examples/OCFSecure/ocf_svr_db_server_RFOTM.dat b/examples/OCFSecure/ocf_svr_db_server_RFOTM.dat new file mode 100644 index 0000000000000000000000000000000000000000..f95379bd0a81582867a7fc60d539edfb491a2b5f Binary files /dev/null and b/examples/OCFSecure/ocf_svr_db_server_RFOTM.dat differ diff --git a/examples/OCFSecure/ocf_svr_db_server_RFOTM.json b/examples/OCFSecure/ocf_svr_db_server_RFOTM.json new file mode 100644 index 0000000000000000000000000000000000000000..d6a11f61d1264b1b9f2800c0943ff38a5e454cb3 --- /dev/null +++ b/examples/OCFSecure/ocf_svr_db_server_RFOTM.json @@ -0,0 +1,63 @@ +{ + "acl": { + "aclist2": [ + { + "aceid": 1, + "subject": { "conntype": "anon-clear" }, + "resources": [ + { "href": "/oic/res" }, + { "href": "/oic/d" }, + { "href": "/oic/p" }, + { "href": "/oic/sec/doxm" } + ], + "permission": 2 + }, + { + "aceid": 2, + "subject": { "conntype": "auth-crypt" }, + "resources": [ + { "href": "/oic/res" }, + { "href": "/oic/d" }, + { "href": "/oic/p" }, + { "href": "/oic/sec/doxm" } + ], + "permission": 2 + }, + { + "aceid": 5, + "subject": {"conntype": "auth-crypt" }, + "resources":[ + { "href":"/switch", + "rt" : ["oic.r.switch.binary"], + "if" : ["oic.if.baseline", "oic.if.a"]} + ], + "permission": 7 + } + ], + "rowneruuid": "00000000-0000-0000-0000-000000000000", + "rt": ["oic.r.acl"], + "if": ["oic.if.baseline"] + }, + "pstat": { + "dos": { "s": 1, "p": false }, + "isop": false, + "cm": 2, + "tm": 0, + "om": 4, + "sm": 4, + "rowneruuid": "00000000-0000-0000-0000-000000000000", + "rt": ["oic.r.pstat"], + "if": ["oic.if.baseline"] + }, + "doxm": { + "oxms": [0], + "oxmsel": 0, + "sct": 9, + "owned": false, + "deviceuuid": "12345678-1234-1234-1234-123456789012", + "devowneruuid": "00000000-0000-0000-0000-000000000000", + "rowneruuid": "00000000-0000-0000-0000-000000000000", + "rt": ["oic.r.doxm"], + "if": ["oic.if.baseline"] + } +} diff --git a/examples/OCFSecure/server.cpp b/examples/OCFSecure/server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18dda175b90dd1ff2006447293e72c2d9a89d153 --- /dev/null +++ b/examples/OCFSecure/server.cpp @@ -0,0 +1,574 @@ +/****************************************************************** +* +* Copyright 2018 Vprime 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. +* +***************************************************************** +\author Rami Alshafi +*/ +/////////////////////////////////////////////////////////////////////// +// NOTE : This sample server is generated based on ocserverbasicops.cpp +/////////////////////////////////////////////////////////////////////// + + +#include "iotivity_config.h" +#ifdef WITH_MRAA +#include "mraa.hpp" +#endif +#include +#include "ocstack.h" +#include "ocpayload.h" +#include "logger.h" +#include "utilities.c" +#include +#include +#define TAG "SERVER_APP" + +static bool STOP = false; +static char SVR_DB[] = "ocf_svr_db_server.dat"; +static char INTROSPECTION_FILE[] = "switch_introspection.dat"; +#ifdef JOULE +int LED_PIN = 100; // built-in led on the intel joule board +#endif +#ifdef RASPBERRY +int LED_PIN = 7; +#endif +#ifdef WITH_MRAA +mraa::Gpio *GPIO; +#endif + +typedef struct +{ + OCResourceHandle handle; + const char* type = "oic.r.switch.binary"; + const char * interface = OC_RSRVD_INTERFACE_ACTUATOR; + const char* uri = "/switch"; + uint8_t properties = OC_DISCOVERABLE | OC_SECURE; + bool value = false; + +} BinarySwitch; + +static BinarySwitch SWITCH; + +static const char* PLATFORM_ID = "12345678-1234-1234-1234-123456789012"; +static const char* MANUFACTURER_NAME = "Vprime"; +// Set of strings for each of device info fields +static const char* DEVICE_NAME = "OCF Developer kit"; +static const char* SPEC_VERSION = "ocf.1.0.0"; +static const char* DATA_MODEL_VERSION = "ocf.res.1.0.0,ocf.sh.1.0.0"; +static const char* PROTO_INDEP_ID = "b0ed9259-ec95-4ac6-8f62-241d0da02683"; +static const char* DEVICE_TYPE = "oic.d.switch"; + + +/** +* utility function to set the platform information +* +* @return stack result +*/ +OCStackResult SetPlatformInfo() +{ + OCStackResult result = OC_STACK_ERROR; + OCResourceHandle rHandle = OCGetResourceHandleAtUri(OC_RSRVD_PLATFORM_URI); + if (rHandle == NULL) + { + OIC_LOG_V(ERROR, TAG, + "[%s] Platform Resource does not exist", __func__); + return result; + } + result = OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, + OC_RSRVD_PLATFORM_ID, + PLATFORM_ID); + if (result != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to set platform ID", __func__); + return result; + } + else + { + char * pin = NULL; + OCGetPropertyValue(PAYLOAD_TYPE_PLATFORM, + OC_RSRVD_PLATFORM_ID, + (void **) &pin); + OIC_LOG_V(INFO, TAG, "[%s] Set platform ID successfully to %s", + __func__, + pin); + } + result = OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, + OC_RSRVD_MFG_NAME, + MANUFACTURER_NAME); + if (result != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to set platform name", + __func__); + return result; + } + else + { + char * mn = NULL; + OCGetPropertyValue(PAYLOAD_TYPE_PLATFORM, + OC_RSRVD_MFG_NAME, + (void **) &mn); + OIC_LOG_V(INFO, TAG, "[%s] Set manufacture name successfully to %s", + __func__, + mn); + } + + return OC_STACK_OK; +} + + +/** +* utility function to set the device information +* +* @return stack result +*/ +OCStackResult SetDeviceInfo(void) +{ + OCStackResult result = OC_STACK_ERROR; + + OCResourceHandle handle = OCGetResourceHandleAtUri(OC_RSRVD_DEVICE_URI); + if (handle == NULL) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to find device resource %s", + __func__, + OC_RSRVD_DEVICE_URI); + return result; + } + + result = OCBindResourceTypeToResource(handle, DEVICE_TYPE); + if (result != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to add device type", __func__); + return result; + } + + result = OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, + OC_RSRVD_DEVICE_NAME, + DEVICE_NAME); + if (result != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to set device name", __func__); + return result; + } + + result = OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, + OC_RSRVD_DATA_MODEL_VERSION, + DATA_MODEL_VERSION); + if (result != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to set data model versions", + __func__); + return result; + } + + result = OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, + OC_RSRVD_SPEC_VERSION, + SPEC_VERSION); + if (result != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to set spec version", __func__); + return result; + } + + result = OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, + OC_RSRVD_PROTOCOL_INDEPENDENT_ID, + PROTO_INDEP_ID); + if (result != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to set proptocol independent id", + __func__); + return result; + } + + return OC_STACK_OK; +} + + +/** +* Internal method to create the response payload and updates it with the +* resource properties. +* +* @param[in] resource the resource used to created the response payload +* +* @return response payload +*/ +OCRepPayload* +CreateResponsePayload(BinarySwitch resource) +{ + OCRepPayload* payload = OCRepPayloadCreate(); + if (!payload) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to create response payload", + __func__); + return NULL; + } + OIC_LOG_V(DEBUG, TAG, "[%s] Created response payload successfully." + "Setting up properties...", + __func__); + OCRepPayloadAddInterface(payload, OC_RSRVD_INTERFACE_DEFAULT); + OCRepPayloadAddInterface(payload, resource.interface); + OCRepPayloadAddResourceType(payload, resource.type); + OCRepPayloadSetPropBool(payload, "value", resource.value); + + return payload; +} + + +/** +* Internal method to process the GET request. +* +* @param[out] payload pointer to the payload that needs to be updated +* +* @return Entity handler result +*/ +OCEntityHandlerResult +ProcessGetRequest(OCRepPayload **payload) +{ + OCEntityHandlerResult eh_res = OC_EH_ERROR; + OIC_LOG_V(DEBUG, TAG, "[%s] Processing GET request", __func__); + OCRepPayload *ResponsePayload = CreateResponsePayload(SWITCH); + + if (ResponsePayload) + { + *payload = ResponsePayload; + eh_res = OC_EH_OK; + } + + return eh_res; +} + + +/** +* Internal method to process the POST request. +* +* @param[in] ehRequest a pointer to the entity handler request +* @param[out] payload a pointer to the pointer to the payload that needs to be +* updated +* +* @return Entity handler result +*/ +OCEntityHandlerResult +ProcessPostRequest(OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload) +{ + OCEntityHandlerResult eh_res = OC_EH_ERROR; + OIC_LOG_V(DEBUG, TAG, "[%s] Processing POST request", __func__); + // casting the request payload into a OCRepPayload data type to + // read the value property + const OCRepPayload* requestPayload = (OCRepPayload*)(ehRequest->payload); + bool value; + if (OCRepPayloadGetPropBool(requestPayload, "value", &value)) + { + SWITCH.value = value; + #if defined(JOULE) || defined(RASPBERRY) + GPIO->write(value); + #endif + } + else + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed updating the value property", + __func__); + return eh_res; + } + + OCRepPayload *ResponsePayload = CreateResponsePayload(SWITCH); + + if (ResponsePayload) + { + *payload = ResponsePayload; + eh_res = OC_EH_OK; + } + + return eh_res; +} + + +/** +* The entity handler call back method for the SWITCH resource to handle the GET +* and POST requests. +* +* @param[in] flag entity handler flag which could be request or observer +* @param[in] ehRequest a pointer to the entity handler request +* @param[in] callbackParam unused +* +* @return Entity handler result +*/ +OCEntityHandlerResult +OCEntityHandlerCallBack(OCEntityHandlerFlag flag, + OCEntityHandlerRequest *ehRequest, + void* callbackParam) +{ + OC_UNUSED(callbackParam); + if (!ehRequest) + { + OIC_LOG_V(ERROR, TAG, "[%s] Invalid request pointer", __func__); + return OC_EH_ERROR; + } + if (ehRequest->payload && + ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION) + { + OIC_LOG_V(ERROR, TAG, "[%s] payload type must be representation", + __func__); + return OC_EH_ERROR; + } + OIC_LOG_V(INFO, TAG, "[%s] Flags: 0x%x: %s", + __func__, + flag, + decode_oc_eh_flag(flag)); + + + OCEntityHandlerResult eh_res = OC_EH_ERROR; + OCStackResult stackResult = OC_STACK_ERROR; + + OCEntityHandlerResponse ehResponse; + memset(&ehResponse, 0, sizeof(ehResponse)); + OCMethod requestMethod = ehRequest->method; + + + OCRepPayload* payload = NULL; + + if (flag & OC_REQUEST_FLAG) + { + OIC_LOG_V(INFO, TAG, "[%s] OC_REQUEST_FLAG is detected", __func__); + if (ehRequest) + { + if (OC_REST_GET == requestMethod) + { + OIC_LOG_V(INFO, TAG, "[%s] Processing GET request", __func__); + eh_res = ProcessGetRequest(&payload); + } + else if (OC_REST_POST == requestMethod) + { + OIC_LOG_V(INFO, TAG, "[%s] Processing POST request", + __func__); + eh_res = ProcessPostRequest(ehRequest, &payload); + } + else + { + OIC_LOG_V(INFO, TAG, "[%s] Received unsupported method (%d):" + " %s", + __func__, + ehRequest->method, + decode_oc_method(ehRequest->method)); + eh_res = OC_EH_ERROR; + } + + if (eh_res == OC_EH_OK) + { + ehResponse.requestHandle = ehRequest->requestHandle; + ehResponse.resourceHandle = ehRequest->resource; + ehResponse.ehResult = eh_res; + ehResponse.payload = (OCPayload*)(payload); + ehResponse.numSendVendorSpecificHeaderOptions = 0; + memset(ehResponse.sendVendorSpecificHeaderOptions, 0, + sizeof(ehResponse.sendVendorSpecificHeaderOptions)); + memset(ehResponse.resourceUri, + 0, + sizeof(ehResponse.resourceUri)); + ehResponse.persistentBufferFlag = 0; + + // Send the ehResponse + stackResult = OCDoResponse(&ehResponse); + if (stackResult != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to send a ehResponse " + "(%d): %s", + __func__, + stackResult, + decode_oc_stack_result(stackResult)); + eh_res = OC_EH_ERROR; + } + } + else + { + OIC_LOG_V(ERROR, TAG, "[%s] Entity handler failure (%d): %s", + __func__, + eh_res, + decode_oc_eh_result(eh_res)); + } + } + } + + OCPayloadDestroy(ehResponse.payload); + return eh_res; +} + + +/** +* SIGINT call back handler to update the STOP flag to exit the main loop. +* +* @param[in] signalNumber +*/ +void +SIGINTHandlerCallBack(int signalNumber) +{ + OIC_LOG_V(INFO, TAG, "[%s] Received SIGINT", __func__); + if (signalNumber == SIGINT) + { + STOP = true; + } +} + + +/** +* Custom fopen method to open the secure virtual resource database correctly. +* +* @param[in] path file name to be opened +* @param[in] mode the mode in which the file will be opened in +* +* @return opened file +*/ +FILE* +ServerFOpen(const char *path, + const char *mode) +{ + if (0 == strcmp(path, OC_SECURITY_DB_DAT_FILE_NAME)) + { + OIC_LOG_V(DEBUG, TAG, "[%s] reading file: %s with mode: %s", + __func__, + SVR_DB, + mode); + return fopen(SVR_DB, mode); + } + else if(0 == strcmp(path, OC_INTROSPECTION_FILE_NAME)) + { + OIC_LOG_V(DEBUG, TAG, "[%s] reading file: %s with mode: %s", + __func__, + INTROSPECTION_FILE, + mode); + return fopen(INTROSPECTION_FILE, mode); + } + else + { + OIC_LOG_V(DEBUG, TAG, "[%s] reading file: %s with mode: %s", + __func__, + path, + mode); + return fopen(path, mode); + } +} + + +/** +* main function +*/ +int +main(void) +{ + OCStackResult stack_res = OC_STACK_ERROR; + // enabling GPIO if running on the Intel Joule or the raspberry pi + #if (defined(JOULE) || defined(RASPBERRY)) && defined(WITH_MRAA) + GPIO = new mraa::Gpio(LED_PIN); + if (!GPIO) + { + OIC_LOG_V(ERROR, TAG, "Error instantiating gpio %d", LED_PIN); + } + GPIO->dir(mraa::DIR_OUT); + #endif + + OIC_LOG_V(DEBUG, TAG, "[%s] Initializing and registering persistent" + "storage", + __func__); + OCPersistentStorage ps = {ServerFOpen, fread, fwrite, fclose, unlink}; + OCRegisterPersistentStorageHandler(&ps); + + OIC_LOG_V(DEBUG, TAG, "[%s] Initializing IoTivity stack for server", + __func__); + stack_res = OCInit(NULL, 0, OC_SERVER); + if (stack_res != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to initialize IoTivity stack (%d): " + "%s", + __func__, stack_res, decode_oc_stack_result(stack_res)); + return stack_res; + } + + stack_res = SetPlatformInfo(); + + if (stack_res != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Platform Registration failed\n", __func__); + return stack_res; + } + else + { + OIC_LOG_V(INFO, TAG, "[%s] Platform set successfully", __func__); + } + + stack_res = SetDeviceInfo(); + if (stack_res != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Device Registration failed\n", __func__); + return stack_res; + } + else + { + OIC_LOG_V(INFO, TAG, "[%s] Device set successfully", __func__); + } + + stack_res = OCCreateResource(&(SWITCH.handle), + SWITCH.type, + SWITCH.interface, + SWITCH.uri, + OCEntityHandlerCallBack, + NULL, + SWITCH.properties); + if (stack_res != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to create resource\n", __func__); + return stack_res; + } + else + { + OIC_LOG_V(INFO, TAG, "[%s] Created resource successfully", __func__); + } + + struct timespec timeout; + timeout.tv_sec = 0; + timeout.tv_nsec = 100000000L; + + OIC_LOG_V(INFO, TAG, "[%s] Server is running, press ctrl+c to stop...", + __func__); + + signal(SIGINT, SIGINTHandlerCallBack); + + while (!STOP) + { + stack_res = OCProcess(); + if (stack_res != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] IoTivity stack process failure (%d): " + "%s", + __func__, stack_res, decode_oc_stack_result(stack_res)); + return stack_res; + } + nanosleep(&timeout, NULL); + } + + OIC_LOG_V(INFO, TAG, "[%s] Stopping IoTivity server...", __func__); + + stack_res = OCStop(); + if (stack_res != OC_STACK_OK) + { + OIC_LOG_V(ERROR, TAG, "[%s] Failed to stop IoTivity server (%d): %s", + __func__, + stack_res, + decode_oc_stack_result(stack_res)); + return stack_res; + } + + return 0; +} diff --git a/examples/OCFSecure/switch_introspection.dat b/examples/OCFSecure/switch_introspection.dat new file mode 100644 index 0000000000000000000000000000000000000000..32936528029ec7f8686d484ccb7608b679d0c36c Binary files /dev/null and b/examples/OCFSecure/switch_introspection.dat differ diff --git a/examples/OCFSecure/switch_introspection.json b/examples/OCFSecure/switch_introspection.json new file mode 100644 index 0000000000000000000000000000000000000000..6e02a21a0cc82e1c0cdc1b46dcf17aca36a3fee0 --- /dev/null +++ b/examples/OCFSecure/switch_introspection.json @@ -0,0 +1,136 @@ +{ + "swagger": "2.0", + "info": { + "title": "OCF Dev Kit", + "version": "1.0" + }, + "schemes": [ + "http" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/switch": { + "get": { + "parameters": [ + { + "name": "if", + "in": "query", + "description": "", + "enum": [ "oic.if.a","oic.if.baseline" ], + + "type": "string" + } + ], + "responses": { + "200" : { + "description" : "", + "schema" : + { + "$ref": "#/definitions/BinarySwitch" + } + } + } + + }, + + "post": { + "parameters": [ + { + "name": "if", + "in": "query", + "description": "", + "enum": [ "oic.if.a","oic.if.baseline" ], + + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": false, + "schema" : + { + "$ref": "#/definitions/BinarySwitch" + } + } + ], + "responses": { + "200" : { + "description" : "", + "schema" : + { + "$ref": "#/definitions/BinarySwitch" + } + + } + } + } + } + }, + "definitions": + { + "BinarySwitch": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "boolean", + "description": "Status of the switch" + }, + "rt": { + "type": "array", + "items" : [ + { + "type" : "string", + "maxLength": 64 + } + ], + "minItems" : 1, + "description": "Resource Type", + "readOnly" : true, + "default" : [ "oic.r.switch.binary" ] + }, + "if": { + "type": "array", + "description": "The interface set supported by this resource", + "readOnly" : true, + "items": { + "type": "string", + "enum": [ + "oic.if.baseline", + "oic.if.a" + ] + } + }, + "n": { + "type": "string", + "maxLength": 64, + "description": "Friendly name of the resource", + "readOnly" : true + }, + "id": { + "type": "string", + "description": "Instance ID of this specific resource", + "readOnly" : true + }, + "range": { + "type": "array", + "description": "The valid range for the value Property", + "readOnly" : true, + "minItems": 2, + "maxItems": 2, + "items": { + "type": "number" + } + } + } + } + } + +} diff --git a/examples/OCFSecure/utilities.c b/examples/OCFSecure/utilities.c new file mode 100644 index 0000000000000000000000000000000000000000..f63a86cc1b23a6d76646a2dc3470f0828cd65cf0 --- /dev/null +++ b/examples/OCFSecure/utilities.c @@ -0,0 +1,202 @@ + +const char* decode_oc_stack_result (OCStackResult result) +{ + switch (result) + { + case OC_STACK_OK: + return "OC_STACK_OK"; + case OC_STACK_RESOURCE_DELETED: + return "OC_STACK_RESOURCE_DELETED"; + case OC_STACK_CONTINUE: + return "OC_STACK_CONTINUE"; + case OC_STACK_RESOURCE_CREATED: + return "OC_STACK_RESOURCE_CREATED"; + case OC_STACK_RESOURCE_CHANGED: + return "OC_STACK_RESOURCE_CHANGED"; + case OC_STACK_INVALID_URI: + return "OC_STACK_INVALID_URI"; + case OC_STACK_INVALID_QUERY: + return "OC_STACK_INVALID_QUERY"; + case OC_STACK_INVALID_IP: + return "OC_STACK_INVALID_IP"; + case OC_STACK_INVALID_PORT: + return "OC_STACK_INVALID_PORT"; + case OC_STACK_INVALID_CALLBACK: + return "OC_STACK_INVALID_CALLBACK"; + case OC_STACK_INVALID_METHOD: + return "OC_STACK_INVALID_METHOD"; + case OC_STACK_INVALID_PARAM: + return "OC_STACK_INVALID_PARAM"; + case OC_STACK_INVALID_OBSERVE_PARAM: + return "OC_STACK_INVALID_OBSERVE_PARAM"; + case OC_STACK_NO_MEMORY: + return "OC_STACK_NO_MEMORY"; + case OC_STACK_COMM_ERROR: + return "OC_STACK_COMM_ERROR"; + case OC_STACK_TIMEOUT: + return "OC_STACK_TIMEOUT"; + case OC_STACK_ADAPTER_NOT_ENABLED: + return "OC_STACK_ADAPTER_NOT_ENABLED"; + case OC_STACK_NOTIMPL: + return "OC_STACK_NOTIMPL"; + case OC_STACK_NO_RESOURCE: + return "OC_STACK_NO_RESOURCE"; + case OC_STACK_RESOURCE_ERROR: + return "OC_STACK_RESOURCE_ERROR"; + case OC_STACK_SLOW_RESOURCE: + return "OC_STACK_SLOW_RESOURCE"; + case OC_STACK_DUPLICATE_REQUEST: + return "OC_STACK_DUPLICATE_REQUEST"; + case OC_STACK_NO_OBSERVERS: + return "OC_STACK_NO_OBSERVERS"; + case OC_STACK_OBSERVER_NOT_FOUND: + return "OC_STACK_OBSERVER_NOT_FOUND"; + case OC_STACK_VIRTUAL_DO_NOT_HANDLE: + return "OC_STACK_VIRTUAL_DO_NOT_HANDLE"; + case OC_STACK_INVALID_OPTION: + return "OC_STACK_INVALID_OPTION"; + case OC_STACK_MALFORMED_RESPONSE: + return "OC_STACK_MALFORMED_RESPONSE"; + case OC_STACK_PERSISTENT_BUFFER_REQUIRED: + return "OC_STACK_PERSISTENT_BUFFER_REQUIRED"; + case OC_STACK_INVALID_REQUEST_HANDLE: + return "OC_STACK_INVALID_REQUEST_HANDLE"; + case OC_STACK_INVALID_DEVICE_INFO: + return "OC_STACK_INVALID_DEVICE_INFO"; + case OC_STACK_INVALID_JSON: + return "OC_STACK_INVALID_JSON"; + case OC_STACK_UNAUTHORIZED_REQ: + return "OC_STACK_UNAUTHORIZED_REQ"; + case OC_STACK_PDM_IS_NOT_INITIALIZED: + return "OC_STACK_PDM_IS_NOT_INITIALIZED"; + case OC_STACK_DUPLICATE_UUID: + return "OC_STACK_DUPLICATE_UUID"; + case OC_STACK_INCONSISTENT_DB: + return "OC_STACK_INCONSISTENT_DB"; + case OC_STACK_AUTHENTICATION_FAILURE: + return "OC_STACK_AUTHENTICATION_FAILURE"; + case OC_STACK_ERROR: + return "OC_STACK_ERROR"; + case OC_STACK_TOO_LARGE_REQ: + return "OC_STACK_TOO_LARGE_REQ"; + case OC_STACK_NOT_ALLOWED_OXM: + return "OC_STACK_NOT_ALLOWED_OXM"; + case OC_STACK_BAD_ENDPOINT: + return "OC_STACK_BAD_ENDPOINT"; + case OC_STACK_USER_DENIED_REQ: + return "OC_STACK_USER_DENIED_REQ"; + case OC_STACK_NOT_ACCEPTABLE: + return "OC_STACK_NOT_ACCEPTABLE"; + case OC_STACK_FORBIDDEN_REQ: + return "OC_STACK_FORBIDDEN_REQ"; + case OC_STACK_INTERNAL_SERVER_ERROR: + return "OC_STACK_INTERNAL_SERVER_ERROR"; + case OC_STACK_GATEWAY_TIMEOUT: + return "OC_STACK_GATEWAY_TIMEOUT"; + case OC_STACK_SERVICE_UNAVAILABLE: + return "OC_STACK_SERVICE_UNAVAILABLE"; + #ifdef WITH_PRESENCE + case OC_STACK_PRESENCE_STOPPED: + return "OC_STACK_PRESENCE_STOPPED"; + case OC_STACK_PRESENCE_TIMEOUT: + return "OC_STACK_PRESENCE_TIMEOUT"; + case OC_STACK_PRESENCE_DO_NOT_HANDLE: + return "OC_STACK_PRESENCE_DO_NOT_HANDLE"; + #endif + default: + return "Unknown result!"; + } +} + +const char* decode_oc_eh_result (OCEntityHandlerResult result) +{ + switch(result) + { + case OC_EH_OK: + return "OC_EH_OK"; + case OC_EH_ERROR: + return "OC_EH_ERROR"; + case OC_EH_SLOW: + return "OC_EH_SLOW"; + case OC_EH_RESOURCE_CREATED: + return "OC_EH_RESOURCE_CREATED"; + case OC_EH_RESOURCE_DELETED: + return "OC_EH_RESOURCE_DELETED"; + case OC_EH_VALID: + return "OC_EH_VALID"; + case OC_EH_CHANGED: + return "OC_EH_CHANGED"; + case OC_EH_CONTENT: + return "OC_EH_CONTENT"; + case OC_EH_BAD_REQ: + return "OC_EH_BAD_REQ"; + case OC_EH_UNAUTHORIZED_REQ: + return "OC_EH_UNAUTHORIZED_REQ"; + case OC_EH_BAD_OPT: + return "OC_EH_BAD_OPT"; + case OC_EH_FORBIDDEN: + return "OC_EH_FORBIDDEN"; + case OC_EH_RESOURCE_NOT_FOUND: + return "OC_EH_RESOURCE_NOT_FOUND"; + case OC_EH_METHOD_NOT_ALLOWED: + return "OC_EH_METHOD_NOT_ALLOWED"; + case OC_EH_NOT_ACCEPTABLE: + return "OC_EH_NOT_ACCEPTABLE"; + case OC_EH_TOO_LARGE: + return "OC_EH_TOO_LARGE"; + case OC_EH_UNSUPPORTED_MEDIA_TYPE: + return "OC_EH_UNSUPPORTED_MEDIA_TYPE"; + case OC_EH_INTERNAL_SERVER_ERROR: + return "OC_EH_INTERNAL_SERVER_ERROR"; + case OC_EH_BAD_GATEWAY: + return "OC_EH_BAD_GATEWAY"; + case OC_EH_SERVICE_UNAVAILABLE: + return "OC_EH_SERVICE_UNAVAILABLE"; + case OC_EH_RETRANSMIT_TIMEOUT: + return "OC_EH_RETRANSMIT_TIMEOUT"; + default: + return "Unknown result!"; + } +} + +const char* decode_oc_method (OCMethod method) +{ + switch(method) + { + case OC_REST_NOMETHOD: + return "OC_REST_NOMETHOD"; + case OC_REST_GET: + return "OC_REST_GET"; + case OC_REST_PUT: + return "OC_REST_PUT"; + case OC_REST_POST: + return "OC_REST_POST"; + case OC_REST_DELETE: + return "OC_REST_DELETE"; + case OC_REST_OBSERVE: + return "OC_REST_OBSERVE"; + case OC_REST_OBSERVE_ALL: + return "OC_REST_OBSERVE_ALL"; + case OC_REST_DISCOVER: + return "OC_REST_DISCOVER"; + #ifdef WITH_PRESENCE + case OC_REST_PRESENCE: + return "OC_REST_PRESENCE"; + #endif + default: + return "Unknown method"; + } +} + +const char* decode_oc_eh_flag (OCEntityHandlerFlag flag) +{ + switch(flag) + { + case OC_REQUEST_FLAG: + return "OC_REQUEST_FLAG"; + case OC_OBSERVE_FLAG: + return "OC_OBSERVE_FLAG"; + default: + return "Unknown oc eh flag"; + } +}