examples: Add notice about using experimental API
[iotivity.git] / resource / csdk / security / provisioning / unittest / sampleserver.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 <signal.h>
27 #include <time.h>
28
29 #include "ocstack.h"
30 #include "ocpayload.h"
31 #include "oic_string.h"
32 #include "srmutility.h"
33 #include "doxmresource.h"
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38
39 /// This example is using experimental API, so there is no guarantee of support for future release,
40 /// nor any there any guarantee that breaking changes will not occur across releases.
41 #include "experimental/logger.h"
42 #include "experimental/ocrandom.h"
43
44 #define TAG "JW_UNITTEST"
45
46 int gQuitFlag = 0;
47 int gNum = 0;
48
49 /* Structure to represent a LED resource */
50 typedef struct LEDRESOURCE{
51     OCResourceHandle handle;
52     bool state;
53     int power;
54 } LEDResource;
55
56 static LEDResource LED;
57 // This variable determines instance number of the LED resource.
58 // Used by POST method to create a new instance of LED resource.
59 static int gCurrLedInstance = 0;
60 #define SAMPLE_MAX_NUM_POST_INSTANCE  2
61 static LEDResource gLedInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
62
63 char *gResourceUri= (char *)"/a/led";
64
65 //Secure Virtual Resource database for Iotivity Server
66 //It contains Server's Identity and the PSK credentials
67 //of other devices which the server trusts
68 static char *gConfigFile;
69
70 /* Function that creates a new LED resource by calling the
71  * OCCreateResource() method.
72  */
73 int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower);
74
75 /* This method converts the payload to JSON format */
76 OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest);
77
78 /* Following methods process the PUT, GET, POST
79  * requests
80  */
81 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
82                                          OCRepPayload **payload);
83 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
84                                          OCRepPayload **payload);
85 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
86                                         OCEntityHandlerResponse *response,
87                                         OCRepPayload **payload);
88
89 /* Entity Handler callback functions */
90 OCEntityHandlerResult
91 OCEntityHandlerCb (OCEntityHandlerFlag flag,
92         OCEntityHandlerRequest *entityHandlerRequest,
93         void* callbackParam);
94
95 const char *getResult(OCStackResult result) {
96     switch (result) {
97     case OC_STACK_OK:
98         return "OC_STACK_OK";
99     case OC_STACK_RESOURCE_CREATED:
100         return "OC_STACK_RESOURCE_CREATED";
101     case OC_STACK_RESOURCE_DELETED:
102         return "OC_STACK_RESOURCE_DELETED";
103     case OC_STACK_INVALID_URI:
104         return "OC_STACK_INVALID_URI";
105     case OC_STACK_INVALID_QUERY:
106         return "OC_STACK_INVALID_QUERY";
107     case OC_STACK_INVALID_IP:
108         return "OC_STACK_INVALID_IP";
109     case OC_STACK_INVALID_PORT:
110         return "OC_STACK_INVALID_PORT";
111     case OC_STACK_INVALID_CALLBACK:
112         return "OC_STACK_INVALID_CALLBACK";
113     case OC_STACK_INVALID_METHOD:
114         return "OC_STACK_INVALID_METHOD";
115     case OC_STACK_NO_MEMORY:
116         return "OC_STACK_NO_MEMORY";
117     case OC_STACK_COMM_ERROR:
118         return "OC_STACK_COMM_ERROR";
119     case OC_STACK_INVALID_PARAM:
120         return "OC_STACK_INVALID_PARAM";
121     case OC_STACK_NOTIMPL:
122         return "OC_STACK_NOTIMPL";
123     case OC_STACK_NO_RESOURCE:
124         return "OC_STACK_NO_RESOURCE";
125     case OC_STACK_RESOURCE_ERROR:
126         return "OC_STACK_RESOURCE_ERROR";
127     case OC_STACK_SLOW_RESOURCE:
128         return "OC_STACK_SLOW_RESOURCE";
129     case OC_STACK_NO_OBSERVERS:
130         return "OC_STACK_NO_OBSERVERS";
131     #ifdef WITH_PRESENCE
132     case OC_STACK_PRESENCE_STOPPED:
133         return "OC_STACK_PRESENCE_STOPPED";
134     #endif
135     case OC_STACK_ERROR:
136         return "OC_STACK_ERROR";
137     default:
138         return "UNKNOWN";
139     }
140 }
141
142 OCRepPayload* getPayload(const char* uri, int64_t power, bool state)
143 {
144     OCRepPayload* payload = OCRepPayloadCreate();
145     if(!payload)
146     {
147         OIC_LOG(FATAL, TAG, "Failed to allocate Payload");
148         return NULL;
149     }
150
151     OCRepPayloadSetUri(payload, uri);
152     OCRepPayloadSetPropBool(payload, "state", state);
153     OCRepPayloadSetPropInt(payload, "power", power);
154
155     return payload;
156 }
157
158 //This function takes the request as an input and returns the response
159 OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest)
160 {
161     if(ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
162     {
163         OIC_LOG(FATAL, TAG, "Incoming payload not a representation");
164         return NULL;
165     }
166
167     OCRepPayload* input = (OCRepPayload*)(ehRequest->payload);
168
169     LEDResource *currLEDResource = &LED;
170
171     if (ehRequest->resource == gLedInstance[0].handle)
172     {
173         currLEDResource = &gLedInstance[0];
174         gResourceUri = (char *) "/a/led/0";
175     }
176     else if (ehRequest->resource == gLedInstance[1].handle)
177     {
178         currLEDResource = &gLedInstance[1];
179         gResourceUri = (char *) "/a/led/1";
180     }
181
182     if(OC_REST_PUT == ehRequest->method)
183     {
184         // Get pointer to query
185         int64_t pow;
186         if(OCRepPayloadGetPropInt(input, "power", &pow))
187         {
188             currLEDResource->power = (int)pow;
189         }
190
191         bool state;
192         if(OCRepPayloadGetPropBool(input, "state", &state))
193         {
194             currLEDResource->state = state;
195         }
196     }
197
198     return getPayload(gResourceUri, currLEDResource->power, currLEDResource->state);
199 }
200
201 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
202         OCRepPayload **payload)
203 {
204     OCEntityHandlerResult ehResult;
205
206     OCRepPayload *getResp = constructResponse(ehRequest);
207
208     if(getResp)
209     {
210         *payload = getResp;
211         ehResult = OC_EH_OK;
212     }
213     else
214     {
215         ehResult = OC_EH_ERROR;
216     }
217
218     return ehResult;
219 }
220
221 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
222         OCRepPayload **payload)
223 {
224     OCEntityHandlerResult ehResult;
225
226     OCRepPayload *putResp = constructResponse(ehRequest);
227
228     if(putResp)
229     {
230         *payload = putResp;
231         ehResult = OC_EH_OK;
232     }
233     else
234     {
235         ehResult = OC_EH_ERROR;
236     }
237
238     return ehResult;
239 }
240
241 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
242         OCEntityHandlerResponse *response, OCRepPayload **payload)
243 {
244     OCRepPayload *respPLPost_led = NULL;
245     OCEntityHandlerResult ehResult = OC_EH_OK;
246
247     /*
248      * The entity handler determines how to process a POST request.
249      * Per the REST paradigm, POST can also be used to update representation of existing
250      * resource or create a new resource.
251      * In the sample below, if the POST is for /a/led then a new instance of the LED
252      * resource is created with default representation (if representation is included in
253      * POST payload it can be used as initial values) as long as the instance is
254      * lesser than max new instance count. Once max instance count is reached, POST on
255      * /a/led updated the representation of /a/led (just like PUT)
256      */
257
258     if (ehRequest->resource == LED.handle)
259     {
260         if (gCurrLedInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
261         {
262             // Create new LED instance
263             char newLedUri[15] = "/a/led/";
264             size_t newLedUriLength = strlen(newLedUri);
265             snprintf (newLedUri + newLedUriLength, sizeof(newLedUri)-newLedUriLength, "%d", gCurrLedInstance);
266
267             respPLPost_led = OCRepPayloadCreate();
268             OCRepPayloadSetUri(respPLPost_led, gResourceUri);
269             OCRepPayloadSetPropString(respPLPost_led, "createduri", newLedUri);
270
271             if (0 == createLEDResource (newLedUri, &gLedInstance[gCurrLedInstance], false, 0))
272             {
273                 OIC_LOG (INFO, TAG, "Created new LED instance");
274                 gLedInstance[gCurrLedInstance].state = 0;
275                 gLedInstance[gCurrLedInstance].power = 0;
276                 gCurrLedInstance++;
277                 strncpy ((char *)response->resourceUri, newLedUri, sizeof(response->resourceUri));
278                 ehResult = OC_EH_RESOURCE_CREATED;
279             }
280         }
281         else
282         {
283             respPLPost_led = constructResponse(ehRequest);
284         }
285     }
286     else
287     {
288         for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
289         {
290             if (ehRequest->resource == gLedInstance[i].handle)
291             {
292                 if (i == 0)
293                 {
294                     respPLPost_led = constructResponse(ehRequest);
295                     break;
296                 }
297                 else if (i == 1)
298                 {
299                     respPLPost_led = constructResponse(ehRequest);
300                 }
301             }
302         }
303     }
304
305     if (respPLPost_led != NULL)
306     {
307         *payload = respPLPost_led;
308         ehResult = OC_EH_OK;
309     }
310     else
311     {
312         OIC_LOG_V (INFO, TAG, "Payload was NULL");
313         ehResult = OC_EH_ERROR;
314     }
315
316     return ehResult;
317 }
318
319 OCEntityHandlerResult
320 OCEntityHandlerCb (OCEntityHandlerFlag flag,
321         OCEntityHandlerRequest *entityHandlerRequest,
322         void* callbackParam)
323 {
324     OIC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
325     (void)callbackParam;
326     OCEntityHandlerResult ehResult = OC_EH_ERROR;
327
328     OCEntityHandlerResponse response;
329     memset(&response, 0, sizeof(response));
330
331     // Validate pointer
332     if (!entityHandlerRequest)
333     {
334         OIC_LOG (FATAL, TAG, "Invalid request pointer");
335         return OC_EH_ERROR;
336     }
337
338     OCRepPayload* payload = NULL;
339
340     if (flag & OC_REQUEST_FLAG)
341     {
342         OIC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
343         if (entityHandlerRequest)
344         {
345             if (OC_REST_GET == entityHandlerRequest->method)
346             {
347                 OIC_LOG (INFO, TAG, "Received OC_REST_GET from client");
348                 ehResult = ProcessGetRequest (entityHandlerRequest, &payload);
349             }
350             else if (OC_REST_PUT == entityHandlerRequest->method)
351             {
352                 OIC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
353                 ehResult = ProcessPutRequest (entityHandlerRequest, &payload);
354             }
355             else if (OC_REST_POST == entityHandlerRequest->method)
356             {
357                 OIC_LOG (INFO, TAG, "Received OC_REST_POST from client");
358                 ehResult = ProcessPostRequest (entityHandlerRequest, &response, &payload);
359             }
360             else
361             {
362                 OIC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
363                         entityHandlerRequest->method);
364                 ehResult = OC_EH_ERROR;
365             }
366
367             if (ehResult == OC_EH_OK && ehResult != OC_EH_FORBIDDEN)
368             {
369                 // Format the response.  Note this requires some info about the request
370                 response.requestHandle = entityHandlerRequest->requestHandle;
371                 response.resourceHandle = entityHandlerRequest->resource;
372                 response.ehResult = ehResult;
373                 response.payload = (OCPayload*)(payload);
374                 response.numSendVendorSpecificHeaderOptions = 0;
375                 memset(response.sendVendorSpecificHeaderOptions, 0,
376                        sizeof(response.sendVendorSpecificHeaderOptions));
377                 memset(response.resourceUri, 0, sizeof(response.resourceUri));
378                 // Indicate that response is NOT in a persistent buffer
379                 response.persistentBufferFlag = 0;
380
381                 // Send the response
382                 if (OCDoResponse(&response) != OC_STACK_OK)
383                 {
384                     OIC_LOG(FATAL, TAG, "Error sending response");
385                     ehResult = OC_EH_ERROR;
386                 }
387             }
388         }
389     }
390
391     OCPayloadDestroy(response.payload);
392     return ehResult;
393 }
394
395 /*signal handler: set gQuitFlag to 1 for graceful termination */
396 void handleSigInt(int signum)
397 {
398     if (signum == SIGTERM)
399     {
400         gQuitFlag = 1;
401     }
402 }
403
404 FILE* server_fopen(const char *path, const char *mode)
405 {
406   if (0 == strcmp(path, OC_SECURITY_DB_DAT_FILE_NAME))
407   {
408     return fopen(gConfigFile, mode);
409   }
410   OIC_LOG_V(DEBUG, TAG, "use db: %s", path);
411   return fopen(path, mode);
412 }
413
414 int main(int argc, char *args[])
415 {
416     struct timespec timeout;
417     if ( argc < 3)
418     {
419         printf("to run: %s num config_file.dat\n", args[0]);
420         exit(1);
421     }
422
423     gNum = atoi(args[1]);
424     gConfigFile = args[2];
425
426     OIC_LOG_V(DEBUG, TAG, "OCServer %d is starting...", gNum);
427
428     // Initialize Persistent Storage for SVR database
429     OCPersistentStorage ps = {server_fopen, fread, fwrite, fclose, unlink};
430
431     OCRegisterPersistentStorageHandler(&ps);
432
433     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
434     {
435         OIC_LOG(FATAL, TAG, "OCStack init error");
436         return 0;
437     }
438
439     OicUuid_t uuid;
440     char uuidString[UUID_STRING_SIZE] = {0};
441     snprintf(uuidString, UUID_STRING_SIZE, "11111111-1234-1234-1234-12345678901%d",gNum);
442     ConvertStrToUuid(uuidString, &uuid);
443
444     if (OC_STACK_OK != SetDoxmDeviceID(&uuid))
445     {
446         OIC_LOG(WARNING, TAG, "Can't change deviceID in server");
447     }
448
449     /*
450      * Declare and create the example resource: LED
451      */
452     if (createLEDResource(gResourceUri, &LED, false, 0) != 0)
453     {
454         OIC_LOG(FATAL, TAG, "exit");
455         return -1;
456     }
457
458     timeout.tv_sec  = 0;
459     timeout.tv_nsec = 100000000L;
460
461     signal(SIGTERM, handleSigInt);
462
463     OIC_LOG(INFO, TAG, "Entering ocserver main loop...");
464
465     while (!gQuitFlag)
466     {
467         if (OCProcess() != OC_STACK_OK)
468         {
469             OIC_LOG(FATAL, TAG, "OCStack process error");
470             return 0;
471         }
472         nanosleep(&timeout, NULL);
473     }
474
475     OIC_LOG(INFO, TAG, "Exiting ocserver main loop...");
476
477     if (OCStop() != OC_STACK_OK)
478     {
479         OIC_LOG(FATAL, TAG, "OCStack process error");
480     }
481
482     return 0;
483 }
484
485 int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower)
486 {
487     if (!uri)
488     {
489         OIC_LOG(FATAL, TAG, "Resource URI cannot be NULL");
490         return -1;
491     }
492
493     ledResource->state = resourceState;
494     ledResource->power= resourcePower;
495     OCStackResult res = OCCreateResource(&(ledResource->handle),
496             "core.led",
497             OC_RSRVD_INTERFACE_DEFAULT,
498             uri,
499             OCEntityHandlerCb,
500             NULL,
501             OC_DISCOVERABLE|OC_OBSERVABLE | OC_SECURE);
502
503     if (OC_STACK_OK != res)
504     {
505         OIC_LOG (FATAL, TAG, "Unable to instantiate LED resource");
506         return 1;
507     }
508     else
509     {
510         OIC_LOG_V(INFO, TAG, "Created LED resource with result: %s", getResult(res));
511     }
512
513     return 0;
514 }