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