static AwaError ClientSubscribeOperation_Add(AwaClientSubscribeOperation * operation, AwaClientSubscription * subscription, bool cancel) { AwaError result = AwaError_Unspecified; if (operation != NULL) { if (subscription != NULL) { AwaClientSubscription * existingSubscription = NULL; Map_Get(operation->Subscribers, subscription->Path, (void **)&existingSubscription); if (existingSubscription == NULL) { if (Map_Put(operation->Subscribers, subscription->Path, subscription)) { List_Add(subscription->Operations, operation); subscription->Cancel = cancel; result = AwaError_Success; } else { result = LogErrorWithEnum(AwaError_Internal, "Failed to add subscription to operation"); } } else { result = LogErrorWithEnum(AwaError_OperationInvalid, "A subscription already exists for path %s in the given operation.", subscription->Path); } } else { result = LogErrorWithEnum(AwaError_SubscriptionInvalid, "Subscription is NULL"); } } else { result = LogErrorWithEnum(AwaError_OperationInvalid, "Operation is NULL"); } return result; }
static void ClientSubscribe_PerformSuccessfulCallback(const char * path, void * value, void * context) { AwaClientSubscription * subscription = (AwaClientSubscription *)value; PerformSuccessfulCallbackContext * successContext = (PerformSuccessfulCallbackContext *)context; const AwaPathResult * result = AwaClientSubscribeResponse_GetPathResult(successContext->Response, subscription->Path); if (!subscription->Cancel) { if (AwaPathResult_GetError(result) == AwaError_Success) { Map_Put(ClientSession_GetSubscribers(successContext->Session), subscription->Path, subscription); // map the subscription to this session. subscription->Session = successContext->Session; } else { LogErrorWithEnum(AwaPathResult_GetError(result), "Failed to subscribe to path %s\n", subscription->Path); successContext->Result = AwaError_Response; } } }
// TODO: is maintaining a separate ClientResponseMap unnecessary? Can the ServerResponse's own Map be used instead? const AwaServerListClientsResponse * AwaServerListClientsOperation_GetResponse(const AwaServerListClientsOperation * operation, const char * clientID) { AwaServerListClientsResponse * listClientsResponse = NULL; if (operation != NULL) { if (clientID != NULL) { if (operation->ServerResponse != NULL) { // check that client response exists: const ResponseCommon * clientResponse = ServerResponse_GetClientResponse(operation->ServerResponse, clientID); if (clientResponse != NULL) { // look up existing Response in map, return it. // if it doesn't exist, create new Response and add to map, return it. Map_Get(operation->ClientResponseMap, clientID, (void *)&listClientsResponse); if (listClientsResponse == NULL) { LogDebug("Create new AwaServerListClientsResponse"); listClientsResponse = Awa_MemAlloc(sizeof(*listClientsResponse)); if (listClientsResponse != NULL) { memset(listClientsResponse, 0, sizeof(*listClientsResponse)); listClientsResponse->Response = clientResponse; // cache the listClientsResponse if (Map_Put(operation->ClientResponseMap, clientID, (void *)listClientsResponse) == false) { // do not return the response if we can't retain it, as it will eventually leak LogErrorWithEnum(AwaError_Internal, "Map put failed"); Awa_MemSafeFree(listClientsResponse); listClientsResponse = NULL; } } else { LogErrorWithEnum(AwaError_OutOfMemory); } } else { LogDebug("Retrieved cached AwaServerListClientsResponse"); } } else { LogErrorWithEnum(AwaError_ClientNotFound, "Client ID %s not found", clientID); } } else { LogErrorWithEnum(AwaError_ResponseInvalid, "operation response is NULL"); } } else { LogErrorWithEnum(AwaError_ClientIDInvalid, "clientID is NULL"); } } else { LogErrorWithEnum(AwaError_OperationInvalid, "operation is NULL"); } return listClientsResponse; }
AwaError GetValuePointer(const ResponseCommon * response, const char * path, const void ** value, size_t * valueSize, AwaResourceType resourceType, int resourceSize, bool withNull) { AwaError result = AwaError_Unspecified; if (path != NULL) { if (Path_IsValidForResource(path)) { if (response != NULL) { if (value != NULL) { const Value * storedValue = ResponseCommon_GetValue(response, path); if (storedValue != NULL) { AwaResourceType type = Value_GetType(storedValue); if (type == resourceType || (type == AwaResourceType_None && resourceType == AwaResourceType_Opaque /* Execute arguments payload */)) { const void * data = Value_GetData(storedValue); size_t length = Value_GetLength(storedValue); // -1 used for e.g. string values as we can't know how long they are without reading them first if (resourceSize != -1 && length != resourceSize) { result = LogErrorWithEnum(AwaError_Internal, "Unexpected length for %s value: %zu expects %d", Utils_ResourceTypeToString(resourceType), length, resourceSize); } else { if (withNull) { char * nulledValue = (char *)malloc(length+1); if ((nulledValue != NULL)) { memcpy(nulledValue, data, length); nulledValue[length] = '\0'; if (valueSize != NULL) { *valueSize = length + 1; } Map_Put(response->NulledValues, path, nulledValue); *value = nulledValue; result = AwaError_Success; } else { result = LogErrorWithEnum(AwaError_OutOfMemory); } } else { *value = (length > 0) ? data : NULL; if (valueSize != NULL) { *valueSize = length; } result = AwaError_Success; } } } else { result = LogErrorWithEnum(AwaError_TypeMismatch, "Resource %s is not of type %s", path, Utils_ResourceTypeToString(resourceType)); } } else { // no value stored for this path result = LogErrorWithEnum(AwaError_PathNotFound, "No value for path %s", path); } } else { result = LogErrorWithEnum(AwaError_OperationInvalid, "Value is null"); } } else { result = LogErrorWithEnum(AwaError_OperationInvalid, "Invalid Get Response"); } } else { result = LogErrorWithEnum(AwaError_PathInvalid, "%s is not a resource path", path); } } else { result = LogErrorWithEnum(AwaError_PathInvalid, "No path specified"); } return result; }
AwaError ResponseCommon_BuildPathResults(ResponseCommon * response) { AwaError result = AwaError_Success; // success if no path results are found if (response != NULL) { FreeSimpleMap(&response->PathResults); response->PathResults = Map_New(); if (response->PathResults != NULL) { TreeNode currentLeafNode = response->ObjectsNode; while ((currentLeafNode = ObjectsTree_GetNextLeafNode(currentLeafNode)) != NULL) { TreeNode currentNode = currentLeafNode; // start at leaf and add path results for parents as well while (currentNode != NULL) { char path[MAX_PATH_LENGTH] = { 0 }; ObjectsTree_GetPath(currentNode, path, sizeof(path)); TreeNode resultNode = Xml_Find(currentNode, "Result"); if (resultNode != NULL) { PathResult * pathResult = PathResult_New(resultNode); if (pathResult != NULL) { if (!Map_Contains(response->PathResults, path)) { Map_Put(response->PathResults, path, pathResult); result = AwaError_Success; } else if (currentNode == currentLeafNode) { PathResult_Free(&pathResult); result = LogErrorWithEnum(AwaError_Internal, "A pathResult already exists for %s\n", path); goto error; } else { // Already added parent node PathResult_Free(&pathResult); } } else { result = LogErrorWithEnum(AwaError_Internal, "Could not create pathResult for %s", path); goto error; } } else { // not all leaves or responses have PathResults, so skip } currentNode = ObjectsTree_IsObjectNode(currentNode)? NULL : TreeNode_GetParent(currentNode); } } } else { result = LogErrorWithEnum(AwaError_OutOfMemory); } } else { result = LogErrorWithEnum(AwaError_ResponseInvalid, "response is NULL"); } error: return result; }
AwaError ResponseCommon_BuildValues(ResponseCommon * response) { AwaError result = AwaError_Success; // success if no values are found if (response != NULL) { FreeValues(&response->Values); response->Values = Map_New(); if (response->Values != NULL) { // get the resource type for the path const OperationCommon * operation = ResponseCommon_GetOperation(response); if (operation != NULL) { const SessionCommon * sessionCommon = OperationCommon_GetSessionCommon(operation); if (sessionCommon != NULL) { TreeNode currentNode = response->ObjectsNode; while ((currentNode = ObjectsTree_GetNextLeafNode(currentNode)) != NULL) { char path[MAX_PATH_LENGTH] = { 0 }; ObjectsTree_GetPath(currentNode, path, sizeof(path)); if (Path_IsValidForResource(path)) { LogDebug("Build values path: %s", path); const AwaResourceDefinition * resourceDefinition = SessionCommon_GetResourceDefinitionFromPath(sessionCommon, path); if (resourceDefinition != NULL) { AwaResourceType resourceType = AwaResourceDefinition_GetType(resourceDefinition); if (resourceType != AwaResourceType_Invalid) { Value * value = Value_New(currentNode, resourceType); if (value != NULL) { if (!Map_Contains(response->Values, path)) { LogDebug("MAP item path: %s", path); Map_Put(response->Values, path, value); result = AwaError_Success; } else { result = LogErrorWithEnum(AwaError_Internal, "A value already exists for %s", path); } } else { // No value is fine - occurs in operations where we only expect path results in the response. } } else { result = LogErrorWithEnum(AwaError_DefinitionInvalid, "resourceDefinition for %s has invalid type", path); } } else { result = LogErrorWithEnum(AwaError_DefinitionInvalid, "resourceDefinition for %s is NULL", path); } } } } else { result = LogErrorWithEnum(AwaError_SessionInvalid, "session is NULL"); } } else { result = LogErrorWithEnum(AwaError_OperationInvalid, "operation is NULL"); } } else { result = LogErrorWithEnum(AwaError_OutOfMemory); } } else { result = LogErrorWithEnum(AwaError_ResponseInvalid, "response is NULL"); } return result; }