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