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