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