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