Imported Upstream version 1.0.0
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / ck_manager / sample / Door_sample.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH 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
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <signal.h>
26 #include <pthread.h>
27 #include <iostream>
28 #include <sstream>
29 #include "ocstack.h"
30 #include "logger.h"
31 #include "cJSON.h"
32 #include "global.h"
33 #include "cainterface.h"
34 #include "cacommon.h"
35 #include "payload_logging.h"
36 #include "ocpayload.h"
37
38
39 #define TAG "DEMO"
40 #define DEFAULT_CONTEXT_VALUE 0x99
41 #define STATE "state"
42 #define OPEN_DURATION "openDuration"
43 #define OPEN_ALARM "openAlarm"
44
45 static const char MULTICAST_DISCOVERY_QUERY[] = "/oic/res";
46
47 volatile sig_atomic_t gQuitFlag = 0;
48 OCPersistentStorage ps = {0, 0, 0, 0, 0};
49 static const char *gResourceUri = "/a/door";
50 uint8_t lightIpAddr[4] = {};
51 uint16_t lightPortNu;
52 static bool isUpdated = false;
53 static std::string coapServerIP;
54 static std::string coapServerPort;
55 static std::string coapServerResource;
56 static OCConnectivityType ocConnType;
57
58 static std::string address;
59
60 static int coapSecureResource;
61
62 static const char CRED_FILE[] = "oic_svr_db_door.json";
63
64 CAEndpoint_t endpoint = {CA_DEFAULT_ADAPTER, CA_DEFAULT_FLAGS, 0, {0}, 0};
65
66 // myDoorState_t variable to store resource's state .
67 typedef enum
68 {
69     STATE_OPEN,    /**< State is opened */
70     STATE_CLOSED        /**< State is closed*/
71 } myDoorState_t;
72
73 //Structure to represent a door resource  and its attributes
74 typedef struct DOORRESOURCE
75 {
76     OCResourceHandle handle;
77     myDoorState_t state; //ReadOnly, The state of the door (open or closed)"
78     char *openDuration;  //ReadOnly, The time duration the door has been open
79     bool openAlarm ; //The state of the door open alarm
80
81 } DoorResource;
82
83 static DoorResource Door;
84
85 int parseClientResponse(OCClientResponse * clientResponse)
86 {
87     if(!clientResponse)
88     {
89         return 0;
90     }
91
92     OCResourcePayload* res = ((OCDiscoveryPayload*)clientResponse->payload)->resources;
93
94     // Initialize all global variables
95     coapServerResource.clear();
96     coapSecureResource = 0;
97
98     while (res)
99     {
100         coapServerResource.assign(res->uri);
101         OC_LOG_V(INFO, TAG, "Uri -- %s", coapServerResource.c_str());
102
103         if (res->secure)
104         {
105             endpoint.port = res->port;
106             coapSecureResource = 1;
107         }
108
109         OC_LOG_V(INFO, TAG, "Secure -- %s", coapSecureResource == 1 ? "YES" : "NO");
110
111         // If we discovered a secure resource, exit from here
112         if (coapSecureResource)
113         {
114             break;
115         }
116
117         res = res->next;
118     }
119
120     return 0;
121 }
122
123 OCRepPayload* getPayload(const char* uri, int64_t state, char* openDuration, bool openAlarm)
124 {
125     OCRepPayload* payload = OCRepPayloadCreate();
126     if (!payload)
127     {
128         OC_LOG(ERROR, TAG, PCF("Failed to allocate Payload"));
129         return nullptr;
130     }
131
132     OCRepPayloadSetUri(payload, uri);
133     OCRepPayloadSetPropInt(payload, STATE, state);
134     OCRepPayloadSetPropString(payload, OPEN_DURATION, openDuration);
135     OCRepPayloadSetPropBool(payload, OPEN_ALARM, openAlarm);
136
137     return payload;
138 }
139
140 //This function takes the request as an input and returns the response
141 OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest)
142 {
143     if(ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
144     {
145         OC_LOG(ERROR, TAG, PCF("Incoming payload not a representation"));
146         return nullptr;
147     }
148
149     DoorResource *currdoorResource = &Door;
150
151     return getPayload(gResourceUri, currdoorResource->state, currdoorResource->openDuration, currdoorResource->openAlarm);
152 }
153
154 OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest,
155         OCRepPayload **payload)
156 {
157     OCEntityHandlerResult ehResult = OC_EH_ERROR;
158
159     OCRepPayload *getResp = constructResponse(ehRequest);
160
161     if(getResp)
162     {
163         *payload = getResp;
164         ehResult = OC_EH_OK;
165     }
166
167     return ehResult;
168 }
169
170 OCEntityHandlerResult OCEntityHandlerCb(OCEntityHandlerFlag flag,
171                                         OCEntityHandlerRequest *entityHandlerRequest,
172                                         void* /*callbackParam*/)
173 {
174     OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
175
176     OCEntityHandlerResult ehResult = OC_EH_ERROR;
177     OCEntityHandlerResponse response;
178
179     // Validate pointer
180     if (!entityHandlerRequest)
181     {
182         OC_LOG (ERROR, TAG, "Invalid request pointer");
183         return OC_EH_ERROR;
184     }
185
186     OCRepPayload* payload = nullptr;
187
188     if (flag & OC_REQUEST_FLAG)
189     {
190         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
191
192         if (entityHandlerRequest)
193         {
194             switch(entityHandlerRequest->method)
195             {
196             case OC_REST_GET:
197             {
198                 OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
199                 ehResult = ProcessGetRequest (entityHandlerRequest, &payload);
200             }
201             break;
202             default:
203             {
204                 OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
205                         entityHandlerRequest->method);
206                 ehResult = OC_EH_ERROR;
207             }
208             break;
209             }
210
211             if (ehResult == OC_EH_OK && ehResult != OC_EH_FORBIDDEN)
212             {
213                 // Format the response.  Note this requires some info about the request
214                 response.requestHandle = entityHandlerRequest->requestHandle;
215                 response.resourceHandle = entityHandlerRequest->resource;
216                 response.ehResult = ehResult;
217                 response.payload = reinterpret_cast<OCPayload*>(payload);
218                 response.numSendVendorSpecificHeaderOptions = 0;
219                 memset(response.sendVendorSpecificHeaderOptions, 0, sizeof response.sendVendorSpecificHeaderOptions);
220                 memset(response.resourceUri, 0, sizeof(response.resourceUri));
221                 // Indicate that response is NOT in a persistent buffer
222                 response.persistentBufferFlag = 0;
223
224                 // Send the response
225                 if (OCDoResponse(&response) != OC_STACK_OK)
226                 {
227                     OC_LOG(ERROR, TAG, "Error sending response");
228                     ehResult = OC_EH_ERROR;
229                 }
230             }
231         }
232     }
233
234     OCPayloadDestroy(response.payload);
235     return ehResult;
236 }
237
238
239 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
240 void handleSigInt(int signum)
241 {
242     if (signum == SIGINT)
243     {
244         gQuitFlag = 1;
245     }
246 }
247
248 FILE *server_fopen(const char * /*path*/, const char *mode)
249 {
250     return fopen(CRED_FILE, mode);
251 }
252
253 void SetPersistentHandler(OCPersistentStorage *ps)
254 {
255     if (ps)
256     {
257         ps->open =  server_fopen;
258         ps->read = fread;
259         ps->write = fwrite;
260         ps->close = fclose;
261         ps->unlink = unlink;
262
263         OCRegisterPersistentStorageHandler(ps);
264     }
265 }
266
267 /**
268  * GetResult is returned result to string.
269  * @param   result             [IN] stack result
270  * @return  converted OCStackResult as string for debugging
271  */
272 static const char *getResult(OCStackResult result)
273 {
274     switch (result)
275     {
276         case OC_STACK_OK:
277             return "OC_STACK_OK";
278         case OC_STACK_RESOURCE_CREATED:
279             return "OC_STACK_RESOURCE_CREATED";
280         case OC_STACK_RESOURCE_DELETED:
281             return "OC_STACK_RESOURCE_DELETED";
282         case OC_STACK_INVALID_URI:
283             return "OC_STACK_INVALID_URI";
284         case OC_STACK_INVALID_QUERY:
285             return "OC_STACK_INVALID_QUERY";
286         case OC_STACK_INVALID_IP:
287             return "OC_STACK_INVALID_IP";
288         case OC_STACK_INVALID_PORT:
289             return "OC_STACK_INVALID_PORT";
290         case OC_STACK_INVALID_CALLBACK:
291             return "OC_STACK_INVALID_CALLBACK";
292         case OC_STACK_INVALID_METHOD:
293             return "OC_STACK_INVALID_METHOD";
294         case OC_STACK_NO_MEMORY:
295             return "OC_STACK_NO_MEMORY";
296         case OC_STACK_COMM_ERROR:
297             return "OC_STACK_COMM_ERROR";
298         case OC_STACK_INVALID_PARAM:
299             return "OC_STACK_INVALID_PARAM";
300         case OC_STACK_NOTIMPL:
301             return "OC_STACK_NOTIMPL";
302         case OC_STACK_NO_RESOURCE:
303             return "OC_STACK_NO_RESOURCE";
304         case OC_STACK_RESOURCE_ERROR:
305             return "OC_STACK_RESOURCE_ERROR";
306         case OC_STACK_SLOW_RESOURCE:
307             return "OC_STACK_SLOW_RESOURCE";
308         case OC_STACK_NO_OBSERVERS:
309             return "OC_STACK_NO_OBSERVERS";
310     case OC_STACK_UNAUTHORIZED_REQ:
311         return "OC_STACK_UNAUTHORIZED_REQ";
312     #ifdef WITH_PRESENCE
313     case OC_STACK_PRESENCE_STOPPED:
314         return "OC_STACK_PRESENCE_STOPPED";
315     #endif
316         case OC_STACK_ERROR:
317             return "OC_STACK_ERROR";
318         default:
319             return "UNKNOWN";
320     }
321 }
322
323
324 /**
325  * CreateDoorResource creates a new door resource by calling the OCCreateResource() method.
326  * @param   uri                   [IN] uri
327  * @param   doorResource          [IN] info of resource
328  * @return ::OC_STACK_OK on success, some other value upon failure.
329  */
330 int  createDoorResource (const char *uri, DoorResource *doorResource)
331 {
332     if (!uri)
333     {
334         OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
335
336     }
337
338     doorResource->state = STATE_CLOSED; //1:closed , 0: open
339     char str[] = "10min";
340     doorResource->openDuration = str;
341     doorResource->openAlarm = false;
342     OCStackResult res = OCCreateResource(&(doorResource->handle),
343                                          "core.door",
344                                          OC_RSRVD_INTERFACE_DEFAULT,
345                                          uri,
346                                          OCEntityHandlerCb,
347                                          NULL,
348                                          OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
349
350     OC_LOG_V(INFO, TAG, "Created Door resource with result: %s", getResult(res));
351     return 0;
352 }
353
354 OCStackApplicationResult putReqCB(void * ctx, OCDoHandle /*handle*/, OCClientResponse *clientResponse)
355 {
356     if (ctx == (void *)DEFAULT_CONTEXT_VALUE)
357     {
358         OC_LOG(INFO, TAG, "Callback Context for PUT recvd successfully");
359     }
360
361     if (clientResponse)
362     {
363         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
364         OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
365         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
366         if ((OCSecurityPayload*)clientResponse->payload)
367         {
368             OC_LOG_V(INFO, TAG, "=============> Put Response",
369                     ((OCSecurityPayload*)clientResponse->payload)->securityData);
370         }
371     }
372     return OC_STACK_DELETE_TRANSACTION;
373 }
374
375 OCStackApplicationResult getReqCB(void * /*ctx*/, OCDoHandle /*handle*/, OCClientResponse *clientResponse)
376 {
377     OC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");
378
379     if (clientResponse)
380     {
381         OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
382         OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
383         OC_LOG_PAYLOAD(INFO, clientResponse->payload);
384         if ((OCSecurityPayload*)clientResponse->payload)
385         {
386             OC_LOG(INFO, TAG, PCF("=============> Get Response"));
387         }
388     }
389     return OC_STACK_DELETE_TRANSACTION;
390 }
391
392 // This is a function called back when a device is discovered
393 OCStackApplicationResult discoveryReqCB(void* /*ctx*/, OCDoHandle /*handle*/,
394         OCClientResponse * clientResponse)
395 {
396     OC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");
397
398     if (clientResponse)
399     {
400         OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
401         OC_LOG_V(INFO, TAG,
402                 "Device =============> Discovered @ %s:%d",
403                 clientResponse->devAddr.addr,
404                 clientResponse->devAddr.port);
405
406         if (clientResponse->result == OC_STACK_OK)
407         {
408             OC_LOG_PAYLOAD(INFO, clientResponse->payload);
409             ocConnType = clientResponse->connType;
410             parseClientResponse(clientResponse);
411         }
412     }
413
414     return OC_STACK_KEEP_TRANSACTION;
415
416 }
417
418
419
420 void initAddress()
421 {
422     static bool initFlag = false;
423     if (!initFlag)
424     {
425         OC_LOG(INFO, TAG, "Enter IP address (with optional port) of the Server hosting resource\n");
426         OC_LOG(INFO, TAG, "IPv4: 192.168.0.15:45454\n");
427         OC_LOG(INFO, TAG, "IPv6: [fe80::20c:29ff:fe1b:9c5]:45454\n");
428
429         std::cin >> address;
430     }
431     initFlag = true;
432 }
433
434 // Local function to send get request of light resource
435 void SendGetRequest()
436 {
437     OCStackResult ret;
438     OC_LOG(INFO, TAG, "Send Get REQ to Light server");
439
440     initAddress();
441
442     char szQueryUri[64] = { '\0'};
443     OCDoHandle handle;
444     OCCallbackData cbData;
445     cbData.cb = getReqCB;
446     cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
447     cbData.cd = NULL;
448     OC_LOG_V(INFO, TAG, "Get payload from Door sample = /a/light ");
449     snprintf(szQueryUri,  sizeof(szQueryUri), "coaps://%s/a/light", const_cast<char*> (address.c_str())); // lightPortNu);
450     ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, NULL, ocConnType, OC_LOW_QOS,
451                  &cbData, NULL, 0);
452     if (ret != OC_STACK_OK)
453     {
454         OC_LOG(ERROR, TAG, "OCStack resource error");
455     }
456 }
457
458
459 void *input_function(void * /*data*/)
460 {
461     char input;
462     char szQueryUri[64] = { 0 };
463     OCDoHandle handle;
464     OCCallbackData cbData;
465     cbData.cb = discoveryReqCB;
466     cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
467     cbData.cd = NULL;
468
469     strcpy(szQueryUri, MULTICAST_DISCOVERY_QUERY);
470
471     while (1)
472     {
473         std::cin >> input;
474         switch (input)
475         {
476             case 'D':
477             case 'd':
478                 if (isUpdated == false)
479                 {
480                     OC_LOG(INFO, TAG, "isUpdated is false...");
481                     OCDoResource(&handle, OC_REST_DISCOVER, szQueryUri, 0, 0, CT_DEFAULT, OC_LOW_QOS, &cbData, NULL, 0);
482
483                 }
484                 break;
485             case 'G':
486             case 'g':
487                 isUpdated = true;
488                 if (isUpdated == true)
489                 {
490                     OC_LOG(INFO, TAG, "isUpdated is true...");
491                     SendGetRequest();
492                 }
493                 break;
494             case 'Q':
495             case 'q':
496                 gQuitFlag = 1;
497                    return 0;
498             default: break;
499         }
500     }
501     return 0;
502 }
503
504 static void PrintUsage()
505 {
506     OC_LOG(INFO, TAG, "*******************************************");
507     OC_LOG(INFO, TAG, "Input D or d to discover Resources");
508     OC_LOG(INFO, TAG, "Input G or g to initiate Get Request");
509     OC_LOG(INFO, TAG, "Input Q or q to exit");
510     OC_LOG(INFO, TAG, "*******************************************");
511 }
512
513 int main()
514 {
515
516     OC_LOG(INFO, TAG, "OCServer is starting...");
517     SetPersistentHandler(&ps);
518     //PrintUsage();
519     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
520     {
521         OC_LOG(ERROR, TAG, "OCStack init error");
522         return 0;
523     }
524
525     /*
526      * Declare and create the example resource: Door
527      */
528     createDoorResource(gResourceUri, &Door);
529     PrintUsage();
530
531     //select ciphersuite for certificates
532     CASelectCipherSuite(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);
533
534     struct timespec timeout;
535     timeout.tv_sec  = 0;
536     timeout.tv_nsec = 100000000L;
537
538     // Break from loop with Ctrl-C
539     OC_LOG(INFO, TAG, "Entering ocserver main loop...");
540     signal(SIGINT, handleSigInt);
541     int thr_id;
542     pthread_t p_thread;
543     thr_id = pthread_create(&p_thread, NULL, input_function, (void *)NULL);
544     if (thr_id < 0)
545     {
546         OC_LOG(ERROR, TAG, "create thread error");
547         return 0;
548     }
549
550     while (!gQuitFlag)
551     {
552
553         if (OCProcess() != OC_STACK_OK)
554         {
555             OC_LOG(ERROR, TAG, "OCStack process error");
556             return 0;
557         }
558
559
560         nanosleep(&timeout, NULL);
561     }
562
563     pthread_join(p_thread, NULL);
564
565     OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
566
567     if (OCStop() != OC_STACK_OK)
568     {
569         OC_LOG(ERROR, TAG, "OCStack process error");
570     }
571
572     return 0;
573 }