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