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