18dda175b90dd1ff2006447293e72c2d9a89d153
[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 manufacture 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",
328                __func__,
329                flag,
330                decode_oc_eh_flag(flag));
331
332
333     OCEntityHandlerResult eh_res = OC_EH_ERROR;
334     OCStackResult stackResult = OC_STACK_ERROR;
335
336     OCEntityHandlerResponse ehResponse;
337     memset(&ehResponse, 0, sizeof(ehResponse));
338     OCMethod requestMethod = ehRequest->method;
339
340
341     OCRepPayload* payload = NULL;
342
343     if (flag & OC_REQUEST_FLAG)
344     {
345         OIC_LOG_V(INFO, TAG, "[%s] OC_REQUEST_FLAG is detected", __func__);
346         if (ehRequest)
347         {
348             if (OC_REST_GET == requestMethod)
349             {
350                 OIC_LOG_V(INFO, TAG, "[%s] Processing GET request", __func__);
351                 eh_res = ProcessGetRequest(&payload);
352             }
353             else if (OC_REST_POST == requestMethod)
354             {
355                 OIC_LOG_V(INFO, TAG, "[%s] Processing POST request",
356                            __func__);
357                 eh_res = ProcessPostRequest(ehRequest, &payload);
358             }
359             else
360             {
361                 OIC_LOG_V(INFO, TAG, "[%s] Received unsupported method (%d):"
362                            " %s",
363                            __func__,
364                            ehRequest->method,
365                            decode_oc_method(ehRequest->method));
366                 eh_res = OC_EH_ERROR;
367             }
368
369             if (eh_res == OC_EH_OK)
370             {
371                 ehResponse.requestHandle = ehRequest->requestHandle;
372                 ehResponse.resourceHandle = ehRequest->resource;
373                 ehResponse.ehResult = eh_res;
374                 ehResponse.payload = (OCPayload*)(payload);
375                 ehResponse.numSendVendorSpecificHeaderOptions = 0;
376                 memset(ehResponse.sendVendorSpecificHeaderOptions, 0,
377                        sizeof(ehResponse.sendVendorSpecificHeaderOptions));
378                 memset(ehResponse.resourceUri,
379                        0,
380                        sizeof(ehResponse.resourceUri));
381                 ehResponse.persistentBufferFlag = 0;
382
383                 // Send the ehResponse
384                 stackResult = OCDoResponse(&ehResponse);
385                 if (stackResult != OC_STACK_OK)
386                 {
387                     OIC_LOG_V(ERROR, TAG, "[%s] Failed to send a ehResponse "
388                               "(%d): %s",
389                               __func__,
390                               stackResult,
391                               decode_oc_stack_result(stackResult));
392                     eh_res = OC_EH_ERROR;
393                 }
394             }
395             else
396             {
397                 OIC_LOG_V(ERROR, TAG, "[%s] Entity handler failure (%d): %s",
398                           __func__,
399                           eh_res,
400                           decode_oc_eh_result(eh_res));
401             }
402         }
403     }
404
405     OCPayloadDestroy(ehResponse.payload);
406     return eh_res;
407 }
408
409
410 /**
411 * SIGINT call back handler to update the STOP flag to exit the main loop.
412 *
413 * @param[in] signalNumber
414 */
415 void
416 SIGINTHandlerCallBack(int signalNumber)
417 {
418     OIC_LOG_V(INFO, TAG, "[%s] Received SIGINT", __func__);
419     if (signalNumber == SIGINT)
420     {
421         STOP = true;
422     }
423 }
424
425
426 /**
427 * Custom fopen method to open the secure virtual resource database correctly.
428 *
429 * @param[in] path file name to be opened
430 * @param[in] mode the mode in which the file will be opened in
431 *
432 * @return opened file
433 */
434 FILE*
435 ServerFOpen(const char *path,
436             const char *mode)
437 {
438     if (0 == strcmp(path, OC_SECURITY_DB_DAT_FILE_NAME))
439     {
440         OIC_LOG_V(DEBUG, TAG, "[%s] reading file: %s with mode: %s",
441                   __func__,
442                   SVR_DB,
443                   mode);
444         return fopen(SVR_DB, mode);
445     }
446     else if(0 == strcmp(path, OC_INTROSPECTION_FILE_NAME))
447     {
448         OIC_LOG_V(DEBUG, TAG, "[%s] reading file: %s with mode: %s",
449                   __func__,
450                   INTROSPECTION_FILE,
451                   mode);
452       return fopen(INTROSPECTION_FILE, mode);
453     }
454     else
455     {
456         OIC_LOG_V(DEBUG, TAG, "[%s] reading file: %s with mode: %s",
457                   __func__,
458                   path,
459                   mode);
460         return fopen(path, mode);
461     }
462 }
463
464
465 /**
466 * main function
467 */
468 int
469 main(void)
470 {
471     OCStackResult stack_res = OC_STACK_ERROR;
472     // enabling GPIO if running on the Intel Joule or the raspberry pi
473     #if (defined(JOULE) || defined(RASPBERRY)) && defined(WITH_MRAA)
474     GPIO = new mraa::Gpio(LED_PIN);
475     if (!GPIO)
476     {
477       OIC_LOG_V(ERROR, TAG, "Error instantiating gpio %d", LED_PIN);
478     }
479     GPIO->dir(mraa::DIR_OUT);
480     #endif
481
482     OIC_LOG_V(DEBUG, TAG, "[%s] Initializing and registering persistent"
483               "storage",
484               __func__);
485     OCPersistentStorage ps = {ServerFOpen, fread, fwrite, fclose, unlink};
486     OCRegisterPersistentStorageHandler(&ps);
487
488     OIC_LOG_V(DEBUG, TAG, "[%s] Initializing IoTivity stack for server",
489               __func__);
490     stack_res = OCInit(NULL, 0, OC_SERVER);
491     if (stack_res != OC_STACK_OK)
492     {
493         OIC_LOG_V(ERROR, TAG, "[%s] Failed to initialize IoTivity stack (%d): "
494                   "%s",
495                   __func__, stack_res, decode_oc_stack_result(stack_res));
496         return stack_res;
497     }
498
499     stack_res = SetPlatformInfo();
500
501     if (stack_res != OC_STACK_OK)
502     {
503         OIC_LOG_V(ERROR, TAG, "[%s] Platform Registration failed\n", __func__);
504         return stack_res;
505     }
506     else
507     {
508         OIC_LOG_V(INFO, TAG, "[%s] Platform set successfully", __func__);
509     }
510
511     stack_res = SetDeviceInfo();
512     if (stack_res != OC_STACK_OK)
513     {
514       OIC_LOG_V(ERROR, TAG, "[%s] Device Registration failed\n", __func__);
515       return stack_res;
516     }
517     else
518     {
519         OIC_LOG_V(INFO, TAG, "[%s] Device set successfully", __func__);
520     }
521
522     stack_res = OCCreateResource(&(SWITCH.handle),
523                                  SWITCH.type,
524                                  SWITCH.interface,
525                                  SWITCH.uri,
526                                  OCEntityHandlerCallBack,
527                                  NULL,
528                                  SWITCH.properties);
529     if (stack_res != OC_STACK_OK)
530     {
531       OIC_LOG_V(ERROR, TAG, "[%s] Failed to create resource\n", __func__);
532       return stack_res;
533     }
534     else
535     {
536         OIC_LOG_V(INFO, TAG, "[%s] Created resource successfully", __func__);
537     }
538
539     struct timespec timeout;
540     timeout.tv_sec  = 0;
541     timeout.tv_nsec = 100000000L;
542
543     OIC_LOG_V(INFO, TAG, "[%s] Server is running, press ctrl+c to stop...",
544               __func__);
545
546     signal(SIGINT, SIGINTHandlerCallBack);
547
548     while (!STOP)
549     {
550         stack_res = OCProcess();
551         if (stack_res != OC_STACK_OK)
552         {
553             OIC_LOG_V(ERROR, TAG, "[%s] IoTivity stack process failure (%d): "
554                       "%s",
555                       __func__, stack_res, decode_oc_stack_result(stack_res));
556             return stack_res;
557         }
558         nanosleep(&timeout, NULL);
559     }
560
561     OIC_LOG_V(INFO, TAG, "[%s] Stopping IoTivity server...", __func__);
562
563     stack_res = OCStop();
564     if (stack_res != OC_STACK_OK)
565     {
566         OIC_LOG_V(ERROR, TAG, "[%s] Failed to stop IoTivity server (%d): %s",
567                   __func__,
568                   stack_res,
569                   decode_oc_stack_result(stack_res));
570         return stack_res;
571     }
572
573     return 0;
574 }