Sample application maintenance for OCFSecure
[iotivity.git] / examples / OCFSecure / server.cpp
1 /******************************************************************
2 *
3 * Copyright 2018 Vprime All Rights Reserved.
4 *
5 *
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *****************************************************************
20 \author    Rami Alshafi <ralshafi@vprime.com>
21 */
22 ///////////////////////////////////////////////////////////////////////
23 // NOTE :  This sample server is generated based on ocserverbasicops.cpp
24 ///////////////////////////////////////////////////////////////////////
25
26
27 #include "iotivity_config.h"
28 #ifdef WITH_MRAA
29 #include "mraa.hpp"
30 #endif
31 #include <signal.h>
32 #include "ocstack.h"
33 #include "ocpayload.h"
34 #include "logger.h"
35 #include "utilities.c"
36 #include <unistd.h>
37 #include <time.h>
38 #define TAG "SERVER_APP"
39
40 static bool STOP = false;
41 static char SVR_DB[] = "ocf_svr_db_server.dat";
42 static char INTROSPECTION_FILE[] = "switch_introspection.dat";
43 #ifdef JOULE
44 int LED_PIN = 100; // built-in led on the intel joule board
45 #endif
46 #ifdef RASPBERRY
47 int LED_PIN = 7;
48 #endif
49 #ifdef WITH_MRAA
50 mraa::Gpio *GPIO;
51 #endif
52
53 typedef struct
54 {
55     OCResourceHandle handle;
56     const char* type = "oic.r.switch.binary";
57     const char * interface = OC_RSRVD_INTERFACE_ACTUATOR;
58     const char* uri = "/switch";
59     uint8_t properties = OC_DISCOVERABLE | OC_SECURE;
60     bool value = false;
61
62 } BinarySwitch;
63
64 static BinarySwitch SWITCH;
65
66 static const char* PLATFORM_ID = "12345678-1234-1234-1234-123456789012";
67 static const char* MANUFACTURER_NAME = "Vprime";
68 // Set of strings for each of device info fields
69 static const char*  DEVICE_NAME = "OCF Developer kit";
70 static const char*  SPEC_VERSION = "ocf.1.0.0";
71 static const char*  DATA_MODEL_VERSION = "ocf.res.1.0.0,ocf.sh.1.0.0";
72 static const char*  PROTO_INDEP_ID = "b0ed9259-ec95-4ac6-8f62-241d0da02683";
73 static const char*  DEVICE_TYPE = "oic.d.switch";
74
75
76 /**
77 * utility function to set the platform information
78 *
79 * @return stack result
80 */
81 OCStackResult SetPlatformInfo()
82 {
83     OCStackResult result = OC_STACK_ERROR;
84     OCResourceHandle rHandle = OCGetResourceHandleAtUri(OC_RSRVD_PLATFORM_URI);
85     if (rHandle == NULL)
86     {
87         OIC_LOG_V(ERROR, TAG,
88                   "[%s] Platform Resource does not exist", __func__);
89         return result;
90     }
91     result = OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM,
92                                 OC_RSRVD_PLATFORM_ID,
93                                 PLATFORM_ID);
94     if (result != OC_STACK_OK)
95     {
96         OIC_LOG_V(ERROR, TAG, "[%s] Failed to set platform ID", __func__);
97         return result;
98     }
99     else
100     {
101         char * pin = NULL;
102         OCGetPropertyValue(PAYLOAD_TYPE_PLATFORM,
103                            OC_RSRVD_PLATFORM_ID,
104                            (void **) &pin);
105         OIC_LOG_V(INFO, TAG, "[%s] Set platform ID successfully to %s",
106             __func__,
107             pin);
108     }
109     result = OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM,
110                                 OC_RSRVD_MFG_NAME,
111                                 MANUFACTURER_NAME);
112     if (result != OC_STACK_OK)
113     {
114         OIC_LOG_V(ERROR, TAG, "[%s] Failed to set platform name",
115                   __func__);
116         return result;
117     }
118     else
119     {
120         char * mn = NULL;
121         OCGetPropertyValue(PAYLOAD_TYPE_PLATFORM,
122                            OC_RSRVD_MFG_NAME,
123                            (void **) &mn);
124         OIC_LOG_V(INFO, TAG, "[%s] Set manufacturer name successfully to %s",
125                   __func__,
126                   mn);
127     }
128
129     return OC_STACK_OK;
130 }
131
132
133 /**
134 * utility function to set the device information
135 *
136 * @return stack result
137 */
138 OCStackResult SetDeviceInfo(void)
139 {
140     OCStackResult result = OC_STACK_ERROR;
141
142     OCResourceHandle handle = OCGetResourceHandleAtUri(OC_RSRVD_DEVICE_URI);
143     if (handle == NULL)
144     {
145         OIC_LOG_V(ERROR, TAG, "[%s] Failed to find device resource %s",
146                   __func__,
147                   OC_RSRVD_DEVICE_URI);
148         return result;
149     }
150
151     result = OCBindResourceTypeToResource(handle, DEVICE_TYPE);
152     if (result != OC_STACK_OK)
153     {
154         OIC_LOG_V(ERROR, TAG, "[%s] Failed to add device type", __func__);
155         return result;
156     }
157
158     result = OCSetPropertyValue(PAYLOAD_TYPE_DEVICE,
159                                 OC_RSRVD_DEVICE_NAME,
160                                 DEVICE_NAME);
161     if (result != OC_STACK_OK)
162     {
163         OIC_LOG_V(ERROR, TAG, "[%s] Failed to set device name", __func__);
164         return result;
165     }
166
167     result = OCSetPropertyValue(PAYLOAD_TYPE_DEVICE,
168                                 OC_RSRVD_DATA_MODEL_VERSION,
169                                 DATA_MODEL_VERSION);
170     if (result != OC_STACK_OK)
171     {
172         OIC_LOG_V(ERROR, TAG, "[%s] Failed to set data model versions",
173                   __func__);
174         return result;
175     }
176
177     result = OCSetPropertyValue(PAYLOAD_TYPE_DEVICE,
178                                 OC_RSRVD_SPEC_VERSION,
179                                 SPEC_VERSION);
180     if (result != OC_STACK_OK)
181     {
182         OIC_LOG_V(ERROR, TAG, "[%s] Failed to set spec version", __func__);
183         return result;
184     }
185
186     result = OCSetPropertyValue(PAYLOAD_TYPE_DEVICE,
187                                 OC_RSRVD_PROTOCOL_INDEPENDENT_ID,
188                                 PROTO_INDEP_ID);
189     if (result != OC_STACK_OK)
190     {
191         OIC_LOG_V(ERROR, TAG, "[%s] Failed to set proptocol independent id",
192                   __func__);
193         return result;
194     }
195
196     return OC_STACK_OK;
197 }
198
199
200 /**
201 * Internal method to create the response payload and updates it with the
202 * resource properties.
203 *
204 * @param[in] resource the resource used to created the response payload
205 *
206 * @return response payload
207 */
208 OCRepPayload*
209 CreateResponsePayload(BinarySwitch resource)
210 {
211     OCRepPayload* payload = OCRepPayloadCreate();
212     if (!payload)
213     {
214         OIC_LOG_V(ERROR, TAG, "[%s] Failed to create response payload",
215                   __func__);
216         return NULL;
217     }
218     OIC_LOG_V(DEBUG, TAG, "[%s] Created response payload successfully."
219               "Setting up properties...",
220               __func__);
221     OCRepPayloadAddInterface(payload, OC_RSRVD_INTERFACE_DEFAULT);
222     OCRepPayloadAddInterface(payload, resource.interface);
223     OCRepPayloadAddResourceType(payload, resource.type);
224     OCRepPayloadSetPropBool(payload, "value", resource.value);
225
226     return payload;
227 }
228
229
230 /**
231 * Internal method to process the GET request.
232 *
233 * @param[out] payload pointer to the payload that needs to be updated
234 *
235 * @return Entity handler result
236 */
237 OCEntityHandlerResult
238 ProcessGetRequest(OCRepPayload **payload)
239 {
240     OCEntityHandlerResult eh_res = OC_EH_ERROR;
241     OIC_LOG_V(DEBUG, TAG, "[%s] Processing GET request", __func__);
242     OCRepPayload *ResponsePayload = CreateResponsePayload(SWITCH);
243
244     if (ResponsePayload)
245     {
246         *payload = ResponsePayload;
247         eh_res = OC_EH_OK;
248     }
249
250     return eh_res;
251 }
252
253
254 /**
255 * Internal method to process the POST request.
256 *
257 * @param[in] ehRequest a pointer to the entity handler request
258 * @param[out] payload a pointer to the pointer to the payload that needs to be
259 * updated
260 *
261 * @return Entity handler result
262 */
263 OCEntityHandlerResult
264 ProcessPostRequest(OCEntityHandlerRequest *ehRequest,
265                    OCRepPayload **payload)
266 {
267     OCEntityHandlerResult eh_res = OC_EH_ERROR;
268     OIC_LOG_V(DEBUG, TAG, "[%s] Processing POST request", __func__);
269     // casting the request payload into a OCRepPayload data type to
270     // read the value property
271     const OCRepPayload* requestPayload = (OCRepPayload*)(ehRequest->payload);
272     bool value;
273     if (OCRepPayloadGetPropBool(requestPayload, "value", &value))
274     {
275         SWITCH.value = value;
276         #if defined(JOULE) || defined(RASPBERRY)
277         GPIO->write(value);
278         #endif
279     }
280     else
281     {
282         OIC_LOG_V(ERROR, TAG, "[%s] Failed updating the value property",
283                   __func__);
284         return eh_res;
285     }
286
287     OCRepPayload *ResponsePayload = CreateResponsePayload(SWITCH);
288
289     if (ResponsePayload)
290     {
291         *payload = ResponsePayload;
292         eh_res = OC_EH_OK;
293     }
294
295     return eh_res;
296 }
297
298
299 /**
300 * The entity handler call back method for the SWITCH resource to handle the GET
301 * and POST requests.
302 *
303 * @param[in] flag entity handler flag which could be request or observer
304 * @param[in] ehRequest a pointer to the entity handler request
305 * @param[in] callbackParam unused
306 *
307 * @return Entity handler result
308 */
309 OCEntityHandlerResult
310 OCEntityHandlerCallBack(OCEntityHandlerFlag flag,
311                         OCEntityHandlerRequest *ehRequest,
312                         void* callbackParam)
313 {
314     OC_UNUSED(callbackParam);
315     if (!ehRequest)
316     {
317         OIC_LOG_V(ERROR, TAG, "[%s] Invalid request pointer", __func__);
318         return OC_EH_ERROR;
319     }
320     if (ehRequest->payload &&
321         ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
322     {
323         OIC_LOG_V(ERROR, TAG, "[%s] payload type must be representation",
324                   __func__);
325         return OC_EH_ERROR;
326     }
327     OIC_LOG_V(INFO, TAG, "[%s] Flags: 0x%x: %s", __func__, flag,
328               decode_oc_eh_flag(flag));
329
330
331     OCEntityHandlerResult eh_res = OC_EH_ERROR;
332     OCStackResult stackResult = OC_STACK_ERROR;
333
334     OCEntityHandlerResponse ehResponse;
335     memset(&ehResponse, 0, sizeof(ehResponse));
336     OCMethod requestMethod = ehRequest->method;
337
338
339     OCRepPayload* payload = NULL;
340
341     if (flag & OC_REQUEST_FLAG)
342     {
343         OIC_LOG_V(INFO, TAG, "[%s] OC_REQUEST_FLAG is detected", __func__);
344         if (ehRequest)
345         {
346             if (OC_REST_GET == requestMethod)
347             {
348                 OIC_LOG_V(INFO, TAG, "[%s] Processing GET request", __func__);
349                 eh_res = ProcessGetRequest(&payload);
350             }
351             else if (OC_REST_POST == requestMethod)
352             {
353                 OIC_LOG_V(INFO, TAG, "[%s] Processing POST request", __func__);
354                 eh_res = ProcessPostRequest(ehRequest, &payload);
355             }
356             else
357             {
358                 OIC_LOG_V(INFO, TAG, "[%s] Received unsupported method (%d):"
359                           " %s",
360                           __func__,
361                           ehRequest->method,
362                           decode_oc_method(ehRequest->method));
363                 eh_res = OC_EH_ERROR;
364             }
365
366             if (eh_res == OC_EH_OK)
367             {
368                 ehResponse.requestHandle = ehRequest->requestHandle;
369                 ehResponse.resourceHandle = ehRequest->resource;
370                 ehResponse.ehResult = eh_res;
371                 ehResponse.payload = (OCPayload*)(payload);
372                 ehResponse.numSendVendorSpecificHeaderOptions = 0;
373                 memset(ehResponse.sendVendorSpecificHeaderOptions, 0,
374                        sizeof(ehResponse.sendVendorSpecificHeaderOptions));
375                 memset(ehResponse.resourceUri,
376                        0,
377                        sizeof(ehResponse.resourceUri));
378                 ehResponse.persistentBufferFlag = 0;
379
380                 // Send the ehResponse
381                 stackResult = OCDoResponse(&ehResponse);
382                 if (stackResult != OC_STACK_OK)
383                 {
384                     OIC_LOG_V(ERROR, TAG, "[%s] Failed to send a ehResponse "
385                               "(%d): %s",
386                               __func__,
387                               stackResult,
388                               decode_oc_stack_result(stackResult));
389                     eh_res = OC_EH_ERROR;
390                 }
391             }
392             else
393             {
394                 OIC_LOG_V(ERROR, TAG, "[%s] Entity handler failure (%d): %s",
395                           __func__,
396                           eh_res,
397                           decode_oc_eh_result(eh_res));
398             }
399         }
400     }
401
402     OCPayloadDestroy(ehResponse.payload);
403     return eh_res;
404 }
405
406
407 /**
408 * SIGINT call back handler to update the STOP flag to exit the main loop.
409 *
410 * @param[in] signalNumber
411 */
412 void
413 SIGINTHandlerCallBack(int signalNumber)
414 {
415     OIC_LOG_V(INFO, TAG, "[%s] Received SIGINT", __func__);
416     if (signalNumber == SIGINT)
417     {
418         STOP = true;
419     }
420 }
421
422
423 /**
424 * Custom fopen method to open the secure virtual resource database correctly.
425 *
426 * @param[in] path file name to be opened
427 * @param[in] mode the mode in which the file will be opened in
428 *
429 * @return opened file
430 */
431 FILE*
432 ServerFOpen(const char *path,
433             const char *mode)
434 {
435     if (0 == strcmp(path, OC_SECURITY_DB_DAT_FILE_NAME))
436     {
437         OIC_LOG_V(DEBUG, TAG, "[%s] reading file: %s with mode: %s",
438                   __func__,
439                   SVR_DB,
440                   mode);
441         return fopen(SVR_DB, mode);
442     }
443     else if(0 == strcmp(path, OC_INTROSPECTION_FILE_NAME))
444     {
445         OIC_LOG_V(DEBUG, TAG, "[%s] reading file: %s with mode: %s",
446                   __func__,
447                   INTROSPECTION_FILE,
448                   mode);
449         return fopen(INTROSPECTION_FILE, mode);
450     }
451     else
452     {
453         OIC_LOG_V(DEBUG, TAG, "[%s] reading file: %s with mode: %s",
454                   __func__,
455                   path,
456                   mode);
457         return fopen(path, mode);
458     }
459 }
460
461
462 /**
463 * main function
464 */
465 int
466 main(void)
467 {
468     OCStackResult stack_res = OC_STACK_ERROR;
469     // enabling GPIO if running on the Intel Joule or the raspberry pi
470     #if (defined(JOULE) || defined(RASPBERRY)) && defined(WITH_MRAA)
471     GPIO = new mraa::Gpio(LED_PIN);
472     if (!GPIO)
473     {
474         OIC_LOG_V(ERROR, TAG, "Error instantiating gpio %d", LED_PIN);
475     }
476     GPIO->dir(mraa::DIR_OUT);
477     #endif
478
479     OIC_LOG_V(DEBUG, TAG, "[%s] Initializing and registering persistent"
480               "storage",
481               __func__);
482     OCPersistentStorage ps = {ServerFOpen, fread, fwrite, fclose, unlink};
483     OCRegisterPersistentStorageHandler(&ps);
484
485     OIC_LOG_V(DEBUG, TAG, "[%s] Initializing IoTivity stack for server",
486               __func__);
487     stack_res = OCInit(NULL, 0, OC_SERVER);
488     if (stack_res != OC_STACK_OK)
489     {
490         OIC_LOG_V(ERROR, TAG, "[%s] Failed to initialize IoTivity stack (%d): "
491                   "%s",
492                   __func__, stack_res, decode_oc_stack_result(stack_res));
493         return stack_res;
494     }
495
496     stack_res = SetPlatformInfo();
497
498     if (stack_res != OC_STACK_OK)
499     {
500         OIC_LOG_V(ERROR, TAG, "[%s] Platform Registration failed\n", __func__);
501         return stack_res;
502     }
503     else
504     {
505         OIC_LOG_V(INFO, TAG, "[%s] Platform set successfully", __func__);
506     }
507
508     stack_res = SetDeviceInfo();
509     if (stack_res != OC_STACK_OK)
510     {
511         OIC_LOG_V(ERROR, TAG, "[%s] Device Registration failed\n", __func__);
512         return stack_res;
513     }
514     else
515     {
516         OIC_LOG_V(INFO, TAG, "[%s] Device set successfully", __func__);
517     }
518
519     stack_res = OCCreateResource(&(SWITCH.handle),
520                                  SWITCH.type,
521                                  SWITCH.interface,
522                                  SWITCH.uri,
523                                  OCEntityHandlerCallBack,
524                                  NULL,
525                                  SWITCH.properties);
526     if (stack_res != OC_STACK_OK)
527     {
528         OIC_LOG_V(ERROR, TAG, "[%s] Failed to create resource\n", __func__);
529         return stack_res;
530     }
531     else
532     {
533         OIC_LOG_V(INFO, TAG, "[%s] Created resource successfully", __func__);
534     }
535
536     struct timespec timeout;
537     timeout.tv_sec  = 0;
538     timeout.tv_nsec = 100000000L;
539
540     OIC_LOG_V(INFO, TAG, "[%s] Server is running, press ctrl+c to stop...",
541               __func__);
542
543     signal(SIGINT, SIGINTHandlerCallBack);
544
545     while (!STOP)
546     {
547         stack_res = OCProcess();
548         if (stack_res != OC_STACK_OK)
549         {
550             OIC_LOG_V(ERROR, TAG, "[%s] IoTivity stack process failure (%d): "
551                       "%s",
552                       __func__, stack_res, decode_oc_stack_result(stack_res));
553             return stack_res;
554         }
555         nanosleep(&timeout, NULL);
556     }
557
558     OIC_LOG_V(INFO, TAG, "[%s] Stopping IoTivity server...", __func__);
559
560     stack_res = OCStop();
561     if (stack_res != OC_STACK_OK)
562     {
563         OIC_LOG_V(ERROR, TAG, "[%s] Failed to stop IoTivity server (%d): %s",
564                   __func__,
565                   stack_res,
566                   decode_oc_stack_result(stack_res));
567         return stack_res;
568     }
569
570     return 0;
571 }