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