1 //******************************************************************
3 // Copyright 2014 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 // Defining _POSIX_C_SOURCE macro with 200112L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1-2001 base
24 // specification (excluding the XSI extension).
25 // For POSIX.1-2001 base specification,
26 // Refer http://pubs.opengroup.org/onlinepubs/009695399/
27 #define _POSIX_C_SOURCE 200112L
33 #include "ocresource.h"
34 #include "occollection.h"
37 #define TAG PCF("OICGROUP")
39 #define DESC_DELIMITER "\""
40 #define ACTION_DELIMITER "*"
41 #define ATTR_DELIMITER "|"
42 #define ATTR_ASSIGN "="
44 // Definitions for operations related to actions
45 #define DO_ACTION "DoAction"
46 #define GET_ACTIONSET "GetActionSet"
47 #define ACTIONSET "ActionSet"
48 #define DELETE_ACTIONSET "DelActionSet"
50 typedef struct aggregatehandleinfo
52 OCServerRequest *ehRequest;
54 OCResource *collResource;
56 struct aggregatehandleinfo *next;
59 static ClientRequestInfo *clientRequestList = NULL;
61 void AddClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* add)
63 ClientRequestInfo *tmp = NULL;
81 ClientRequestInfo* GetClientRequestInfo(ClientRequestInfo *head, OCDoHandle handle)
83 ClientRequestInfo *tmp = NULL;
91 if (tmp->required == handle)
104 void RemoveClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* del)
106 ClientRequestInfo *tmp = NULL;
110 *head = (*head)->next;
115 while (tmp->next && (tmp->next != del))
121 tmp->next = del->next;
126 void AddCapability(OCCapability** head, OCCapability* node)
128 OCCapability *pointer = *head;
135 while (pointer->next != NULL)
137 pointer = pointer->next;
140 pointer->next = node;
144 void AddAction(OCAction** head, OCAction* node)
146 OCAction *pointer = *head;
154 while (pointer->next != NULL)
156 pointer = pointer->next;
159 pointer->next = node;
163 void AddActionSet(OCActionSet **head, OCActionSet* node)
165 OCActionSet *pointer = *head;
173 while (pointer->next != NULL)
175 pointer = pointer->next;
178 pointer->next = node;
182 void DeleteCapability(OCCapability *del)
184 OCFree(del->capability);
185 del->capability = NULL;
190 void DeleteAction(OCAction** action)
192 OCCapability* pointer = (*action)->head;
193 OCCapability* pDel = NULL;
198 pointer = pointer->next;
200 DeleteCapability(pDel);
203 OCFree((*action)->resourceUri);
204 (*action)->resourceUri = NULL;
205 (*action)->next = NULL;
208 void DeleteActionSet(OCActionSet** actionset)
210 OCAction* pointer = (*actionset)->head;
211 OCAction* pDel = NULL;
216 pointer = pointer->next;
222 OCFree((*actionset)->actionsetName);
223 (*actionset)->head = NULL;
226 OCStackResult FindAndDeleteActionSet(OCResource **resource, const char * actionsetName)
228 if (*resource != NULL)
230 OCActionSet *pointer = NULL;
231 OCActionSet *pDel = NULL;
233 pointer = (*resource)->actionsetHead;
237 return OC_STACK_ERROR;
241 if (strcmp(pointer->actionsetName, actionsetName) == 0)
243 if (pointer->next != NULL)
244 (*resource)->actionsetHead = pointer->next;
246 (*resource)->actionsetHead = NULL;
247 DeleteActionSet(&pointer);
249 else if (pointer->next != NULL)
253 if (pointer->next != NULL)
255 if (strcmp(pointer->next->actionsetName, actionsetName) == 0)
257 pDel = pointer->next;
258 pointer->next = pointer->next->next;
260 DeleteActionSet(&pDel);
263 pointer = pointer->next;
271 return OC_STACK_ERROR;
274 OCStackResult DeleteActionSets(OCResource** resource)
276 OCActionSet *pointer = (*resource)->actionsetHead;
277 OCActionSet *pDel = pointer;
282 pointer = pointer->next;
284 DeleteActionSet(&pDel);
288 (*resource)->actionsetHead = NULL;
292 OCStackResult GetActionSet(const char *actionName, OCActionSet *head, OCActionSet** actionset)
294 OCActionSet *pointer = head;
298 if (strcmp(pointer->actionsetName, actionName) == 0)
300 *actionset = pointer;
304 pointer = pointer->next;
307 return OC_STACK_ERROR;
312 #define OIC_ACTION_PREFIX "{\"oc\":[{\"rep\":{"
313 #define VARIFY_POINTER_NULL(pointer, result, toExit) \
314 if(pointer == NULL) \
316 result = OC_STACK_NO_MEMORY;\
319 #define VARIFY_PARAM_NULL(pointer, result, toExit) \
322 result = OC_STACK_INVALID_PARAM;\
326 OCStackResult ExtractKeyValueFromRequest(char *request, char **key, char **value)
328 OCStackResult result = OC_STACK_OK;
331 if(strlen(request) <= strlen(OIC_ACTION_PREFIX))
333 return OC_STACK_INVALID_PARAM;
336 char* pRequest = (char *)request + strlen(OIC_ACTION_PREFIX);
337 char* iterToken = NULL;
338 char* iterTokenPtr = NULL;
340 iterToken = (char *) strtok_r(pRequest, ":", &iterTokenPtr);
341 length = strlen(iterToken) + 1;
343 *key = (char *)OCMalloc(length);
344 VARIFY_POINTER_NULL(*key, result, exit);
346 strncpy(*key, iterToken + 1, length);
347 ((*key)[ (( length - 1 ) - 2) ]) = '\0';
349 iterToken = (char *) strtok_r(NULL, "}", &iterTokenPtr);
350 length = strlen(iterToken) + 1;
352 *value = (char *)OCMalloc(length);
353 VARIFY_POINTER_NULL(*key, result, exit);
355 strncpy(*value, iterToken + 1, length);
356 ((*value)[ (( length - 1 ) - 2) ]) = '\0';
358 if(result != OC_STACK_OK)
369 OCStackResult BuildActionSetFromString(OCActionSet **set, char* actiondesc)
371 OCStackResult result = OC_STACK_OK;
373 char *iterToken = NULL, *iterTokenPtr = NULL;
374 char *descIterToken = NULL;
375 char *descIterTokenPtr = NULL;
376 char *attrIterToken = NULL;
377 char *attrIterTokenPtr = NULL;
383 OCAction *action = NULL;
384 OCCapability *capa = NULL;
386 OC_LOG(INFO, TAG, PCF("Build ActionSet Instance."));
388 *set = (OCActionSet*) OCMalloc(sizeof(OCActionSet));
389 VARIFY_POINTER_NULL(*set, result, exit)
391 iterToken = (char *) strtok_r(actiondesc, ACTION_DELIMITER, &iterTokenPtr);
393 memset(*set, 0, sizeof(OCActionSet));
394 (*set)->actionsetName = (char *)OCMalloc(sizeof(OCActionSet));
395 VARIFY_POINTER_NULL((*set)->actionsetName, result, exit)
396 VARIFY_PARAM_NULL(iterToken, result, exit)
397 strncpy((*set)->actionsetName, iterToken, strlen(iterToken) + 1);
399 OC_LOG_V(INFO, TAG, "ActionSet Name : %s", (*set)->actionsetName);
401 iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
404 desc = (char *)OCMalloc(strlen(iterToken) + 1);
405 strncpy(desc, iterToken, strlen(iterToken) + 1);
406 descIterToken = (char *) strtok_r(desc, ATTR_DELIMITER, &descIterTokenPtr);
409 attr = (char *)OCMalloc(strlen(descIterToken) + 1);
410 strncpy(attr, descIterToken, strlen(descIterToken) + 1);
412 attrIterToken = (char *) strtok_r(attr, ATTR_ASSIGN, &attrIterTokenPtr);
413 key = (char *)OCMalloc(strlen(attrIterToken) + 1);
414 VARIFY_POINTER_NULL(key, result, exit)
416 VARIFY_PARAM_NULL(attrIterToken, result, exit)
417 strncpy(key, attrIterToken, strlen(attrIterToken) + 1);
418 attrIterToken = (char *) strtok_r(NULL, ATTR_ASSIGN, &attrIterTokenPtr);
420 value = (char *)OCMalloc(strlen(attrIterToken) + 1);
421 VARIFY_POINTER_NULL(value, result, exit)
422 VARIFY_PARAM_NULL(attrIterToken, result, exit)
423 strncpy(value, attrIterToken, strlen(attrIterToken) + 1);
425 if(strncmp(key, "uri", sizeof("uri") - 1) == 0)
427 OC_LOG(INFO, TAG, PCF("Build OCAction Instance."));
429 action = (OCAction*)OCMalloc(sizeof(OCAction));
430 VARIFY_POINTER_NULL(action, result, exit)
431 memset(action, 0, sizeof(OCAction));
432 action->resourceUri = (char *)OCMalloc(strlen(value) + 1);
433 VARIFY_POINTER_NULL(action->resourceUri, result, exit)
434 VARIFY_PARAM_NULL(value, result, exit)
435 strncpy(action->resourceUri, value, strlen(value) + 1);
439 if( (key != NULL) && (value != NULL))
441 OC_LOG(INFO, TAG, PCF("Build OCCapability Instance."));
442 capa = (OCCapability*)OCMalloc(sizeof(OCCapability));
443 VARIFY_POINTER_NULL(capa, result, exit)
444 memset(capa, 0, sizeof(OCCapability));
445 capa->capability = (char *)OCMalloc(strlen(key) + 1);
446 capa->status = (char *)OCMalloc(strlen(value) + 1);
448 strncpy(capa->capability, key, strlen(key) + 1);
449 strncpy(capa->status, value, strlen(value) + 1);
451 VARIFY_POINTER_NULL(action, result, exit)
453 AddCapability(&action->head, capa);
461 descIterToken = (char *) strtok_r(NULL, ATTR_DELIMITER, &descIterTokenPtr);
464 AddAction(&(*set)->head, action);
465 iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
480 OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc)
482 char temp[1024] = { 0 };
483 uint16_t remaining = sizeof(temp) - 1;
485 OCAction *action = actionset->head;
487 if (remaining >= strlen(actionset->actionsetName) + (sizeof(ACTION_DELIMITER)-1) )
489 strncat(temp, actionset->actionsetName, remaining);
490 remaining -= strlen(actionset->actionsetName);
491 strcat(temp, ACTION_DELIMITER);
492 remaining -= (sizeof(ACTION_DELIMITER)-1);
496 return OC_STACK_ERROR;
499 while (action != NULL)
501 OC_LOG_V(INFO, TAG, "\tURI :: %s\n", action->resourceUri);
502 strcat(temp, "uri=");
503 remaining -= strlen("uri=");
504 strcat(temp, action->resourceUri);
505 remaining -= strlen(action->resourceUri);
506 strcat(temp, ATTR_DELIMITER);
509 OCCapability *capas = action->head;
510 while (capas != NULL)
512 OC_LOG_V(INFO, TAG, "\t\t%s = %s\n", capas->capability, capas->status);
513 strcat(temp, capas->capability);
514 remaining -= strlen(capas->capability);
515 strcat(temp, ATTR_ASSIGN);
517 strcat(temp, capas->status);
518 remaining -= strlen(capas->capability);
523 strcat(temp, ATTR_DELIMITER);
527 action = action->next;
530 strcat(temp, ACTION_DELIMITER);
535 *desc = (char *) OCMalloc(1024 - remaining);
538 return OC_STACK_NO_MEMORY;
546 OCStackApplicationResult ActionSetCB(void* context, OCDoHandle handle,
547 OCClientResponse* clientResponse)
549 OC_LOG(INFO, TAG, PCF("\n\n\tcallback is called\n\n"));
551 ClientRequestInfo *info = GetClientRequestInfo(clientRequestList, handle);
557 char *responseJson = (char *) OCMalloc(
558 (unsigned int) (strlen( clientResponse->resJSONPayload) + 1));
560 // We need the body of response.
561 // Copy the body from the response
562 strncpy((char *) responseJson, (clientResponse->resJSONPayload
563 + OC_JSON_PREFIX_LEN), strlen(clientResponse->resJSONPayload) + 1);
564 idx = strlen((char *) responseJson) - OC_JSON_SUFFIX_LEN;
565 // And insert NULL at the end of body.
566 (responseJson[idx]) = 0;
568 OCEntityHandlerResponse response = { };
569 response.ehResult = OC_EH_OK;
570 response.payload = responseJson;
571 response.payloadSize = (unsigned int) strlen((char *) responseJson) + 1;
572 response.persistentBufferFlag = 0;
573 response.requestHandle = (OCRequestHandle) info->ehRequest;
574 response.resourceHandle = (OCResourceHandle) info->collResource;
576 OCDoResponse(&response);
578 RemoveClientRequestInfo(&clientRequestList, info);
579 OCFree(responseJson);
582 return OC_STACK_KEEP_TRANSACTION;
585 void ActionSetCD(void *context)
589 OCStackResult BuildActionJSON(OCAction* action, char* bufferPtr, uint16_t *remaining)
591 OCStackResult ret = OC_STACK_ERROR;
595 char *jsonStr = NULL;
596 uint16_t jsonLen = 0;
598 OC_LOG(INFO, TAG, PCF("Entering BuildActionJSON"));
599 json = cJSON_CreateObject();
601 cJSON_AddItemToObject(json, OC_RSRVD_REPRESENTATION, body = cJSON_CreateObject());
603 OCCapability* pointerCapa = action->head;
606 cJSON_AddStringToObject(body, pointerCapa->capability, pointerCapa->status);
607 pointerCapa = pointerCapa->next;
610 jsonStr = cJSON_PrintUnformatted(json);
612 jsonLen = strlen(jsonStr);
613 if (jsonLen < *remaining)
615 strcat((char*) bufferPtr, jsonStr);
616 *remaining -= jsonLen;
617 bufferPtr += jsonLen;
627 uint32_t GetNumOfTargetResource(OCAction *actionset)
629 uint32_t numOfResource = 0;
631 OCAction *pointerAction = actionset;
633 while (pointerAction != NULL)
636 pointerAction = pointerAction->next;
639 return numOfResource;
642 OCStackResult SendAction(OCDoHandle *handle, const char *targetUri, const char *action)
644 OCCallbackData cbdata = { };
645 cbdata.cb = &ActionSetCB;
646 cbdata.cd = &ActionSetCD;
647 cbdata.context = (void *) 0x99;
649 return OCDoResource(handle, OC_REST_PUT, targetUri,
650 //temp->rsrcType->resourcetypename,
651 NULL, (char *) action, OC_WIFI, OC_NA_QOS, &cbdata, NULL, 0);
654 OCStackResult BuildCollectionGroupActionJSONResponse(OCMethod method/*OCEntityHandlerFlag flag*/,
655 OCResource *resource, OCEntityHandlerRequest *ehRequest)
657 OCStackResult stackRet = OC_STACK_ERROR;
659 OC_LOG(INFO, TAG, PCF("Group Action is requested."));
661 char *details = NULL;
663 size_t bufferLength = 0;
664 char buffer[MAX_RESPONSE_LENGTH] = { 0 };
665 char *bufferPtr = NULL;
669 OCResource * collResource = (OCResource *) ehRequest->resource;
673 stackRet = ExtractKeyValueFromRequest((char *)ehRequest->reqJSONPayload, &doWhat, &details);
675 if (stackRet != OC_STACK_OK)
684 if (method == OC_REST_PUT)
686 json = cJSON_CreateObject();
687 cJSON_AddStringToObject(json, OC_RSRVD_HREF, resource->uri);
688 cJSON_AddItemToObject(json, OC_RSRVD_REPRESENTATION, format = cJSON_CreateObject());
690 OC_LOG(INFO, TAG, PCF("Group Action[PUT]."));
692 if(strcmp(doWhat, ACTIONSET) == 0)
694 OCActionSet *actionSet;
695 BuildActionSetFromString(&actionSet, details);
697 if(actionSet != NULL)
699 AddActionSet(&resource->actionsetHead, actionSet);
700 stackRet = OC_STACK_OK;
704 stackRet = OC_STACK_ERROR;
708 else if (strncmp(doWhat, DELETE_ACTIONSET, sizeof(DELETE_ACTIONSET)) == 0)
710 if (FindAndDeleteActionSet(&resource, details) == OC_STACK_OK)
712 stackRet = OC_STACK_OK;
716 stackRet = OC_STACK_ERROR;
720 jsonResponse = cJSON_Print(json);
723 strcat((char *) bufferPtr, jsonResponse);
725 bufferLength = strlen((const char *) buffer);
726 if (bufferLength > 0)
728 OCEntityHandlerResponse response = { 0 };
729 response.ehResult = OC_EH_OK;
730 response.payload = buffer;
731 response.payloadSize = bufferLength + 1;
732 response.persistentBufferFlag = 0;
733 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
734 response.resourceHandle = (OCResourceHandle) collResource;
735 stackRet = OCDoResponse(&response);
738 stackRet = OC_STACK_OK;
741 if (method == OC_REST_POST)
743 OC_LOG(INFO, TAG, PCF("Group Action[POST]."));
745 OCActionSet *actionset = NULL;
747 json = cJSON_CreateObject();
748 cJSON_AddStringToObject(json, OC_RSRVD_HREF, resource->uri);
750 if (strcmp(doWhat, DO_ACTION) == 0)
752 if (GetActionSet(details, resource->actionsetHead, &actionset) != OC_STACK_OK)
754 OC_LOG(ERROR, TAG, PCF("ERROR: GetActionSet failed"));
755 stackRet = OC_STACK_ERROR;
758 if (actionset == NULL)
760 OC_LOG(ERROR, TAG, PCF("ERROR: Actionset is NULL"));
761 stackRet = OC_STACK_ERROR;
766 OCAction *pointerAction = actionset->head;
768 uint32_t num = GetNumOfTargetResource(pointerAction);
770 ((OCServerRequest *) ehRequest->requestHandle)->ehResponseHandler =
771 HandleAggregateResponse;
772 ((OCServerRequest *) ehRequest->requestHandle)->numResponses = num + 1;
774 while (pointerAction != NULL)
776 char actionDesc[MAX_RESPONSE_LENGTH] = { 0 };
777 char* actionDescPtr = actionDesc;
778 uint16_t remaining = MAX_RESPONSE_LENGTH;
780 strncpy((char *) actionDescPtr, (const char *) OC_JSON_PREFIX,
781 strlen((const char *) OC_JSON_PREFIX) + 1);
782 BuildActionJSON(pointerAction, actionDescPtr, &remaining);
783 strncat((char *) actionDescPtr, (const char *) OC_JSON_SUFFIX,
784 strlen((const char *) OC_JSON_SUFFIX));
786 ClientRequestInfo *info = (ClientRequestInfo *) OCMalloc(
787 sizeof(ClientRequestInfo));
788 memset(info, 0, sizeof(ClientRequestInfo));
790 info->collResource = resource;
791 info->ehRequest = (OCServerRequest *) ehRequest->requestHandle;
793 SendAction(&info->required, pointerAction->resourceUri, actionDescPtr);
795 AddClientRequestInfo(&clientRequestList, info);
797 pointerAction = pointerAction->next;
801 stackRet = OC_STACK_OK;
804 else if (strcmp(doWhat, GET_ACTIONSET) == 0)
806 char *plainText = NULL;
807 OCActionSet *actionset = NULL;
809 cJSON_AddItemToObject(json, OC_RSRVD_REPRESENTATION, format = cJSON_CreateObject());
810 GetActionSet(details, resource->actionsetHead, &actionset);
811 if (actionset != NULL)
813 BuildStringFromActionSet(actionset, &plainText);
815 if (plainText != NULL)
817 cJSON_AddStringToObject(format, ACTIONSET, plainText);
820 stackRet = OC_STACK_OK;
824 jsonResponse = cJSON_Print(json);
827 strcat((char *) bufferPtr, jsonResponse);
829 bufferLength = strlen((const char *) buffer);
830 if (bufferLength > 0)
832 OCEntityHandlerResponse response = {};
833 response.ehResult = OC_EH_OK;
834 response.payload = buffer;
835 response.payloadSize = bufferLength + 1;
836 response.persistentBufferFlag = 0;
837 response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
838 response.resourceHandle = (OCResourceHandle) collResource;
839 stackRet = OCDoResponse(&response);