Merge "Merge branch 'master' into resource-manipulation" into resource-manipulation
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / linux / SimpleClientServer / ocserverbasicops.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 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 "ocstack.h"
28 #include "logger.h"
29 #include "cJSON.h"
30 #include "ocserverbasicops.h"
31
32 //string length of "/a/led/" + std::numeric_limits<int>::digits10 + '\0'"
33 // 7 + 9 + 1 = 17
34 const int URI_MAXSIZE = 17;
35
36 volatile sig_atomic_t gQuitFlag = 0;
37
38 static LEDResource LED;
39 // This variable determines instance number of the LED resource.
40 // Used by POST method to create a new instance of LED resource.
41 static int gCurrLedInstance = 0;
42 #define SAMPLE_MAX_NUM_POST_INSTANCE 2
43 static LEDResource gLedInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
44
45 char *gResourceUri= (char *)"/a/led";
46
47 //This function takes the request as an input and returns the response
48 //in JSON format.
49 char* constructJsonResponse (OCEntityHandlerRequest *ehRequest)
50 {
51     cJSON *json = cJSON_CreateObject();
52
53     if(!json)
54     {
55         OC_LOG (ERROR, TAG, "json object not created properly");
56         return NULL;
57     }
58
59     cJSON *format;
60     cJSON *putJson = NULL;
61     char *jsonResponse = NULL;
62     LEDResource *currLEDResource = &LED;
63
64     if (ehRequest->resource == gLedInstance[0].handle)
65     {
66         currLEDResource = &gLedInstance[0];
67         gResourceUri = (char *) "/a/led/0";
68     }
69     else if (ehRequest->resource == gLedInstance[1].handle)
70     {
71         currLEDResource = &gLedInstance[1];
72         gResourceUri = (char *) "/a/led/1";
73     }
74
75     if(OC_REST_PUT == ehRequest->method)
76     {
77         cJSON* jsonObj = NULL;
78         putJson = cJSON_Parse(ehRequest->reqJSONPayload);
79         if(putJson)
80         {
81             jsonObj = cJSON_GetObjectItem(putJson,"oic");
82             if (jsonObj)
83             {
84                 jsonObj = cJSON_GetArrayItem(jsonObj, 0);
85                 if (jsonObj)
86                 {
87                     jsonObj = cJSON_GetObjectItem(jsonObj, "rep");
88                 }
89             }
90         }
91         if (NULL == jsonObj)
92         {
93             OC_LOG_V(ERROR, TAG, "Failed to parse JSON: %s", ehRequest->reqJSONPayload);
94             goto exit;
95         }
96
97         cJSON* prop = cJSON_GetObjectItem(jsonObj,"power");
98         if (prop)
99         {
100             currLEDResource->power =prop->valueint;
101         }
102
103         prop = cJSON_GetObjectItem(jsonObj,"state");
104         if (prop)
105         {
106             currLEDResource->state = prop->valueint;
107         }
108     }
109
110     cJSON_AddStringToObject(json,"href",gResourceUri);
111     format = cJSON_CreateObject();
112
113     if(!format)
114     {
115         OC_LOG (ERROR, TAG, "format object not created properly");
116         goto exit;
117     }
118
119     cJSON_AddItemToObject(json, "rep", format);
120     cJSON_AddStringToObject(format, "state", (char *) (currLEDResource->state ? "on":"off"));
121     cJSON_AddNumberToObject(format, "power", currLEDResource->power);
122
123     jsonResponse = cJSON_Print(json);
124
125 exit:
126     cJSON_Delete(putJson);
127     cJSON_Delete(json);
128     return jsonResponse;
129 }
130
131 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest, char *payload,
132         uint16_t maxPayloadSize)
133 {
134     OCEntityHandlerResult ehResult;
135     char *getResp = constructJsonResponse(ehRequest);
136
137     if(getResp)
138     {
139         if (maxPayloadSize > strlen ((char *)getResp))
140         {
141             strncpy(payload, getResp, strlen((char *)getResp));
142             ehResult = OC_EH_OK;
143         }
144         else
145         {
146             OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
147                     maxPayloadSize);
148             ehResult = OC_EH_ERROR;
149         }
150
151         free(getResp);
152     }
153     else
154     {
155         ehResult = OC_EH_ERROR;
156     }
157
158     return ehResult;
159 }
160
161 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest, char *payload,
162         uint16_t maxPayloadSize)
163 {
164     OCEntityHandlerResult ehResult;
165     char *putResp = constructJsonResponse(ehRequest);
166
167     if(putResp)
168     {
169         if (maxPayloadSize > strlen ((char *)putResp))
170         {
171             strncpy(payload, putResp, strlen((char *)putResp));
172             ehResult = OC_EH_OK;
173         }
174         else
175         {
176             OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
177                     maxPayloadSize);
178             ehResult = OC_EH_ERROR;
179         }
180
181         free(putResp);
182     }
183     else
184     {
185         ehResult = OC_EH_ERROR;
186     }
187
188     return ehResult;
189 }
190
191 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest, char *payload,
192         uint16_t maxPayloadSize)
193 {
194     char *respPLPost_led = NULL;
195     cJSON *json;
196     cJSON *format;
197     OCEntityHandlerResult ehResult;
198
199     /*
200      * The entity handler determines how to process a POST request.
201      * Per the REST paradigm, POST can also be used to update representation of existing
202      * resource or create a new resource.
203      * In the sample below, if the POST is for /a/led then a new instance of the LED
204      * resource is created with default representation (if representation is included in
205      * POST payload it can be used as initial values) as long as the instance is
206      * lesser than max new instance count. Once max instance count is reached, POST on
207      * /a/led updated the representation of /a/led (just like PUT)
208      */
209
210     if (ehRequest->resource == LED.handle)
211     {
212         if (gCurrLedInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
213         {
214             // Create new LED instance
215             char newLedUri[URI_MAXSIZE ];
216             snprintf(newLedUri, URI_MAXSIZE, "/a/led/%d", gCurrLedInstance);
217
218             json = cJSON_CreateObject();
219             if(!json)
220             {
221                 return OC_EH_ERROR;
222             }
223
224             cJSON_AddStringToObject(json,"href",gResourceUri);
225             format = cJSON_CreateObject();
226
227             if(!format)
228             {
229                 return OC_EH_ERROR;
230             }
231
232             cJSON_AddItemToObject(json, "rep", format);
233             cJSON_AddStringToObject(format, "createduri", (char *) newLedUri);
234
235             if (0 == createLEDResource (newLedUri, &gLedInstance[gCurrLedInstance], false, 0))
236             {
237                 OC_LOG (INFO, TAG, "Created new LED instance");
238                 gLedInstance[gCurrLedInstance].state = 0;
239                 gLedInstance[gCurrLedInstance].power = 0;
240                 gCurrLedInstance++;
241                 respPLPost_led = cJSON_Print(json);
242             }
243
244             cJSON_Delete(json);
245         }
246         else
247         {
248             respPLPost_led = constructJsonResponse(ehRequest);
249         }
250     }
251     else
252     {
253         for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
254         {
255             if (ehRequest->resource == gLedInstance[i].handle)
256             {
257                 if (i == 0)
258                 {
259                     respPLPost_led = constructJsonResponse(ehRequest);
260                     break;
261                 }
262                 else if (i == 1)
263                 {
264                     respPLPost_led = constructJsonResponse(ehRequest);
265                 }
266             }
267         }
268     }
269
270     if ((respPLPost_led != NULL) && (maxPayloadSize > strlen ((char *)respPLPost_led)))
271     {
272         strncpy(payload, respPLPost_led, strlen((char *)respPLPost_led));
273         ehResult = OC_EH_OK;
274     }
275     else
276     {
277         OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
278                 maxPayloadSize);
279         ehResult = OC_EH_ERROR;
280     }
281
282     free(respPLPost_led);
283
284     return ehResult;
285 }
286
287 OCEntityHandlerResult
288 OCEntityHandlerCb (OCEntityHandlerFlag flag,
289         OCEntityHandlerRequest *entityHandlerRequest,void* callbackParam)
290 {
291     OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
292
293     OCEntityHandlerResult ehResult = OC_EH_ERROR;
294     OCEntityHandlerResponse response;
295     char payload[MAX_RESPONSE_LENGTH] = {0};
296
297     if (flag & OC_REQUEST_FLAG)
298     {
299         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
300         if (entityHandlerRequest)
301         {
302             if (OC_REST_GET == entityHandlerRequest->method)
303             {
304                 OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
305                 ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
306             }
307             else if (OC_REST_PUT == entityHandlerRequest->method)
308             {
309                 OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
310                 ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
311             }
312             else if (OC_REST_POST == entityHandlerRequest->method)
313             {
314                 OC_LOG (INFO, TAG, "Received OC_REST_POST from client");
315                 ehResult = ProcessPostRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
316             }
317             else
318             {
319                 OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
320                         entityHandlerRequest->method);
321             }
322
323             if (ehResult == OC_EH_OK)
324             {
325                 // Format the response.  Note this requires some info about the request
326                 response.requestHandle = entityHandlerRequest->requestHandle;
327                 response.resourceHandle = entityHandlerRequest->resource;
328                 response.ehResult = ehResult;
329                 response.payload = payload;
330                 response.payloadSize = strlen(payload);
331                 response.numSendVendorSpecificHeaderOptions = 0;
332                 memset(response.sendVendorSpecificHeaderOptions, 0, sizeof response.sendVendorSpecificHeaderOptions);
333                 memset(response.resourceUri, 0, sizeof(response.resourceUri));
334                 // Indicate that response is NOT in a persistent buffer
335                 response.persistentBufferFlag = 0;
336
337                 // Send the response
338                 if (OCDoResponse(&response) != OC_STACK_OK)
339                 {
340                     OC_LOG(ERROR, TAG, "Error sending response");
341                     ehResult = OC_EH_ERROR;
342                 }
343             }
344         }
345     }
346     return ehResult;
347 }
348
349 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
350 void handleSigInt(int signum)
351 {
352     if (signum == SIGINT)
353     {
354         gQuitFlag = 1;
355     }
356 }
357
358 int main(int argc, char* argv[])
359 {
360     OC_LOG(DEBUG, TAG, "OCServer is starting...");
361     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
362     {
363         OC_LOG(ERROR, TAG, "OCStack init error");
364         return 0;
365     }
366
367     /*
368      * Declare and create the example resource: LED
369      */
370     createLEDResource(gResourceUri, &LED, false, 0);
371
372     // Break from loop with Ctrl-C
373     OC_LOG(INFO, TAG, "Entering ocserver main loop...");
374     signal(SIGINT, handleSigInt);
375     while (!gQuitFlag)
376     {
377         if (OCProcess() != OC_STACK_OK)
378         {
379             OC_LOG(ERROR, TAG, "OCStack process error");
380             return 0;
381         }
382
383         sleep(2);
384     }
385
386     OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
387
388     if (OCStop() != OC_STACK_OK)
389     {
390         OC_LOG(ERROR, TAG, "OCStack process error");
391     }
392
393     return 0;
394 }
395
396 int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower)
397 {
398     if (!uri)
399     {
400         OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
401         return -1;
402     }
403
404     ledResource->state = resourceState;
405     ledResource->power= resourcePower;
406     OCStackResult res = OCCreateResource(&(ledResource->handle),
407             "core.led",
408             OC_RSRVD_INTERFACE_DEFAULT,
409             uri,
410             OCEntityHandlerCb,
411             NULL,
412             OC_DISCOVERABLE|OC_OBSERVABLE);
413     OC_LOG_V(INFO, TAG, "Created LED resource with result: %s", getResult(res));
414
415     return 0;
416 }
417