[IOT-1569] Use OICMalloc/OICFree consistently
[platform/upstream/iotivity.git] / resource / csdk / stack / src / oicgroup.c
1 //******************************************************************
2 //
3 // Copyright 2014 Samsung Electronics 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 #define _POSIX_C_SOURCE 200112L
22
23 #include "iotivity_config.h"
24
25 #include <string.h>
26
27 #include "oicgroup.h"
28 #include "cJSON.h"
29 #include "cbor.h"
30 #include "ocpayload.h"
31 #include "oic_malloc.h"
32 #include "oic_string.h"
33 #include "occollection.h"
34 #include "logger.h"
35 #include "timer.h"
36
37 #define TAG "OIC_RI_GROUP"
38
39 #define DESC_DELIMITER          "\""
40 #define ACTION_DELIMITER        "*"
41 #define ATTR_DELIMITER          "|"
42 #define ATTR_ASSIGN             "="
43
44 // Definitions for operations related to actions
45 #define DO_ACTION               "DoAction"
46 #define GET_ACTIONSET           "GetActionSet"
47 #define ACTIONSET               "ActionSet"
48 #define CANCEL_ACTIONSET        "CancelAction"
49 #define DELETE_ACTIONSET        "DelActionSet"
50
51 #define DEFAULT_CONTEXT_VALUE 0x99
52
53 #define VARIFY_POINTER_NULL(pointer, result, toExit) \
54     if(pointer == NULL) \
55     {\
56         result = OC_STACK_NO_MEMORY;\
57         goto toExit;\
58     }
59 #define VARIFY_PARAM_NULL(pointer, result, toExit) \
60     if(pointer == NULL)\
61     {\
62         result = OC_STACK_INVALID_PARAM;\
63         goto exit;\
64     }
65
66 #define OCFREE(pointer) \
67     { \
68         OICFree(pointer); \
69         pointer = NULL; \
70     }
71
72 // Mutex implementation macros
73 #if defined(HAVE_PTHREAD_H)
74
75  #include <pthread.h>
76  pthread_mutex_t g_scheduledResourceLock;
77  #define MUTEX_LOCK(ARG_NAME)       { pthread_mutex_lock(ARG_NAME); }
78  #define MUTEX_UNLOCK(ARG_NAME)     { pthread_mutex_unlock(ARG_NAME); }
79  #define MUTEX_INITIALIZE(ARG_NAME) { }
80  #define MUTEX_TERMINATE(ARG_NAME)  { }
81
82 #elif defined(HAVE_WINDOWS_H)
83
84  #include <windows.h>
85  CRITICAL_SECTION g_scheduledResourceLock;
86  bool g_initializedScheduledResourceLock = false;
87  #define MUTEX_LOCK(ARG_NAME)       { EnterCriticalSection(ARG_NAME); }
88  #define MUTEX_UNLOCK(ARG_NAME)     { LeaveCriticalSection(ARG_NAME); }
89  #define MUTEX_INITIALIZE(ARG_NAME) { assert(!g_initializedScheduledResourceLock); \
90                                       InitializeCriticalSection(ARG_NAME); \
91                                       g_initializedScheduledResourceLock = true; \
92                                     }
93  #define MUTEX_TERMINATE(ARG_NAME)  { if (g_initializedScheduledResourceLock) \
94                                       { \
95                                           DeleteCriticalSection(ARG_NAME); \
96                                           g_initializedScheduledResourceLock = false; \
97                                       } \
98                                     }
99
100 #elif defined(WITH_ARDUINO)
101
102  #define MUTEX_LOCK(ARG_NAME)       { }
103  #define MUTEX_UNLOCK(ARG_NAME)     { }
104  #define MUTEX_INITIALIZE(ARG_NAME) { }
105  #define MUTEX_TERMINATE(ARG_NAME)  { }
106
107 #else
108
109  ERROR Need mutex implementation on this platform
110
111 #endif
112
113 enum ACTION_TYPE
114 {
115     NONE = 0, SCHEDULED, RECURSIVE
116 };
117
118 typedef struct scheduledresourceinfo
119 {
120     OCResource *resource;
121     OCActionSet *actionset;
122
123     int timer_id;
124
125     OCServerRequest *ehRequest;
126
127     time_t time;
128     struct scheduledresourceinfo* next;
129 } ScheduledResourceInfo;
130
131 ScheduledResourceInfo *g_scheduleResourceList = NULL;
132
133 void AddScheduledResource(ScheduledResourceInfo **head,
134         ScheduledResourceInfo* add)
135 {
136     OIC_LOG(INFO, TAG, "AddScheduledResource Entering...");
137
138     MUTEX_LOCK(&g_scheduledResourceLock);
139     ScheduledResourceInfo *tmp = NULL;
140
141     if (*head != NULL)
142     {
143         tmp = *head;
144
145         while (tmp->next)
146         {
147             tmp = tmp->next;
148         }
149         tmp->next = add;
150     }
151     else
152     {
153         *head = add;
154     }
155     MUTEX_UNLOCK(&g_scheduledResourceLock);
156 }
157
158 ScheduledResourceInfo* GetScheduledResource(ScheduledResourceInfo *head)
159 {
160     OIC_LOG(INFO, TAG, "GetScheduledResource Entering...");
161
162     MUTEX_LOCK(&g_scheduledResourceLock);
163
164     time_t t_now;
165
166     ScheduledResourceInfo *tmp = NULL;
167     tmp = head;
168
169 #if !defined(WITH_ARDUINO)
170     time(&t_now);
171 #else
172     t_now = now();
173 #endif
174
175     if (tmp)
176     {
177         while (tmp)
178         {
179             time_t diffTm = 0;
180             diffTm = timespec_diff(tmp->time, t_now);
181
182             if (diffTm <= (time_t) 0)
183             {
184                 OIC_LOG(INFO, TAG, "return Call INFO.");
185                 goto exit;
186             }
187
188             tmp = tmp->next;
189         }
190     }
191
192     exit:
193
194     MUTEX_UNLOCK(&g_scheduledResourceLock);
195
196     if (tmp == NULL)
197     {
198         OIC_LOG(INFO, TAG, "Cannot Find Call Info.");
199     }
200     return tmp;
201 }
202
203 ScheduledResourceInfo* GetScheduledResourceByActionSetName(ScheduledResourceInfo *head, char *setName)
204 {
205     OIC_LOG(INFO, TAG, "GetScheduledResourceByActionSetName Entering...");
206
207     MUTEX_LOCK(&g_scheduledResourceLock);
208
209     ScheduledResourceInfo *tmp = NULL;
210     tmp = head;
211
212     if (tmp)
213     {
214         while (tmp)
215         {
216             if (strcmp(tmp->actionset->actionsetName, setName) == 0)
217             {
218                 OIC_LOG(INFO, TAG, "return Call INFO.");
219                 goto exit;
220             }
221             tmp = tmp->next;
222         }
223     }
224
225 exit:
226
227     MUTEX_UNLOCK(&g_scheduledResourceLock);
228
229     if (tmp == NULL)
230     {
231         OIC_LOG(INFO, TAG, "Cannot Find Call Info.");
232     }
233     return tmp;
234 }
235
236 void RemoveScheduledResource(ScheduledResourceInfo **head,
237         ScheduledResourceInfo* del)
238 {
239
240     MUTEX_LOCK(&g_scheduledResourceLock);
241
242     OIC_LOG(INFO, TAG, "RemoveScheduledResource Entering...");
243     ScheduledResourceInfo *tmp = NULL;
244
245     if (del == NULL)
246     {
247
248         MUTEX_UNLOCK(&g_scheduledResourceLock);
249
250         return;
251     }
252
253     if (*head == del)
254     {
255         *head = (*head)->next;
256     }
257     else
258     {
259         tmp = *head;
260         while (tmp->next && (tmp->next != del))
261         {
262             tmp = tmp->next;
263         }
264         if (tmp->next)
265         {
266             tmp->next = del->next;
267         }
268     }
269
270     OCFREE(del)
271
272     MUTEX_UNLOCK(&g_scheduledResourceLock);
273 }
274
275 typedef struct aggregatehandleinfo
276 {
277     OCServerRequest *ehRequest;
278     OCDoHandle required;
279     OCResource *collResource;
280
281     struct aggregatehandleinfo *next;
282 } ClientRequestInfo;
283
284 ClientRequestInfo *clientRequstList = NULL;
285
286 void AddClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* add)
287 {
288     ClientRequestInfo *tmp = NULL;
289
290     if (*head != NULL)
291     {
292         tmp = *head;
293
294         while (tmp->next)
295         {
296             tmp = tmp->next;
297         }
298         tmp->next = add;
299     }
300     else
301     {
302         *head = add;
303     }
304 }
305
306 ClientRequestInfo* GetClientRequestInfo(ClientRequestInfo *head,
307         OCDoHandle handle)
308 {
309     ClientRequestInfo *tmp = NULL;
310
311     tmp = head;
312
313     if (tmp)
314     {
315         while (tmp)
316         {
317             if (tmp->required == handle)
318             {
319                 break;
320             }
321
322             tmp = tmp->next;
323         }
324
325         return tmp;
326     }
327     return NULL;
328 }
329
330 void RemoveClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* del)
331 {
332     ClientRequestInfo *tmp = NULL;
333
334     if (del == NULL)
335         return;
336
337     if (*head == del)
338     {
339         *head = (*head)->next;
340     }
341     else
342     {
343         tmp = *head;
344         while (tmp->next && (tmp->next != del))
345         {
346             tmp = tmp->next;
347         }
348         if (tmp->next)
349         {
350             tmp->next = del->next;
351         }
352     }
353 }
354
355 void AddCapability(OCCapability** head, OCCapability* node)
356 {
357     OCCapability *pointer = *head;
358     if (NULL == pointer)
359     {
360         *head = node;
361     }
362     else
363     {
364         while (pointer->next != NULL)
365         {
366             pointer = pointer->next;
367         }
368
369         pointer->next = node;
370     }
371 }
372
373 void AddAction(OCAction** head, OCAction* node)
374 {
375     OCAction *pointer = *head;
376     if (NULL == pointer)
377     {
378         *head = node;
379     }
380     else
381     {
382
383         while (pointer->next != NULL)
384         {
385             pointer = pointer->next;
386         }
387
388         pointer->next = node;
389     }
390 }
391
392 OCStackResult AddActionSet(OCActionSet **head, OCActionSet* node)
393 {
394     OCActionSet *pointer = *head;
395     OCActionSet *prev = NULL;
396     if(node == NULL)
397     {
398         return OC_STACK_ERROR;
399     }
400     if (NULL == pointer)
401     {
402         *head = node;
403     }
404     else
405     {
406         prev = pointer;
407         while (pointer != NULL)
408         {
409             // check the uniqeness of actionsetname.
410             if (strcmp(pointer->actionsetName, node->actionsetName) == 0)
411             {
412                 return OC_STACK_ERROR;
413             }
414
415             prev = pointer;
416             pointer = pointer->next;
417         }
418
419         prev->next = node;
420     }
421
422     return OC_STACK_OK;
423 }
424
425 void DeleteCapability(OCCapability *del)
426 {
427     OCFREE(del->capability)
428     del->capability = NULL;
429     OCFREE(del->status)
430     del->status = NULL;
431     OCFREE(del)
432 }
433
434 void DeleteAction(OCAction** action)
435 {
436     OCCapability* pointer = (*action)->head;
437     OCCapability* pDel = NULL;
438
439     while (pointer)
440     {
441         pDel = pointer;
442         pointer = pointer->next;
443
444         DeleteCapability(pDel);
445     }
446     OCFREE((*action)->resourceUri)
447     (*action)->next = NULL;
448     OCFREE(*action)
449 }
450
451 void DeleteActionSet(OCActionSet** actionset)
452 {
453     OCAction* pointer = NULL;
454     OCAction* pDel = NULL;
455
456     if(*actionset == NULL)
457         return;
458
459     pointer = (*actionset)->head;
460
461     while (pointer)
462     {
463         pDel = pointer;
464         pointer = pointer->next;
465
466         DeleteAction(&pDel);
467     }
468     //    (*actionset)->head = NULL;
469     OCFREE((*actionset)->actionsetName)
470     OCFREE(*actionset)
471 }
472
473 OCStackResult FindAndDeleteActionSet(OCResource **resource,
474         const char * actionsetName)
475 {
476     if (*resource != NULL)
477     {
478         OCActionSet *pointer = NULL;
479         OCActionSet *pDel = NULL;
480
481         pointer = (*resource)->actionsetHead;
482
483         if (pointer == NULL)
484         {
485             return OC_STACK_ERROR;
486         }
487         else
488         {
489             if (strcmp(pointer->actionsetName, actionsetName) == 0)
490             {
491                 if (pointer->next != NULL)
492                     (*resource)->actionsetHead = pointer->next;
493                 else
494                     (*resource)->actionsetHead = NULL;
495
496                 DeleteActionSet(&pointer);
497             }
498             else if (pointer->next != NULL)
499             {
500                 while (pointer)
501                 {
502                     if (pointer->next != NULL)
503                     {
504                         if (strcmp(pointer->next->actionsetName, actionsetName)
505                                 == 0)
506                         {
507                             pDel = pointer->next;
508                             pointer->next = pointer->next->next;
509
510                             DeleteActionSet(&pDel);
511                         }
512                     }
513                     pointer = pointer->next;
514                 }
515             }
516
517             return OC_STACK_OK;
518         }
519
520     }
521     return OC_STACK_ERROR;
522 }
523
524 OCStackResult GetActionSet(const char *actionName, OCActionSet *head,
525         OCActionSet** actionset)
526 {
527     OCActionSet *pointer = head;
528
529     while (pointer)
530     {
531         if (strcmp(pointer->actionsetName, actionName) == 0)
532         {
533             *actionset = pointer;
534             return OC_STACK_OK;
535         }
536
537         pointer = pointer->next;
538     }
539
540     return OC_STACK_ERROR;
541
542 }
543
544 OCStackResult ExtractKeyValueFromRequest(OCEntityHandlerRequest *ehRequest,
545                                         char **key, char **value)
546 {
547     OCStackResult result = OC_STACK_OK;
548
549     char *actionSetStr = NULL;
550
551     if( NULL == ehRequest->payload )
552     {
553         result = OC_STACK_ERROR;
554         goto exit;
555     }
556
557     OCRepPayload* input;
558
559     input = (OCRepPayload*)(ehRequest->payload);
560
561     if(OCRepPayloadGetPropString(input, ACTIONSET, &actionSetStr))
562     {
563         *key = OICStrdup(ACTIONSET);
564         VARIFY_POINTER_NULL(*key, result, exit);
565
566         *value = OICStrdup(actionSetStr);
567         VARIFY_POINTER_NULL(*value, result, exit);
568     }
569     else if(OCRepPayloadGetPropString(input, DO_ACTION, &actionSetStr))
570     {
571         *key = OICStrdup(DO_ACTION);
572         VARIFY_POINTER_NULL(*key, result, exit);
573
574         *value = OICStrdup(actionSetStr);
575         VARIFY_POINTER_NULL(*value, result, exit);
576     }
577     else if(OCRepPayloadGetPropString(input, GET_ACTIONSET, &actionSetStr))
578     {
579         *key = OICStrdup(GET_ACTIONSET);
580         VARIFY_POINTER_NULL(*key, result, exit);
581
582         *value = OICStrdup(actionSetStr);
583         VARIFY_POINTER_NULL(*value, result, exit);
584     }
585     else if(OCRepPayloadGetPropString(input, DELETE_ACTIONSET, &actionSetStr))
586     {
587         *key = OICStrdup(DELETE_ACTIONSET);
588         VARIFY_POINTER_NULL(*key, result, exit);
589
590         *value = OICStrdup(actionSetStr);
591         VARIFY_POINTER_NULL(*value, result, exit);
592     }
593     else if(OCRepPayloadGetPropString(input, CANCEL_ACTIONSET, &actionSetStr))
594     {
595         *key = OICStrdup(CANCEL_ACTIONSET);
596         VARIFY_POINTER_NULL(*key, result, exit);
597
598         *value = OICStrdup(actionSetStr);
599         VARIFY_POINTER_NULL(*value, result, exit);
600     }
601     else
602     {
603         result = OC_STACK_ERROR;
604     }
605
606 exit:
607     if (result != OC_STACK_OK)
608     {
609         OCFREE(*key)
610         OCFREE(*value)
611     }
612
613     OCFREE(actionSetStr);
614
615     return result;
616 }
617
618 OCStackResult ExtractActionSetNameAndDelaytime(char *pChar, char **setName,
619         long int *pa)
620 {
621     char *token = NULL, *tokenPtr = NULL;
622     OCStackResult result = OC_STACK_OK;
623
624     token = (char*) strtok_r(pChar, ACTION_DELIMITER, &tokenPtr);
625     VARIFY_POINTER_NULL(token, result, exit)
626
627     *setName = (char *) OICMalloc(strlen(token) + 1);
628     VARIFY_POINTER_NULL(*setName, result, exit)
629     VARIFY_PARAM_NULL(token, result, exit)
630     strncpy(*setName, token, strlen(token) + 1);
631
632     token = strtok_r(NULL, ACTION_DELIMITER, &tokenPtr);
633     VARIFY_POINTER_NULL(pa, result, exit)
634     VARIFY_PARAM_NULL(token, result, exit)
635     *pa = atoi(token);
636
637     return OC_STACK_OK;
638
639 exit:
640     OCFREE(*setName);
641     return result;
642 }
643
644 OCStackResult BuildActionSetFromString(OCActionSet **set, char* actiondesc)
645 {
646     OCStackResult result = OC_STACK_OK;
647
648     char *iterToken = NULL, *iterTokenPtr = NULL;
649     char *descIterToken = NULL, *descIterTokenPtr = NULL;
650     char *attrIterToken = NULL, *attrIterTokenPtr = NULL;
651     char *desc = NULL, *attr = NULL;
652     char *key = NULL, *value = NULL;
653
654     OCAction *action = NULL;
655     OCCapability *capa = NULL;
656
657     OIC_LOG(INFO, TAG, "Build ActionSet Instance.");
658
659     *set = (OCActionSet*) OICMalloc(sizeof(OCActionSet));
660     VARIFY_POINTER_NULL(*set, result, exit)
661
662     iterToken = (char *) strtok_r(actiondesc, ACTION_DELIMITER, &iterTokenPtr);
663     VARIFY_POINTER_NULL(iterToken, result, exit);
664
665     // ActionSet Name
666     memset(*set, 0, sizeof(OCActionSet));
667     (*set)->actionsetName = (char *) OICMalloc(strlen(iterToken) + 1);
668     VARIFY_POINTER_NULL((*set)->actionsetName, result, exit)
669     VARIFY_PARAM_NULL(iterToken, result, exit)
670     strncpy((*set)->actionsetName, iterToken, strlen(iterToken) + 1);
671
672     // Time info. for Scheduled/Recursive Group action.
673     // d is meant Day of the week.
674     // T is meant ActionType.
675     // yyyy-mm-dd hh:mm:ss d
676     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
677     VARIFY_PARAM_NULL(iterToken, result, exit)
678 #if !defined(WITH_ARDUINO)
679     if( 2 != sscanf(iterToken, "%ld %u", &(*set)->timesteps, &(*set)->type) )
680     {
681         // If the return value should be 2, the number of items in the argument. Otherwise, it fails.
682         goto exit;
683     }
684 #endif
685
686     OIC_LOG_V(INFO, TAG, "ActionSet Name : %s", (*set)->actionsetName);
687
688     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
689     while (iterToken)
690     {
691         desc = (char *) OICMalloc(strlen(iterToken) + 1);
692         VARIFY_POINTER_NULL(desc, result, exit)
693         VARIFY_PARAM_NULL(desc, result, exit)
694         strncpy(desc, iterToken, strlen(iterToken) + 1);
695         descIterToken = (char *) strtok_r(desc, ATTR_DELIMITER,
696                 &descIterTokenPtr);
697         while (descIterToken)
698         {
699             attr = (char *) OICMalloc(strlen(descIterToken) + 1);
700             VARIFY_POINTER_NULL(attr, result, exit)
701             VARIFY_PARAM_NULL(descIterToken, result, exit)
702             strncpy(attr, descIterToken, strlen(descIterToken) + 1);
703
704             attrIterToken = (char *) strtok_r(attr, ATTR_ASSIGN,
705                     &attrIterTokenPtr);
706             VARIFY_POINTER_NULL(attrIterToken, result, exit);
707
708             key = (char *) OICMalloc(strlen(attrIterToken) + 1);
709             VARIFY_POINTER_NULL(key, result, exit)
710             VARIFY_PARAM_NULL(attrIterToken, result, exit)
711             strncpy(key, attrIterToken, strlen(attrIterToken) + 1);
712
713             attrIterToken = (char *) strtok_r(NULL, ATTR_ASSIGN,
714                     &attrIterTokenPtr);
715             VARIFY_POINTER_NULL(attrIterToken, result, exit);
716             value = (char *) OICMalloc(strlen(attrIterToken) + 1);
717             VARIFY_POINTER_NULL(value, result, exit)
718             VARIFY_PARAM_NULL(attrIterToken, result, exit)
719             strncpy(value, attrIterToken, strlen(attrIterToken) + 1);
720
721             if (strcmp(key, "uri") == 0)
722             {
723                 OIC_LOG(INFO, TAG, "Build OCAction Instance.");
724
725                 action = (OCAction*) OICMalloc(sizeof(OCAction));
726                 VARIFY_POINTER_NULL(action, result, exit)
727                 memset(action, 0, sizeof(OCAction));
728                 action->resourceUri = (char *) OICMalloc(strlen(value) + 1);
729                 VARIFY_POINTER_NULL(action->resourceUri, result, exit)
730                 VARIFY_PARAM_NULL(value, result, exit)
731                 strncpy(action->resourceUri, value, strlen(value) + 1);
732             }
733             else
734             {
735                 if ((key != NULL) && (value != NULL))
736                 {
737                     OIC_LOG(INFO, TAG, "Build OCCapability Instance.");
738
739                     capa = (OCCapability*) OICMalloc(sizeof(OCCapability));
740                     VARIFY_POINTER_NULL(capa, result, exit)
741                     memset(capa, 0, sizeof(OCCapability));
742
743                     capa->capability = (char *) OICMalloc(strlen(key) + 1);
744                     VARIFY_POINTER_NULL(capa->capability, result, exit)
745                     VARIFY_PARAM_NULL(key, result, exit)
746                     strncpy(capa->capability, key, strlen(key) + 1);
747
748                     capa->status = (char *) OICMalloc(strlen(value) + 1);
749                     VARIFY_POINTER_NULL(capa->status, result, exit)
750                     VARIFY_PARAM_NULL(value, result, exit)
751                     strncpy(capa->status, value, strlen(value) + 1);
752
753                     VARIFY_POINTER_NULL(action, result, exit)
754
755                     AddCapability(&action->head, capa);
756                 }
757             }
758
759             OCFREE(key)
760             OCFREE(value)
761             OCFREE(attr)
762
763             descIterToken = (char *) strtok_r(NULL, ATTR_DELIMITER,
764                     &descIterTokenPtr);
765         }
766
767         AddAction(&(*set)->head, action);
768         iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
769         OCFREE(desc);
770     }
771
772     return OC_STACK_OK;
773 exit:
774     OCFREE(attr)
775     OCFREE(desc)
776     OCFREE(capa)
777     OCFREE(action)
778     OCFREE(*set)
779     OCFREE(key)
780     OCFREE(value)
781     OCFREE(attr)
782
783     return result;
784 }
785
786 OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc)
787 {
788     // Can't use the macros here as they are hardcoded to 'exit' and will
789     // result in dereferencing a null pointer.
790     if (!actionset || !desc)
791     {
792         return OC_STACK_INVALID_PARAM;
793     }
794     char temp[1024] = { 0 };
795     size_t remaining = sizeof(temp) - 1;
796     OCStackResult res = OC_STACK_ERROR;
797     char* actionTypeStr = NULL;
798
799     OCAction *action = actionset->head;
800
801     if (remaining >= strlen(actionset->actionsetName) + 1)
802     {
803         strncat(temp, actionset->actionsetName, strlen(actionset->actionsetName));
804         remaining -= strlen(actionset->actionsetName);
805         strncat(temp, ACTION_DELIMITER, strlen(ACTION_DELIMITER));
806         remaining--;
807     }
808     else
809     {
810         res = OC_STACK_ERROR;
811         goto exit;
812     }
813
814     actionTypeStr = (char *)OICMalloc(1024);
815     if(actionTypeStr != NULL)
816     {
817         sprintf(actionTypeStr, "%ld %u", actionset->timesteps, actionset->type);
818         if(remaining >= strlen(actionTypeStr) + strlen(ACTION_DELIMITER) + 1)
819         {
820             strncat(temp, actionTypeStr, strlen(actionTypeStr));
821             remaining -= strlen(actionTypeStr);
822             strncat(temp, ACTION_DELIMITER, strlen(ACTION_DELIMITER));
823             remaining -= strlen(ACTION_DELIMITER);
824             OICFree(actionTypeStr);
825         }
826         else
827         {
828             OICFree(actionTypeStr);
829             res = OC_STACK_ERROR;
830             goto exit;
831         }
832     }
833     else
834     {
835         res = OC_STACK_ERROR;
836         goto exit;
837     }
838
839     while (action != NULL)
840     {
841         if (remaining < (strlen("uri=") + strlen(action->resourceUri) + 1))
842         {
843             res = OC_STACK_ERROR;
844             goto exit;
845         }
846
847         strcat(temp, "uri=");
848         remaining -= strlen("uri=");
849         strcat(temp, action->resourceUri);
850         remaining -= strlen(action->resourceUri);
851         strcat(temp, "|");
852         remaining--;
853
854         OCCapability *capas = action->head;
855         while (capas != NULL)
856         {
857             if (remaining < (strlen(capas->capability)
858                              + 1 + strlen(capas->status)))
859             {
860                 res = OC_STACK_ERROR;
861                 goto exit;
862             }
863
864             strcat(temp, capas->capability);
865             remaining -= strlen(capas->capability);
866             strcat(temp, "=");
867             remaining--;
868             strcat(temp, capas->status);
869             remaining -= strlen(capas->status);
870
871             capas = capas->next;
872             if (capas != NULL)
873             {
874                 if (remaining < 1)
875                 {
876                     res = OC_STACK_ERROR;
877                     goto exit;
878                 }
879                 strcat(temp, "|");
880                 remaining --;
881             }
882         }
883
884         action = action->next;
885         if (action != NULL)
886         {
887             if (remaining < strlen(ACTION_DELIMITER))
888             {
889                 res = OC_STACK_ERROR;
890                 goto exit;
891             }
892             strcat(temp, ACTION_DELIMITER);
893             remaining--;
894         }
895     }
896
897     *desc = OICStrdup(temp);
898     VARIFY_POINTER_NULL(*desc, res, exit);
899
900     return OC_STACK_OK;
901
902 exit:
903     OCFREE(*desc);
904     return res;
905 }
906
907 OCStackApplicationResult ActionSetCB(void* context, OCDoHandle handle,
908         OCClientResponse* clientResponse)
909 {
910     (void)context;
911     (void)clientResponse;
912     OIC_LOG(INFO, TAG, "Entering ActionSetCB");
913
914     ClientRequestInfo *info = GetClientRequestInfo(clientRequstList, handle);
915
916     if (info)
917     {
918         OCEntityHandlerResponse response = { 0 };
919
920         response.ehResult = OC_EH_OK;
921
922         if(NULL == clientResponse->payload)
923         {
924             OIC_LOG(ERROR, TAG, "Error sending response");
925             return OC_STACK_DELETE_TRANSACTION;
926         }
927
928         // Format the response.  Note this requires some info about the request
929         response.requestHandle = info->ehRequest;
930         response.resourceHandle = info->collResource;
931         response.payload = clientResponse->payload;
932         response.numSendVendorSpecificHeaderOptions = 0;
933         memset(response.sendVendorSpecificHeaderOptions, 0,
934                 sizeof response.sendVendorSpecificHeaderOptions);
935         memset(response.resourceUri, 0, sizeof response.resourceUri);
936         // Indicate that response is NOT in a persistent buffer
937         response.persistentBufferFlag = 0;
938
939         // Send the response
940         if (OCDoResponse(&response) != OC_STACK_OK)
941         {
942             OIC_LOG(ERROR, TAG, "Error sending response");
943             return OC_STACK_DELETE_TRANSACTION;
944         }
945
946         RemoveClientRequestInfo(&clientRequstList, info);
947         OCFREE(info)
948     }
949
950     return OC_STACK_KEEP_TRANSACTION;
951 }
952
953 void ActionSetCD(void *context)
954 {
955     (void)context;
956 }
957
958 OCStackResult BuildActionJSON(OCAction* action, unsigned char* bufferPtr,
959         uint16_t *remaining)
960 {
961     OCStackResult ret = OC_STACK_ERROR;
962     cJSON *json;
963     cJSON *body;
964
965     char *jsonStr;
966     uint16_t jsonLen;
967
968     OIC_LOG(INFO, TAG, "Entering BuildActionJSON");
969     json = cJSON_CreateObject();
970
971     cJSON_AddItemToObject(json, "rep", body = cJSON_CreateObject());
972
973     OCCapability* pointerCapa = action->head;
974     while (pointerCapa)
975     {
976         cJSON_AddStringToObject(body, pointerCapa->capability,
977                 pointerCapa->status);
978         pointerCapa = pointerCapa->next;
979     }
980
981     jsonStr = cJSON_PrintUnformatted(json);
982
983     jsonLen = strlen(jsonStr);
984     if (jsonLen < *remaining)
985     {
986         strncat((char*) bufferPtr, jsonStr, jsonLen);
987         *remaining -= jsonLen;
988         bufferPtr += jsonLen;
989         ret = OC_STACK_OK;
990     }
991
992     cJSON_Delete(json);
993     free(jsonStr);
994
995     return ret;
996 }
997
998 OCPayload* BuildActionCBOR(OCAction* action)
999 {
1000     OCRepPayload* payload = OCRepPayloadCreate();
1001
1002     if (!payload)
1003     {
1004         OIC_LOG(INFO, TAG, "Failed to create put payload object");
1005         return NULL;
1006     }
1007
1008     OCCapability* pointerCapa = action->head;
1009     while (pointerCapa)
1010     {
1011         OCRepPayloadSetPropString(payload, pointerCapa->capability, pointerCapa->status);
1012         pointerCapa = pointerCapa->next;
1013     }
1014
1015     return (OCPayload*) payload;
1016 }
1017
1018 unsigned int GetNumOfTargetResource(OCAction *actionset)
1019 {
1020     int numOfResource = 0;
1021
1022     OCAction *pointerAction = actionset;
1023
1024     while (pointerAction != NULL)
1025     {
1026         numOfResource++;
1027         pointerAction = pointerAction->next;
1028     }
1029
1030     return numOfResource;
1031 }
1032
1033 OCStackResult SendAction(OCDoHandle *handle, OCServerRequest* requestHandle, const char *targetUri,
1034         OCPayload *payload)
1035 {
1036
1037     OCCallbackData cbData;
1038     cbData.cb = &ActionSetCB;
1039     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
1040     cbData.cd = NULL;
1041
1042     return OCDoResource(handle, OC_REST_PUT, targetUri, &requestHandle->devAddr,
1043                        payload, CT_ADAPTER_IP, OC_NA_QOS, &cbData, NULL, 0);
1044 }
1045
1046 OCStackResult DoAction(OCResource* resource, OCActionSet* actionset,
1047         OCServerRequest* requestHandle)
1048 {
1049     OCStackResult result = OC_STACK_ERROR;
1050
1051     if( NULL == actionset->head)
1052     {
1053         return result;
1054     }
1055
1056     OCAction *pointerAction = actionset->head;
1057
1058     while (pointerAction != NULL)
1059     {
1060         OCPayload* payload;
1061         payload = BuildActionCBOR(pointerAction);
1062
1063         if(payload == NULL)
1064         {
1065             return result;
1066         }
1067
1068         ClientRequestInfo *info = (ClientRequestInfo *) OICMalloc(
1069                 sizeof(ClientRequestInfo));
1070
1071         if( info == NULL )
1072         {
1073             OCFREE(payload);
1074             return OC_STACK_NO_MEMORY;
1075         }
1076
1077         memset(info, 0, sizeof(ClientRequestInfo));
1078
1079         info->collResource = resource;
1080         info->ehRequest = requestHandle;
1081
1082         result = SendAction(&info->required, info->ehRequest, pointerAction->resourceUri,
1083                 payload);
1084
1085         if (result != OC_STACK_OK)
1086         {
1087             OICFree(info);
1088             return result;
1089         }
1090
1091         AddClientRequestInfo(&clientRequstList, info);
1092
1093         pointerAction = pointerAction->next;
1094     }
1095
1096     return result;
1097 }
1098
1099 void DoScheduledGroupAction()
1100 {
1101     OIC_LOG(INFO, TAG, "DoScheduledGroupAction Entering...");
1102     ScheduledResourceInfo* info = GetScheduledResource(g_scheduleResourceList);
1103
1104     if (info == NULL)
1105     {
1106         OIC_LOG(INFO, TAG, "Target resource is NULL");
1107         goto exit;
1108     }
1109     else if (info->resource == NULL)
1110     {
1111         OIC_LOG(INFO, TAG, "Target resource is NULL");
1112         goto exit;
1113     }
1114     else if (info->actionset == NULL)
1115     {
1116         OIC_LOG(INFO, TAG, "Target ActionSet is NULL");
1117         goto exit;
1118     }
1119     else if (info->ehRequest == NULL)
1120     {
1121         OIC_LOG(INFO, TAG, "Target ActionSet is NULL");
1122         goto exit;
1123     }
1124
1125     MUTEX_LOCK(&g_scheduledResourceLock);
1126
1127     DoAction(info->resource, info->actionset, info->ehRequest);
1128
1129     MUTEX_UNLOCK(&g_scheduledResourceLock);
1130
1131
1132     if (info->actionset->type == RECURSIVE)
1133     {
1134         ScheduledResourceInfo *schedule;
1135         schedule = (ScheduledResourceInfo *) OICMalloc(
1136                 sizeof(ScheduledResourceInfo));
1137
1138         if (schedule)
1139         {
1140             OIC_LOG(INFO, TAG, "Building New Call Info.");
1141             memset(schedule, 0, sizeof(ScheduledResourceInfo));
1142
1143             if (info->actionset->timesteps > 0)
1144             {
1145                 MUTEX_LOCK(&g_scheduledResourceLock);
1146                 schedule->resource = info->resource;
1147                 schedule->actionset = info->actionset;
1148                 schedule->ehRequest = info->ehRequest;
1149
1150                 schedule->time = registerTimer(info->actionset->timesteps,
1151                         &schedule->timer_id,
1152                         &DoScheduledGroupAction);
1153
1154                 OIC_LOG(INFO, TAG, "Reregistration.");
1155                 MUTEX_UNLOCK(&g_scheduledResourceLock);
1156                 AddScheduledResource(&g_scheduleResourceList, schedule);
1157             }
1158             else
1159             {
1160                 OICFree(schedule);
1161             }
1162         }
1163     }
1164
1165     RemoveScheduledResource(&g_scheduleResourceList, info);
1166
1167     exit:
1168
1169     return;
1170 }
1171
1172 OCStackResult BuildCollectionGroupActionCBORResponse(
1173         OCMethod method/*OCEntityHandlerFlag flag*/, OCResource *resource,
1174         OCEntityHandlerRequest *ehRequest)
1175 {
1176     OCStackResult stackRet = OC_STACK_ERROR;
1177
1178     OIC_LOG(INFO, TAG, "Group Action is requested.");
1179
1180     char *doWhat = NULL;
1181     char *details = NULL;
1182
1183     stackRet = ExtractKeyValueFromRequest(ehRequest, &doWhat, &details);
1184
1185     if(stackRet != OC_STACK_OK)
1186     {
1187         OIC_LOG_V(ERROR, TAG, "ExtractKeyValueFromRequest failed: %d", stackRet);
1188         return stackRet;
1189     }
1190
1191     stackRet = OC_STACK_ERROR;
1192
1193     if (method == OC_REST_PUT)
1194     {
1195         OIC_LOG(INFO, TAG, "Group Action[PUT].");
1196
1197         if (strcmp(doWhat, ACTIONSET) == 0)
1198         {
1199             OCActionSet *actionSet = NULL;
1200             stackRet = BuildActionSetFromString(&actionSet, details);
1201
1202             if(stackRet == OC_STACK_OK)
1203             {
1204                 if (actionSet != NULL)
1205                 {
1206                     stackRet = AddActionSet(&resource->actionsetHead,
1207                             actionSet);
1208                     if (stackRet == OC_STACK_ERROR)
1209                     {
1210                         if(actionSet != NULL)
1211                         {
1212                             DeleteActionSet( &actionSet );
1213                         }
1214                         OIC_LOG(INFO, TAG, "Duplicated ActionSet ");
1215                     }
1216                 }
1217                 else
1218                 {
1219                     stackRet = OC_STACK_ERROR;
1220                     goto exit;
1221                 }
1222             }
1223             else
1224             {
1225                 stackRet = OC_STACK_ERROR;
1226             }
1227
1228         }
1229         else if (strcmp(doWhat, DELETE_ACTIONSET) == 0)
1230         {
1231             if (FindAndDeleteActionSet(&resource, details) == OC_STACK_OK)
1232             {
1233                 stackRet = OC_STACK_OK;
1234             }
1235             else
1236             {
1237                 stackRet = OC_STACK_ERROR;
1238             }
1239         }
1240
1241         OCRepPayload* payload = OCRepPayloadCreate();
1242
1243         if(!payload)
1244         {
1245             OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
1246             stackRet = OC_STACK_ERROR;
1247         }
1248         else
1249         {
1250             OCEntityHandlerResponse response = { 0 };
1251
1252             if(stackRet == OC_STACK_OK)
1253                 response.ehResult = OC_EH_OK;
1254             else
1255                 response.ehResult = OC_EH_ERROR;
1256
1257             // Format the response.  Note this requires some info about the request
1258             response.requestHandle = ehRequest->requestHandle;
1259             response.resourceHandle = ehRequest->resource;
1260             response.payload = (OCPayload*) payload;
1261             response.numSendVendorSpecificHeaderOptions = 0;
1262             memset(response.sendVendorSpecificHeaderOptions, 0,
1263                     sizeof response.sendVendorSpecificHeaderOptions);
1264             memset(response.resourceUri, 0, sizeof response. resourceUri);
1265             // Indicate that response is NOT in a persistent buffer
1266             response.persistentBufferFlag = 0;
1267             response.ehResult = (stackRet == OC_STACK_OK)?OC_EH_OK:OC_EH_ERROR;
1268
1269             // Send the response
1270             if (OCDoResponse(&response) != OC_STACK_OK)
1271             {
1272                 OIC_LOG(ERROR, TAG, "Error sending response");
1273                 stackRet = OC_STACK_ERROR;
1274             }
1275         }
1276     }
1277     else if (method == OC_REST_POST)
1278     {
1279         OCActionSet *actionset = NULL;
1280
1281         OCRepPayload* payload = OCRepPayloadCreate();
1282         OCRepPayloadSetUri(payload, resource->uri);
1283
1284         if ((strcmp(doWhat, DO_ACTION) == 0)
1285                 || (strcmp(doWhat, "DoScheduledAction") == 0))
1286         {
1287             char *pActionsetName = NULL;
1288             long int delay = -1;
1289
1290             if (strcmp(doWhat, "DoScheduledAction") == 0)
1291             {
1292                 stackRet = ExtractActionSetNameAndDelaytime(details,
1293                         &pActionsetName, &delay);
1294
1295                 OCFREE(details)
1296                 details = pActionsetName;
1297             }
1298             else
1299             {
1300                 stackRet = OC_STACK_OK;
1301             }
1302
1303             if (stackRet == OC_STACK_OK)
1304             {
1305                 if (GetActionSet(details, resource->actionsetHead,
1306                         &actionset) != OC_STACK_OK)
1307                 {
1308                     OIC_LOG(INFO, TAG, "ERROR");
1309                     stackRet = OC_STACK_ERROR;
1310                 }
1311
1312                 if (actionset == NULL)
1313                 {
1314                     OIC_LOG(INFO, TAG, "Cannot Find ActionSet");
1315                     stackRet = OC_STACK_ERROR;
1316                 }
1317                 else
1318                 {
1319                     OIC_LOG(INFO, TAG, "Group Action[POST].");
1320                     if (actionset->type == NONE)
1321                     {
1322                         OIC_LOG_V(INFO, TAG, "Execute ActionSet : %s",
1323                                 actionset->actionsetName);
1324                         unsigned int num = GetNumOfTargetResource(
1325                                 actionset->head);
1326
1327                         ((OCServerRequest *) ehRequest->requestHandle)->ehResponseHandler =
1328                                 HandleAggregateResponse;
1329                         ((OCServerRequest *) ehRequest->requestHandle)->numResponses =
1330                                 num + 1;
1331
1332                         DoAction(resource, actionset,
1333                                 (OCServerRequest*) ehRequest->requestHandle);
1334                         stackRet = OC_STACK_OK;
1335                     }
1336                     else
1337                     {
1338                         OIC_LOG_V(INFO, TAG, "Execute Scheduled ActionSet : %s",
1339                                 actionset->actionsetName);
1340
1341                         delay =
1342                                 (delay == -1 ? actionset->timesteps : delay);
1343
1344                         ScheduledResourceInfo *schedule;
1345                         schedule = (ScheduledResourceInfo *) OICMalloc(
1346                                 sizeof(ScheduledResourceInfo));
1347
1348                         if (schedule)
1349                         {
1350                             OIC_LOG(INFO, TAG, "Building New Call Info.");
1351                             memset(schedule, 0,
1352                                     sizeof(ScheduledResourceInfo));
1353                             MUTEX_LOCK(&g_scheduledResourceLock);
1354                             schedule->resource = resource;
1355                             schedule->actionset = actionset;
1356                             schedule->ehRequest =
1357                                     (OCServerRequest*) ehRequest->requestHandle;
1358                             MUTEX_UNLOCK(&g_scheduledResourceLock);
1359                             if (delay > 0)
1360                             {
1361                                 OIC_LOG_V(INFO, TAG, "delay_time is %ld seconds.",
1362                                         actionset->timesteps);
1363                                 MUTEX_LOCK(&g_scheduledResourceLock);
1364                                 schedule->time = registerTimer(delay,
1365                                         &schedule->timer_id,
1366                                         &DoScheduledGroupAction);
1367                                 MUTEX_UNLOCK(&g_scheduledResourceLock);
1368                                 AddScheduledResource(&g_scheduleResourceList,
1369                                         schedule);
1370                                 stackRet = OC_STACK_OK;
1371                             }
1372                             else
1373                             {
1374                                 stackRet = OC_STACK_ERROR;
1375                             }
1376                         }
1377                     }
1378                 }
1379             }
1380         }
1381         else if (strcmp(doWhat, "CancelAction") == 0)
1382         {
1383             ScheduledResourceInfo *info =
1384                     GetScheduledResourceByActionSetName(g_scheduleResourceList, details);
1385
1386             if(info != NULL)
1387             {
1388                 MUTEX_LOCK(&g_scheduledResourceLock);
1389                 unregisterTimer(info->timer_id);
1390                 MUTEX_UNLOCK(&g_scheduledResourceLock);
1391
1392                 RemoveScheduledResource(&g_scheduleResourceList, info);
1393                 stackRet = OC_STACK_OK;
1394             }
1395             else
1396             {
1397                 stackRet = OC_STACK_ERROR;
1398             }
1399         }
1400
1401         else if (strcmp(doWhat, GET_ACTIONSET) == 0)
1402         {
1403             char *plainText = NULL;
1404             OCActionSet *actionset = NULL;
1405
1406             GetActionSet(details, resource->actionsetHead, &actionset);
1407             if (actionset != NULL)
1408             {
1409                 BuildStringFromActionSet(actionset, &plainText);
1410
1411                 if (plainText != NULL)
1412                 {
1413                     OCRepPayloadSetPropString(payload, ACTIONSET, plainText);
1414                 }
1415                 OICFree(plainText);
1416                 stackRet = OC_STACK_OK;
1417             }
1418         }
1419
1420         if(!payload)
1421         {
1422             OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
1423             stackRet = OC_STACK_ERROR;
1424         }
1425         else
1426         {
1427             OCEntityHandlerResponse response = { 0 };
1428             if(stackRet == OC_STACK_OK)
1429                 response.ehResult = OC_EH_OK;
1430             else
1431                 response.ehResult = OC_EH_ERROR;
1432
1433             // Format the response.  Note this requires some info about the request
1434             response.requestHandle = ehRequest->requestHandle;
1435             response.resourceHandle = ehRequest->resource;
1436             response.payload = (OCPayload*) payload;
1437             response.numSendVendorSpecificHeaderOptions = 0;
1438             memset(response.sendVendorSpecificHeaderOptions, 0,
1439                     sizeof response.sendVendorSpecificHeaderOptions);
1440             memset(response.resourceUri, 0, sizeof response.resourceUri);
1441             // Indicate that response is NOT in a persistent buffer
1442             response.persistentBufferFlag = 0;
1443             response.ehResult = (stackRet == OC_STACK_OK)?OC_EH_OK:OC_EH_ERROR;
1444
1445             // Send the response
1446             if (OCDoResponse(&response) != OC_STACK_OK)
1447             {
1448                 OIC_LOG(ERROR, TAG, "Error sending response");
1449                 stackRet = OC_STACK_ERROR;
1450             }
1451         }
1452     }
1453
1454 exit:
1455
1456     OCFREE(doWhat)
1457     OCFREE(details)
1458
1459     return stackRet;
1460 }
1461
1462 OCStackResult InitializeScheduleResourceList()
1463 {
1464     MUTEX_INITIALIZE(&g_scheduledResourceLock);
1465
1466     g_scheduleResourceList = NULL;
1467     return OC_STACK_OK;
1468 }
1469
1470 void TerminateScheduleResourceList()
1471 {
1472     assert(g_scheduleResourceList == NULL);
1473
1474     MUTEX_TERMINATE(&g_scheduledResourceLock);
1475 }