Fix provisioning unit tests
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / unittest / sampleserver1.cpp
1 /******************************************************************
2 *
3 * Copyright 2015 Samsung Electronics 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 //NOTE :  This sample server is generated based on ocserverbasicops.cpp
22 ///////////////////////////////////////////////////////////////////////
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <signal.h>
28 #include <pthread.h>
29 #include "ocstack.h"
30 #include "logger.h"
31 #include "ocpayload.h"
32 #include "oic_string.h"
33
34 #define TAG "UNITTEST_SERVER_1"
35
36 int gQuitFlag = 0;
37
38 /* Structure to represent a LED resource */
39 typedef struct LEDRESOURCE{
40     OCResourceHandle handle;
41     bool state;
42     int power;
43 } LEDResource;
44
45 static LEDResource LED;
46 // This variable determines instance number of the LED resource.
47 // Used by POST method to create a new instance of LED resource.
48 static int gCurrLedInstance = 0;
49 #define SAMPLE_MAX_NUM_POST_INSTANCE  2
50 static LEDResource gLedInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
51
52 char *gResourceUri= (char *)"/a/led";
53
54 //Secure Virtual Resource database for Iotivity Server
55 //It contains Server's Identity and the PSK credentials
56 //of other devices which the server trusts
57 static char CRED_FILE[] = "oic_svr_db_server1.dat";
58
59 static char SVR_DB_FILE_NAME[] = "oic_svr_db_server_justworks.dat";
60
61 /* Function that creates a new LED resource by calling the
62  * OCCreateResource() method.
63  */
64 int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower);
65
66 /* This method converts the payload to JSON format */
67 OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest);
68
69 /* Following methods process the PUT, GET, POST
70  * requests
71  */
72 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
73                                          OCRepPayload **payload);
74 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
75                                          OCRepPayload **payload);
76 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
77                                         OCEntityHandlerResponse *response,
78                                         OCRepPayload **payload);
79
80 /* Entity Handler callback functions */
81 OCEntityHandlerResult
82 OCEntityHandlerCb (OCEntityHandlerFlag flag,
83         OCEntityHandlerRequest *entityHandlerRequest,
84         void* callbackParam);
85
86 const char *getResult(OCStackResult result) {
87     switch (result) {
88     case OC_STACK_OK:
89         return "OC_STACK_OK";
90     case OC_STACK_RESOURCE_CREATED:
91         return "OC_STACK_RESOURCE_CREATED";
92     case OC_STACK_RESOURCE_DELETED:
93         return "OC_STACK_RESOURCE_DELETED";
94     case OC_STACK_INVALID_URI:
95         return "OC_STACK_INVALID_URI";
96     case OC_STACK_INVALID_QUERY:
97         return "OC_STACK_INVALID_QUERY";
98     case OC_STACK_INVALID_IP:
99         return "OC_STACK_INVALID_IP";
100     case OC_STACK_INVALID_PORT:
101         return "OC_STACK_INVALID_PORT";
102     case OC_STACK_INVALID_CALLBACK:
103         return "OC_STACK_INVALID_CALLBACK";
104     case OC_STACK_INVALID_METHOD:
105         return "OC_STACK_INVALID_METHOD";
106     case OC_STACK_NO_MEMORY:
107         return "OC_STACK_NO_MEMORY";
108     case OC_STACK_COMM_ERROR:
109         return "OC_STACK_COMM_ERROR";
110     case OC_STACK_INVALID_PARAM:
111         return "OC_STACK_INVALID_PARAM";
112     case OC_STACK_NOTIMPL:
113         return "OC_STACK_NOTIMPL";
114     case OC_STACK_NO_RESOURCE:
115         return "OC_STACK_NO_RESOURCE";
116     case OC_STACK_RESOURCE_ERROR:
117         return "OC_STACK_RESOURCE_ERROR";
118     case OC_STACK_SLOW_RESOURCE:
119         return "OC_STACK_SLOW_RESOURCE";
120     case OC_STACK_NO_OBSERVERS:
121         return "OC_STACK_NO_OBSERVERS";
122     #ifdef WITH_PRESENCE
123     case OC_STACK_PRESENCE_STOPPED:
124         return "OC_STACK_PRESENCE_STOPPED";
125     #endif
126     case OC_STACK_ERROR:
127         return "OC_STACK_ERROR";
128     default:
129         return "UNKNOWN";
130     }
131 }
132
133 OCRepPayload* getPayload(const char* uri, int64_t power, bool state)
134 {
135     OCRepPayload* payload = OCRepPayloadCreate();
136     if(!payload)
137     {
138         OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
139         return NULL;
140     }
141
142     OCRepPayloadSetUri(payload, uri);
143     OCRepPayloadSetPropBool(payload, "state", state);
144     OCRepPayloadSetPropInt(payload, "power", power);
145
146     return payload;
147 }
148
149 //This function takes the request as an input and returns the response
150 OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest)
151 {
152     if(ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
153     {
154         OIC_LOG(ERROR, TAG, "Incoming payload not a representation");
155         return NULL;
156     }
157
158     OCRepPayload* input = (OCRepPayload*)(ehRequest->payload);
159
160     LEDResource *currLEDResource = &LED;
161
162     if (ehRequest->resource == gLedInstance[0].handle)
163     {
164         currLEDResource = &gLedInstance[0];
165         gResourceUri = (char *) "/a/led/0";
166     }
167     else if (ehRequest->resource == gLedInstance[1].handle)
168     {
169         currLEDResource = &gLedInstance[1];
170         gResourceUri = (char *) "/a/led/1";
171     }
172
173     if(OC_REST_PUT == ehRequest->method)
174     {
175         // Get pointer to query
176         int64_t pow;
177         if(OCRepPayloadGetPropInt(input, "power", &pow))
178         {
179             currLEDResource->power =pow;
180         }
181
182         bool state;
183         if(OCRepPayloadGetPropBool(input, "state", &state))
184         {
185             currLEDResource->state = state;
186         }
187     }
188
189     return getPayload(gResourceUri, currLEDResource->power, currLEDResource->state);
190 }
191
192 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
193         OCRepPayload **payload)
194 {
195     OCEntityHandlerResult ehResult;
196
197     OCRepPayload *getResp = constructResponse(ehRequest);
198
199     if(getResp)
200     {
201         *payload = getResp;
202         ehResult = OC_EH_OK;
203     }
204     else
205     {
206         ehResult = OC_EH_ERROR;
207     }
208
209     return ehResult;
210 }
211
212 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
213         OCRepPayload **payload)
214 {
215     OCEntityHandlerResult ehResult;
216
217     OCRepPayload *putResp = constructResponse(ehRequest);
218
219     if(putResp)
220     {
221         *payload = putResp;
222         ehResult = OC_EH_OK;
223     }
224     else
225     {
226         ehResult = OC_EH_ERROR;
227     }
228
229     return ehResult;
230 }
231
232 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
233         OCEntityHandlerResponse *response, OCRepPayload **payload)
234 {
235     OCRepPayload *respPLPost_led = NULL;
236     OCEntityHandlerResult ehResult = OC_EH_OK;
237
238     /*
239      * The entity handler determines how to process a POST request.
240      * Per the REST paradigm, POST can also be used to update representation of existing
241      * resource or create a new resource.
242      * In the sample below, if the POST is for /a/led then a new instance of the LED
243      * resource is created with default representation (if representation is included in
244      * POST payload it can be used as initial values) as long as the instance is
245      * lesser than max new instance count. Once max instance count is reached, POST on
246      * /a/led updated the representation of /a/led (just like PUT)
247      */
248
249     if (ehRequest->resource == LED.handle)
250     {
251         if (gCurrLedInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
252         {
253             // Create new LED instance
254             char newLedUri[15] = "/a/led/";
255             int newLedUriLength = strlen(newLedUri);
256             snprintf (newLedUri + newLedUriLength, sizeof(newLedUri)-newLedUriLength, "%d", gCurrLedInstance);
257
258             respPLPost_led = OCRepPayloadCreate();
259             OCRepPayloadSetUri(respPLPost_led, gResourceUri);
260             OCRepPayloadSetPropString(respPLPost_led, "createduri", newLedUri);
261
262             if (0 == createLEDResource (newLedUri, &gLedInstance[gCurrLedInstance], false, 0))
263             {
264                 OIC_LOG (INFO, TAG, "Created new LED instance");
265                 gLedInstance[gCurrLedInstance].state = 0;
266                 gLedInstance[gCurrLedInstance].power = 0;
267                 gCurrLedInstance++;
268                 strncpy ((char *)response->resourceUri, newLedUri, sizeof(response->resourceUri));
269                 ehResult = OC_EH_RESOURCE_CREATED;
270             }
271         }
272         else
273         {
274             respPLPost_led = constructResponse(ehRequest);
275         }
276     }
277     else
278     {
279         for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
280         {
281             if (ehRequest->resource == gLedInstance[i].handle)
282             {
283                 if (i == 0)
284                 {
285                     respPLPost_led = constructResponse(ehRequest);
286                     break;
287                 }
288                 else if (i == 1)
289                 {
290                     respPLPost_led = constructResponse(ehRequest);
291                 }
292             }
293         }
294     }
295
296     if (respPLPost_led != NULL)
297     {
298         *payload = respPLPost_led;
299         ehResult = OC_EH_OK;
300     }
301     else
302     {
303         OIC_LOG_V (INFO, TAG, "Payload was NULL");
304         ehResult = OC_EH_ERROR;
305     }
306
307     return ehResult;
308 }
309
310 OCEntityHandlerResult
311 OCEntityHandlerCb (OCEntityHandlerFlag flag,
312         OCEntityHandlerRequest *entityHandlerRequest,
313         void* callbackParam)
314 {
315     OIC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
316     (void)callbackParam;
317     OCEntityHandlerResult ehResult = OC_EH_ERROR;
318
319     OCEntityHandlerResponse response;
320     memset(&response, 0, sizeof(response));
321
322     // Validate pointer
323     if (!entityHandlerRequest)
324     {
325         OIC_LOG (ERROR, TAG, "Invalid request pointer");
326         return OC_EH_ERROR;
327     }
328
329     OCRepPayload* payload = NULL;
330
331     if (flag & OC_REQUEST_FLAG)
332     {
333         OIC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
334         if (entityHandlerRequest)
335         {
336             if (OC_REST_GET == entityHandlerRequest->method)
337             {
338                 OIC_LOG (INFO, TAG, "Received OC_REST_GET from client");
339                 ehResult = ProcessGetRequest (entityHandlerRequest, &payload);
340             }
341             else if (OC_REST_PUT == entityHandlerRequest->method)
342             {
343                 OIC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
344                 ehResult = ProcessPutRequest (entityHandlerRequest, &payload);
345             }
346             else if (OC_REST_POST == entityHandlerRequest->method)
347             {
348                 OIC_LOG (INFO, TAG, "Received OC_REST_POST from client");
349                 ehResult = ProcessPostRequest (entityHandlerRequest, &response, &payload);
350             }
351             else
352             {
353                 OIC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
354                         entityHandlerRequest->method);
355                 ehResult = OC_EH_ERROR;
356             }
357
358             if (ehResult == OC_EH_OK && ehResult != OC_EH_FORBIDDEN)
359             {
360                 // Format the response.  Note this requires some info about the request
361                 response.requestHandle = entityHandlerRequest->requestHandle;
362                 response.resourceHandle = entityHandlerRequest->resource;
363                 response.ehResult = ehResult;
364                 response.payload = (OCPayload*)(payload);
365                 response.numSendVendorSpecificHeaderOptions = 0;
366                 memset(response.sendVendorSpecificHeaderOptions, 0,
367                        sizeof(response.sendVendorSpecificHeaderOptions));
368                 memset(response.resourceUri, 0, sizeof(response.resourceUri));
369                 // Indicate that response is NOT in a persistent buffer
370                 response.persistentBufferFlag = 0;
371
372                 // Send the response
373                 if (OCDoResponse(&response) != OC_STACK_OK)
374                 {
375                     OIC_LOG(ERROR, TAG, "Error sending response");
376                     ehResult = OC_EH_ERROR;
377                 }
378             }
379         }
380     }
381
382     OCPayloadDestroy(response.payload);
383     return ehResult;
384 }
385
386 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
387 void handleSigInt(int signum)
388 {
389     if (signum == SIGINT)
390     {
391         gQuitFlag = 1;
392     }
393 }
394
395 static void GetCurrentWorkingDirectory(char* buf, size_t bufsize)
396 {
397     char cwd[1024] = {0};
398     const char* unittest_path = "resource/csdk/security/provisioning/unittest";
399     if(getcwd(cwd, sizeof(cwd)) != NULL)
400     {
401         if(strstr(cwd, unittest_path) == NULL)
402         {
403 #if defined __linux__
404 #if __x86_64__
405         snprintf(buf, bufsize, "%s/out/linux/x86_64/release/%s/", cwd, unittest_path);
406         snprintf(buf, bufsize, "%s/out/linux/x86_64/release/%s/", cwd, unittest_path);
407 #else
408         snprintf(buf, bufsize, "%s/out/linux/x86/release/%s/", cwd, unittest_path);
409         snprintf(buf, bufsize, "%s/out/linux/x86/release/%s/", cwd, unittest_path);
410 #endif //__x86_64__
411 #endif //defined __linux__
412         }
413         else
414         {
415             snprintf(buf, bufsize, "%s/", cwd);
416         }
417     }
418 }
419
420 FILE* server_fopen(const char *path, const char *mode)
421 {
422     if (0 == strcmp(path, OC_SECURITY_DB_DAT_FILE_NAME))
423     {
424         char cwd[1024] = { 0 };
425         char cred_path[1024] = { 0 };
426         GetCurrentWorkingDirectory(cwd, sizeof(cwd));
427         snprintf(cred_path, sizeof(cred_path), "%s%s", cwd, CRED_FILE);
428         return fopen(cred_path, mode);
429     }
430     else
431     {
432         return fopen(path, mode);
433     }
434 }
435
436 /**
437  * Generate default SVR DB path
438  *
439  * Exclude "out/<OS>/<platform>/<release>/" from current working directory path
440  * Replace "unittest" by "sample" at the end of current working directory path
441  * Add proper db file name to the end of path
442  *
443  * @param[in]  cwd  - current working directory
444  * @param[out] path - generated default database path
445  * @param[in] path_len - allocated length for variable path
446  * @return OC_STACK_OK for success.
447  */
448 static OCStackResult GenerateDefaultDbPath(const char *cwd, char *path, size_t path_len)
449 {
450     const char FOLDER_OUT[]      = "out";
451     const char FOLDER_UNITTEST[] = "unittest";
452     const char FOLDER_SAMPLE[]   = "sample";
453
454 #ifdef _WIN32
455     const char slash = '\\';
456 #else
457     const char slash = '/';
458 #endif
459
460     const char slash_str[2] = {slash, 0};
461
462     path[0] = 0;
463
464     char out[5] = {0};
465     snprintf(out, sizeof(out), "%c%s%c", slash, FOLDER_OUT, slash);
466
467     char *start = strstr((char*)cwd, out);
468     if (NULL == start)
469     {
470         OIC_LOG_V(ERROR, TAG, "Can't find %s folder while parsing current working directory\n", FOLDER_OUT);
471         return OC_STACK_ERROR;
472     }
473     start++; //Go to next symbol after slash
474
475     char *end = start;
476     for (int i = 0; i < 4; i++)
477     {
478         end = strchr(end, slash);
479         if (NULL == end)
480         {
481             OIC_LOG_V(ERROR, TAG, "Can't find slash number %d while parsing current working directory\n", i);
482             return OC_STACK_ERROR;
483         }
484         end++; //Go to next symbol after slash
485     }
486
487     //Cut "unittest" string at the end
488     char *last = strstr(end, FOLDER_UNITTEST);
489     if (NULL == last)
490     {
491         OIC_LOG_V(ERROR, TAG, "Can't find %s folder while parsing current working directory\n", FOLDER_UNITTEST);
492         return OC_STACK_ERROR;
493     }
494
495     //Generate default svr db path
496     OICStrcatPartial(path, path_len, cwd, start - cwd); //copy iotivity root path
497     OICStrcatPartial(path, path_len, end, last - end); //copy 'resource/.../provisioning' path
498     OICStrcatPartial(path, path_len, FOLDER_SAMPLE, sizeof(FOLDER_SAMPLE));
499     OICStrcatPartial(path, path_len, slash_str, sizeof(slash_str));
500     OICStrcatPartial(path, path_len, SVR_DB_FILE_NAME, sizeof(SVR_DB_FILE_NAME));
501
502     return OC_STACK_OK;
503 }
504
505 int main()
506 {
507     struct timespec timeout;
508
509     //Delete previous SVR DB, if exist.
510     char cwd[1024] = {0};
511     char cmd[1024] = {0};
512     GetCurrentWorkingDirectory(cwd, sizeof(cwd));
513     snprintf(cmd, sizeof(cmd), "rm -rf %s%s", cwd, CRED_FILE);
514     system(cmd);
515
516     char default_svrdb_path[1024] = {0};
517     if (OC_STACK_OK != GenerateDefaultDbPath(cwd, default_svrdb_path, sizeof(default_svrdb_path)))
518     {
519         OIC_LOG(ERROR, TAG, "Can't generate default db path");
520         return 0;
521     }
522
523     //Copy default SVR DB to current folder
524     snprintf(cmd, sizeof(cmd), "cp %s %s", default_svrdb_path, CRED_FILE);
525     system(cmd);
526
527     OIC_LOG(DEBUG, TAG, "OCServer is starting...");
528
529     // Initialize Persistent Storage for SVR database
530     OCPersistentStorage ps = {server_fopen, fread, fwrite, fclose, unlink};
531
532     OCRegisterPersistentStorageHandler(&ps);
533
534     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
535     {
536         OIC_LOG(ERROR, TAG, "OCStack init error");
537         return 0;
538     }
539
540     /*
541      * Declare and create the example resource: LED
542      */
543     createLEDResource(gResourceUri, &LED, false, 0);
544
545     timeout.tv_sec  = 0;
546     timeout.tv_nsec = 100000000L;
547
548     // Break from loop with Ctrl-C
549     OIC_LOG(INFO, TAG, "Entering ocserver main loop...");
550     signal(SIGINT, handleSigInt);
551     while (!gQuitFlag)
552     {
553         if (OCProcess() != OC_STACK_OK)
554         {
555             OIC_LOG(ERROR, TAG, "OCStack process error");
556             return 0;
557         }
558         nanosleep(&timeout, NULL);
559     }
560
561     OIC_LOG(INFO, TAG, "Exiting ocserver main loop...");
562
563     if (OCStop() != OC_STACK_OK)
564     {
565         OIC_LOG(ERROR, TAG, "OCStack process error");
566     }
567
568     return 0;
569 }
570
571 int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower)
572 {
573     if (!uri)
574     {
575         OIC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
576         return -1;
577     }
578
579     ledResource->state = resourceState;
580     ledResource->power= resourcePower;
581     OCStackResult res = OCCreateResource(&(ledResource->handle),
582             "core.led",
583             OC_RSRVD_INTERFACE_DEFAULT,
584             uri,
585             OCEntityHandlerCb,
586             NULL,
587             OC_DISCOVERABLE|OC_OBSERVABLE | OC_SECURE);
588     OIC_LOG_V(INFO, TAG, "Created LED resource with result: %s", getResult(res));
589
590     return 0;
591 }