Imported Upstream version 0.9.1
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / linux / SimpleClientServer / ocserverslow.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 <sys/time.h>
28 #include <list>
29 #include "ocstack.h"
30 #include "ocmalloc.h"
31 #include "logger.h"
32 #include "cJSON.h"
33 #include "ocserverslow.h"
34
35 volatile sig_atomic_t gQuitFlag = 0;
36
37 static std::list<OCEntityHandlerRequest *> gRequestList;
38 static constexpr unsigned int SLOW_RESPONSE_DELAY_SEC = 5;
39
40 static LEDResource LED;
41
42 static constexpr unsigned int SAMPLE_MAX_NUM_POST_INSTANCE = 2;
43 static LEDResource gLedInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
44
45 //char *gResourceUri= const_cast<char *>("/a/led");
46 char *gResourceUri= (char *)"/a/led";
47
48 //This function takes the request as an input and returns the response
49 //in JSON format.
50 char* constructJsonResponse (OCEntityHandlerRequest *ehRequest)
51 {
52     cJSON *json = cJSON_CreateObject();
53
54     if(!json)
55     {
56         OC_LOG(ERROR, TAG, "CreateObject result in null for json");
57         return NULL;
58     }
59
60     cJSON *format;
61     char *jsonResponse;
62     LEDResource *currLEDResource = &LED;
63
64     OC_LOG(INFO, TAG, "Entering constructJsonResponse");
65
66     if (ehRequest->resource == gLedInstance[0].handle)
67     {
68         OC_LOG(INFO, TAG, "handle 0");
69         currLEDResource = &gLedInstance[0];
70         gResourceUri = const_cast<char *>("a/led/0");
71     }
72     else if (ehRequest->resource == gLedInstance[1].handle)
73     {
74         OC_LOG(INFO, TAG, "handle 1");
75         currLEDResource = &gLedInstance[1];
76         gResourceUri = const_cast<char *>("a/led/1");
77     }
78
79     if(OC_REST_PUT == ehRequest->method)
80     {
81         cJSON *putJson = cJSON_Parse((char *)ehRequest->reqJSONPayload);
82
83         if(!putJson)
84         {
85             OC_LOG(ERROR, TAG, "CreateObject result in null for putJson");
86             cJSON_Delete(json);
87             return NULL;
88         }
89
90         currLEDResource->state = ( !strcmp(cJSON_GetObjectItem(putJson,"state")->valuestring ,
91                 "on") ? true:false);
92         currLEDResource->power = cJSON_GetObjectItem(putJson,"power")->valuedouble;
93         cJSON_Delete(putJson);
94     }
95
96     cJSON_AddStringToObject(json,"href",gResourceUri);
97     format = cJSON_CreateObject();
98
99     if(!format)
100     {
101         OC_LOG(ERROR, TAG, "CreateObject result in null for format");
102         cJSON_Delete(json);
103         return NULL;
104     }
105
106     cJSON_AddItemToObject(json, "rep", format);
107     cJSON_AddStringToObject(format, "state", (char *) (currLEDResource->state ? "on":"off"));
108     cJSON_AddNumberToObject(format, "power", currLEDResource->power);
109
110     OC_LOG(INFO, TAG, "Before constructJsonResponse print");
111     jsonResponse = cJSON_Print(json);
112     OC_LOG(INFO, TAG, "Before constructJsonResponse delete");
113     cJSON_Delete(json);
114
115     OC_LOG(INFO, TAG, "Before constructJsonResponse return");
116     return jsonResponse;
117 }
118
119 void ProcessGetRequest (OCEntityHandlerRequest *ehRequest)
120 {
121     OC_LOG(INFO, TAG, "Entering ProcessGetRequest");
122     char *getResp = constructJsonResponse(ehRequest);
123
124     if(!getResp)
125     {
126         OC_LOG(ERROR, TAG, "Failed to constructJsonResponse");
127         return;
128     }
129     OC_LOG(INFO, TAG, "After constructJsonResponse");
130     OCEntityHandlerResponse response;
131
132     // Format the response.  Note this requires some info about the request
133     response.requestHandle = ehRequest->requestHandle;
134     response.resourceHandle = ehRequest->resource;
135     response.ehResult = OC_EH_OK;
136     response.payload = getResp;
137     response.payloadSize = strlen(getResp) + 1;
138     response.numSendVendorSpecificHeaderOptions = 0;
139     memset(response.sendVendorSpecificHeaderOptions,
140             0, sizeof response.sendVendorSpecificHeaderOptions);
141     memset(response.resourceUri, 0, sizeof(response.resourceUri));
142     // Indicate that response is NOT in a persistent buffer
143     response.persistentBufferFlag = 0;
144
145     // Send the response
146     if (OCDoResponse(&response) != OC_STACK_OK)
147     {
148         OC_LOG(ERROR, TAG, "Error sending response");
149     }
150
151     free(getResp);
152 }
153
154 OCEntityHandlerRequest *CopyRequest(OCEntityHandlerRequest *entityHandlerRequest)
155 {
156     OC_LOG(INFO, TAG, "Copying received request for slow response");
157     OCEntityHandlerRequest *request =
158             (OCEntityHandlerRequest *)OCMalloc(sizeof(OCEntityHandlerRequest));
159     if (request)
160     {
161         // Do shallow copy
162         memcpy(request, entityHandlerRequest, sizeof(OCEntityHandlerRequest));
163         // Do deep copy of query
164         request->query =
165                 (char * )OCMalloc(strlen((const char *)entityHandlerRequest->query) + 1);
166         if (request->query)
167         {
168             strcpy((char *)request->query, (const char *)entityHandlerRequest->query);
169
170             // Copy the request payload
171             request->reqJSONPayload = (char * )OCMalloc(
172                             strlen((const char *)entityHandlerRequest->reqJSONPayload) + 1);
173             if (request->reqJSONPayload)
174             {
175                 strcpy((char *)request->reqJSONPayload,
176                         (const char *)entityHandlerRequest->reqJSONPayload);
177
178                 // Ignore vendor specific header options for example
179                 request->numRcvdVendorSpecificHeaderOptions = 0;
180                 request->rcvdVendorSpecificHeaderOptions = NULL;
181             }
182             else
183             {
184                 OCFree(request->query);
185                 OCFree(request);
186                 request = NULL;
187             }
188         }
189         else
190         {
191             OCFree(request);
192             request = NULL;
193         }
194     }
195
196     if (request)
197     {
198         OC_LOG(INFO, TAG, "Copied client request");
199     }
200     else
201     {
202         OC_LOG(ERROR, TAG, "Error copying client request");
203     }
204     return request;
205 }
206
207 OCEntityHandlerResult
208 OCEntityHandlerCb (OCEntityHandlerFlag flag,
209         OCEntityHandlerRequest *entityHandlerRequest)
210 {
211     OCEntityHandlerResult result = OC_EH_ERROR;
212     OCEntityHandlerRequest *request = NULL;
213
214     OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
215     if (flag & OC_REQUEST_FLAG)
216     {
217         OC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
218         if (entityHandlerRequest)
219         {
220             OC_LOG_V (INFO, TAG, "request query %s from client",
221                                         entityHandlerRequest->query);
222             OC_LOG_V (INFO, TAG, "request payload %s from client",
223                                         entityHandlerRequest->reqJSONPayload);
224             // Make deep copy of received request and queue it for slow processing
225             request = CopyRequest(entityHandlerRequest);
226             if (request)
227             {
228
229                 OC_LOG(INFO, TAG, "Scheduling slow response for received request");
230                 gRequestList.push_back(request);
231                 // Indicate to the stack that this is a slow response
232                 result = OC_EH_SLOW;
233                 // Start the slow response alarm
234                 alarm(SLOW_RESPONSE_DELAY_SEC);
235             }
236             else
237             {
238                 OC_LOG(ERROR, TAG, "Error queuing request for slow response");
239                 // Indicate to the stack that this is a slow response
240                 result = OC_EH_ERROR;
241             }
242         }
243         else
244         {
245             OC_LOG(ERROR, TAG, "Invalid request");
246             result = OC_EH_ERROR;
247         }
248     }
249     return result;
250 }
251
252 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
253 void handleSigInt(int signum)
254 {
255     if (signum == SIGINT)
256     {
257         gQuitFlag = 1;
258     }
259 }
260
261 // SIGINT alarm handler:  alarm set by entity handler.  Does
262 // slow response when fired
263 void AlarmHandler(int sig)
264 {
265     if (sig == SIGALRM)
266     {
267         OC_LOG (INFO, TAG, "Server starting slow response");
268         if (gRequestList.empty())
269         {
270             OC_LOG (INFO, TAG, "No requests to service");
271             return;
272         }
273
274         // Get the request from the list
275         OCEntityHandlerRequest *entityHandlerRequest = gRequestList.front();
276         gRequestList.pop_front();
277         if (entityHandlerRequest->method == OC_REST_GET)
278         {
279             OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
280             ProcessGetRequest (entityHandlerRequest);
281         }
282         else
283         {
284             OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
285                     entityHandlerRequest->method);
286         }
287         // Free the request
288         OCFree(entityHandlerRequest->query);
289         OCFree(entityHandlerRequest->reqJSONPayload);
290         OCFree(entityHandlerRequest);
291
292         // If there are more requests in list, re-arm the alarm signal
293         if (gRequestList.empty())
294         {
295             alarm(SLOW_RESPONSE_DELAY_SEC);
296         }
297     }
298 }
299
300 int main(int argc, char* argv[])
301 {
302     OC_LOG(DEBUG, TAG, "OCServer is starting...");
303
304     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
305     {
306         OC_LOG(ERROR, TAG, "OCStack init error");
307         return 0;
308     }
309
310     /*
311      * Declare and create the example resource: LED
312      */
313     createLEDResource(gResourceUri, &LED, false, 0);
314
315     // Initialize slow response alarm
316     signal(SIGALRM, AlarmHandler);
317
318     // Break from loop with Ctrl-C
319     OC_LOG(INFO, TAG, "Entering ocserver main loop...");
320     signal(SIGINT, handleSigInt);
321
322     while (!gQuitFlag)
323     {
324         if (OCProcess() != OC_STACK_OK)
325         {
326             OC_LOG(ERROR, TAG, "OCStack process error");
327             return 0;
328         }
329
330         sleep(2);
331     }
332
333     OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
334
335     // Free requests
336     if (!gRequestList.empty())
337     {
338         for (auto iter = gRequestList.begin(); iter != gRequestList.end(); ++iter)
339         {
340             OCFree((*iter)->query);
341             OCFree((*iter)->reqJSONPayload);
342             OCFree(*iter);
343         }
344         gRequestList.clear();
345     }
346
347     if (OCStop() != OC_STACK_OK)
348     {
349         OC_LOG(ERROR, TAG, "OCStack process error");
350     }
351
352     return 0;
353 }
354
355 int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower)
356 {
357     if (!uri)
358     {
359         OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
360         return -1;
361     }
362
363     ledResource->state = resourceState;
364     ledResource->power= resourcePower;
365     OCStackResult res = OCCreateResource(&(ledResource->handle),
366             "core.led",
367             OC_RSRVD_INTERFACE_DEFAULT,
368             uri,
369             OCEntityHandlerCb,
370             OC_DISCOVERABLE|OC_OBSERVABLE);
371     OC_LOG_V(INFO, TAG, "Created LED resource with result: %s", getResult(res));
372
373     return 0;
374 }
375