Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: sht15_remote_monitoring f767zi_mqtt remote_monitoring simplesample_amqp ... more
commanddecoder.c
00001 // Copyright (c) Microsoft. All rights reserved. 00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 00003 00004 #include <stdlib.h> 00005 #include "azure_c_shared_utility/optimize_size.h" 00006 #include "azure_c_shared_utility/gballoc.h" 00007 00008 #include <stddef.h> 00009 00010 #include "commanddecoder.h" 00011 #include "multitree.h" 00012 #include "azure_c_shared_utility/crt_abstractions.h" 00013 #include "azure_c_shared_utility/xlogging.h" 00014 #include "schema.h" 00015 #include "codefirst.h" 00016 #include "jsondecoder.h" 00017 00018 DEFINE_ENUM_STRINGS(COMMANDDECODER_RESULT, COMMANDDECODER_RESULT_VALUES); 00019 00020 typedef struct COMMAND_DECODER_HANDLE_DATA_TAG 00021 { 00022 METHOD_CALLBACK_FUNC methodCallback; 00023 void* methodCallbackContext; 00024 SCHEMA_MODEL_TYPE_HANDLE ModelHandle; 00025 ACTION_CALLBACK_FUNC ActionCallback; 00026 void* ActionCallbackContext; 00027 } COMMAND_DECODER_HANDLE_DATA; 00028 00029 static int DecodeValueFromNode(SCHEMA_HANDLE schemaHandle, AGENT_DATA_TYPE* agentDataType, MULTITREE_HANDLE node, const char* edmTypeName) 00030 { 00031 /* because "pottentially uninitialized variable on MS compiler" */ 00032 int result = 0; 00033 const char* argStringValue; 00034 AGENT_DATA_TYPE_TYPE primitiveType; 00035 00036 /* Codes_SRS_COMMAND_DECODER_99_029:[ If the argument type is complex then a complex type value shall be built from the child nodes.] */ 00037 if ((primitiveType = CodeFirst_GetPrimitiveType(edmTypeName)) == EDM_NO_TYPE) 00038 { 00039 SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle; 00040 size_t propertyCount; 00041 00042 /* Codes_SRS_COMMAND_DECODER_99_033:[ In order to determine which are the members of a complex types, Schema APIs for structure types shall be used.] */ 00043 if (((structTypeHandle = Schema_GetStructTypeByName(schemaHandle, edmTypeName)) == NULL) || 00044 (Schema_GetStructTypePropertyCount(structTypeHandle, &propertyCount) != SCHEMA_OK)) 00045 { 00046 /* Codes_SRS_COMMAND_DECODER_99_010:[ If any Schema API fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/ 00047 result = __FAILURE__; 00048 LogError("Getting Struct information failed."); 00049 } 00050 else 00051 { 00052 if (propertyCount == 0) 00053 { 00054 /* Codes_SRS_COMMAND_DECODER_99_034:[ If Schema APIs indicate that a complex type has 0 members then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */ 00055 result = __FAILURE__; 00056 LogError("Struct type with 0 members is not allowed"); 00057 } 00058 else 00059 { 00060 AGENT_DATA_TYPE* memberValues = (AGENT_DATA_TYPE*)malloc(sizeof(AGENT_DATA_TYPE)* propertyCount); 00061 if (memberValues == NULL) 00062 { 00063 /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */ 00064 result = __FAILURE__; 00065 LogError("Failed allocating member values for command argument"); 00066 } 00067 else 00068 { 00069 const char** memberNames = (const char**)malloc(sizeof(const char*)* propertyCount); 00070 if (memberNames == NULL) 00071 { 00072 /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */ 00073 result = __FAILURE__; 00074 LogError("Failed allocating member names for command argument."); 00075 } 00076 else 00077 { 00078 size_t j; 00079 size_t k; 00080 00081 for (j = 0; j < propertyCount; j++) 00082 { 00083 SCHEMA_PROPERTY_HANDLE propertyHandle; 00084 MULTITREE_HANDLE memberNode; 00085 const char* propertyName; 00086 const char* propertyType; 00087 00088 if ((propertyHandle = Schema_GetStructTypePropertyByIndex(structTypeHandle, j)) == NULL) 00089 { 00090 /* Codes_SRS_COMMAND_DECODER_99_010:[ If any Schema API fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/ 00091 result = __FAILURE__; 00092 LogError("Getting struct member failed."); 00093 break; 00094 } 00095 else if (((propertyName = Schema_GetPropertyName(propertyHandle)) == NULL) || 00096 ((propertyType = Schema_GetPropertyType(propertyHandle)) == NULL)) 00097 { 00098 /* Codes_SRS_COMMAND_DECODER_99_010:[ If any Schema API fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/ 00099 result = __FAILURE__; 00100 LogError("Getting the struct member information failed."); 00101 break; 00102 } 00103 else 00104 { 00105 memberNames[j] = propertyName; 00106 00107 /* Codes_SRS_COMMAND_DECODER_01_014: [CommandDecoder shall use the MultiTree APIs to extract a specific element from the command JSON.] */ 00108 if (MultiTree_GetChildByName(node, memberNames[j], &memberNode) != MULTITREE_OK) 00109 { 00110 /* Codes_SRS_COMMAND_DECODER_99_028:[ If decoding the argument fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */ 00111 result = __FAILURE__; 00112 LogError("Getting child %s failed", propertyName); 00113 break; 00114 } 00115 /* Codes_SRS_COMMAND_DECODER_99_032:[ Nesting shall be supported for complex type.] */ 00116 else if ((result = DecodeValueFromNode(schemaHandle, &memberValues[j], memberNode, propertyType)) != 0) 00117 { 00118 break; 00119 } 00120 } 00121 } 00122 00123 if (j == propertyCount) 00124 { 00125 /* Codes_SRS_COMMAND_DECODER_99_031:[ The complex type value that aggregates the children shall be built by using the Create_AGENT_DATA_TYPE_from_Members.] */ 00126 if (Create_AGENT_DATA_TYPE_from_Members(agentDataType, edmTypeName, propertyCount, (const char* const*)memberNames, memberValues) != AGENT_DATA_TYPES_OK) 00127 { 00128 /* Codes_SRS_COMMAND_DECODER_99_028:[ If decoding the argument fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */ 00129 result = __FAILURE__; 00130 LogError("Creating the agent data type from members failed."); 00131 } 00132 else 00133 { 00134 result = 0; 00135 } 00136 } 00137 00138 for (k = 0; k < j; k++) 00139 { 00140 Destroy_AGENT_DATA_TYPE(&memberValues[k]); 00141 } 00142 00143 free((void*)memberNames); 00144 } 00145 00146 free(memberValues); 00147 } 00148 } 00149 } 00150 } 00151 else 00152 { 00153 /* Codes_SRS_COMMAND_DECODER_01_014: [CommandDecoder shall use the MultiTree APIs to extract a specific element from the command JSON.] */ 00154 if (MultiTree_GetValue(node, (const void **)&argStringValue) != MULTITREE_OK) 00155 { 00156 /* Codes_SRS_COMMAND_DECODER_99_012:[ If any argument is missing in the command text then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */ 00157 result = __FAILURE__; 00158 LogError("Getting the string from the multitree failed."); 00159 } 00160 /* Codes_SRS_COMMAND_DECODER_99_027:[ The value for an argument of primitive type shall be decoded by using the CreateAgentDataType_From_String API.] */ 00161 else if (CreateAgentDataType_From_String(argStringValue, primitiveType, agentDataType) != AGENT_DATA_TYPES_OK) 00162 { 00163 /* Codes_SRS_COMMAND_DECODER_99_028:[ If decoding the argument fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */ 00164 result = __FAILURE__; 00165 LogError("Failed parsing node %s.", argStringValue); 00166 } 00167 } 00168 00169 return result; 00170 } 00171 00172 static EXECUTE_COMMAND_RESULT DecodeAndExecuteModelAction(COMMAND_DECODER_HANDLE_DATA* commandDecoderInstance, SCHEMA_HANDLE schemaHandle, SCHEMA_MODEL_TYPE_HANDLE modelHandle, const char* relativeActionPath, const char* actionName, MULTITREE_HANDLE commandNode) 00173 { 00174 EXECUTE_COMMAND_RESULT result; 00175 char tempStr[128]; 00176 size_t strLength = strlen(actionName); 00177 00178 if (strLength <= 1) 00179 { 00180 /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */ 00181 LogError("Invalid action name"); 00182 result = EXECUTE_COMMAND_ERROR; 00183 } 00184 else if (strLength >= 128) 00185 { 00186 /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */ 00187 LogError("Invalid action name length"); 00188 result = EXECUTE_COMMAND_ERROR; 00189 } 00190 else 00191 { 00192 /* Codes_SRS_COMMAND_DECODER_99_006:[ The action name shall be decoded from the element "Name" of the command JSON.] */ 00193 SCHEMA_ACTION_HANDLE modelActionHandle; 00194 size_t argCount; 00195 MULTITREE_HANDLE parametersTreeNode; 00196 00197 if (memcpy(tempStr, actionName, strLength-1) == NULL) 00198 { 00199 /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */ 00200 LogError("Invalid action name."); 00201 result = EXECUTE_COMMAND_ERROR; 00202 } 00203 /* Codes_SRS_COMMAND_DECODER_01_014: [CommandDecoder shall use the MultiTree APIs to extract a specific element from the command JSON.] */ 00204 else if (MultiTree_GetChildByName(commandNode, "Parameters", ¶metersTreeNode) != MULTITREE_OK) 00205 { 00206 /* Codes_SRS_COMMAND_DECODER_01_015: [If any MultiTree API call fails then the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */ 00207 LogError("Error getting Parameters node."); 00208 result = EXECUTE_COMMAND_ERROR; 00209 } 00210 else 00211 { 00212 tempStr[strLength-1] = 0; 00213 /* Codes_SRS_COMMAND_DECODER_99_009:[ CommandDecoder shall call Schema_GetModelActionByName to obtain the information about a specific action.] */ 00214 if (((modelActionHandle = Schema_GetModelActionByName(modelHandle, tempStr)) == NULL) || 00215 (Schema_GetModelActionArgumentCount(modelActionHandle, &argCount) != SCHEMA_OK)) 00216 { 00217 /* Codes_SRS_COMMAND_DECODER_99_010:[ If any Schema API fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/ 00218 LogError("Failed reading action %s from the schema", tempStr); 00219 result = EXECUTE_COMMAND_ERROR; 00220 } 00221 else 00222 { 00223 AGENT_DATA_TYPE* arguments = NULL; 00224 00225 if (argCount > 0) 00226 { 00227 arguments = (AGENT_DATA_TYPE*)malloc(sizeof(AGENT_DATA_TYPE)* argCount); 00228 } 00229 00230 if ((argCount > 0) && 00231 (arguments == NULL)) 00232 { 00233 /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */ 00234 LogError("Failed allocating arguments array"); 00235 result = EXECUTE_COMMAND_ERROR; 00236 } 00237 else 00238 { 00239 size_t i; 00240 size_t j; 00241 result = EXECUTE_COMMAND_ERROR; 00242 00243 /* Codes_SRS_COMMAND_DECODER_99_011:[ CommandDecoder shall attempt to extract from the command text the value for each action argument.] */ 00244 for (i = 0; i < argCount; i++) 00245 { 00246 SCHEMA_ACTION_ARGUMENT_HANDLE actionArgumentHandle; 00247 MULTITREE_HANDLE argumentNode; 00248 const char* argName; 00249 const char* argType; 00250 00251 if (((actionArgumentHandle = Schema_GetModelActionArgumentByIndex(modelActionHandle, i)) == NULL) || 00252 ((argName = Schema_GetActionArgumentName(actionArgumentHandle)) == NULL) || 00253 ((argType = Schema_GetActionArgumentType(actionArgumentHandle)) == NULL)) 00254 { 00255 LogError("Failed getting the argument information from the schema"); 00256 result = EXECUTE_COMMAND_ERROR; 00257 break; 00258 } 00259 /* Codes_SRS_COMMAND_DECODER_01_014: [CommandDecoder shall use the MultiTree APIs to extract a specific element from the command JSON.] */ 00260 /* Codes_SRS_COMMAND_DECODER_01_008: [Each argument shall be looked up as a field, member of the "Parameters" node.] */ 00261 else if (MultiTree_GetChildByName(parametersTreeNode, argName, &argumentNode) != MULTITREE_OK) 00262 { 00263 /* Codes_SRS_COMMAND_DECODER_99_012:[ If any argument is missing in the command text then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */ 00264 LogError("Missing argument %s", argName); 00265 result = EXECUTE_COMMAND_ERROR; 00266 break; 00267 } 00268 else if (DecodeValueFromNode(schemaHandle, &arguments[i], argumentNode, argType) != 0) 00269 { 00270 result = EXECUTE_COMMAND_ERROR; 00271 break; 00272 } 00273 } 00274 00275 if (i == argCount) 00276 { 00277 /* Codes_SRS_COMMAND_DECODER_99_005:[ If an Invoke Action is decoded successfully then the callback actionCallback shall be called, passing to it the callback action context, decoded name and arguments.] */ 00278 result = commandDecoderInstance->ActionCallback(commandDecoderInstance->ActionCallbackContext, relativeActionPath, tempStr, argCount, arguments); 00279 } 00280 00281 for (j = 0; j < i; j++) 00282 { 00283 Destroy_AGENT_DATA_TYPE(&arguments[j]); 00284 } 00285 00286 if (arguments != NULL) 00287 { 00288 free(arguments); 00289 } 00290 } 00291 } 00292 } 00293 } 00294 return result; 00295 } 00296 00297 static METHODRETURN_HANDLE DecodeAndExecuteModelMethod(COMMAND_DECODER_HANDLE_DATA* commandDecoderInstance, SCHEMA_HANDLE schemaHandle, SCHEMA_MODEL_TYPE_HANDLE modelHandle, const char* relativeMethodPath, const char* methodName, MULTITREE_HANDLE methodTree) 00298 { 00299 METHODRETURN_HANDLE result; 00300 size_t strLength = strlen(methodName); 00301 00302 if (strLength == 0) 00303 { 00304 /*Codes_SRS_COMMAND_DECODER_02_023: [ If any of the previous operations fail, then CommandDecoder_ExecuteMethod shall return NULL. ]*/ 00305 LogError("Invalid method name"); 00306 result = NULL; 00307 } 00308 else 00309 { 00310 SCHEMA_METHOD_HANDLE modelMethodHandle; 00311 size_t argCount; 00312 00313 #ifdef _MSC_VER 00314 #pragma warning(suppress: 6324) /* We intentionally use here strncpy */ 00315 #endif 00316 00317 /*Codes_SRS_COMMAND_DECODER_02_020: [ CommandDecoder_ExecuteMethod shall verify that the model has a method called methodName. ]*/ 00318 if (((modelMethodHandle = Schema_GetModelMethodByName(modelHandle, methodName)) == NULL) || 00319 (Schema_GetModelMethodArgumentCount(modelMethodHandle, &argCount) != SCHEMA_OK)) 00320 { 00321 /*Codes_SRS_COMMAND_DECODER_02_023: [ If any of the previous operations fail, then CommandDecoder_ExecuteMethod shall return NULL. ]*/ 00322 LogError("Failed reading method %s from the schema", methodName); 00323 result = NULL; 00324 } 00325 else 00326 { 00327 /*Codes_SRS_COMMAND_DECODER_02_021: [ For every argument of methodName, CommandDecoder_ExecuteMethod shall build an AGENT_DATA_TYPE from the node with the same name from the MULTITREE_HANDLE. ]*/ 00328 00329 if (argCount == 0) 00330 { 00331 /*no need for any parameters*/ 00332 result = commandDecoderInstance->methodCallback(commandDecoderInstance->methodCallbackContext, relativeMethodPath, methodName, 0, NULL); 00333 } 00334 else 00335 { 00336 AGENT_DATA_TYPE* arguments; 00337 arguments = (AGENT_DATA_TYPE*)malloc(sizeof(AGENT_DATA_TYPE)* argCount); 00338 if (arguments == NULL) 00339 { 00340 LogError("Failed allocating arguments array"); 00341 result = NULL; 00342 } 00343 else 00344 { 00345 size_t i; 00346 size_t j; 00347 result = NULL; 00348 00349 for (i = 0; i < argCount; i++) 00350 { 00351 SCHEMA_METHOD_ARGUMENT_HANDLE methodArgumentHandle; 00352 MULTITREE_HANDLE argumentNode; 00353 const char* argName; 00354 const char* argType; 00355 00356 if (((methodArgumentHandle = Schema_GetModelMethodArgumentByIndex(modelMethodHandle, i)) == NULL) || 00357 ((argName = Schema_GetMethodArgumentName(methodArgumentHandle)) == NULL) || 00358 ((argType = Schema_GetMethodArgumentType(methodArgumentHandle)) == NULL)) 00359 { 00360 /*Codes_SRS_COMMAND_DECODER_02_023: [ If any of the previous operations fail, then CommandDecoder_ExecuteMethod shall return NULL. ]*/ 00361 LogError("Failed getting the argument information from the schema"); 00362 result = NULL; 00363 break; 00364 } 00365 else if (MultiTree_GetChildByName(methodTree, argName, &argumentNode) != MULTITREE_OK) 00366 { 00367 /*Codes_SRS_COMMAND_DECODER_02_023: [ If any of the previous operations fail, then CommandDecoder_ExecuteMethod shall return NULL. ]*/ 00368 LogError("Missing argument %s", argName); 00369 result = NULL; 00370 break; 00371 } 00372 else if (DecodeValueFromNode(schemaHandle, &arguments[i], argumentNode, argType) != 0) 00373 { 00374 /*Codes_SRS_COMMAND_DECODER_02_023: [ If any of the previous operations fail, then CommandDecoder_ExecuteMethod shall return NULL. ]*/ 00375 LogError("failure in DecodeValueFromNode"); 00376 result = NULL; 00377 break; 00378 } 00379 } 00380 00381 if (i == argCount) 00382 { 00383 /*Codes_SRS_COMMAND_DECODER_02_022: [ CommandDecoder_ExecuteMethod shall call methodCallback passing the context, the methodName, number of arguments and the AGENT_DATA_TYPE. ]*/ 00384 /*Codes_SRS_COMMAND_DECODER_02_024: [ Otherwise, CommandDecoder_ExecuteMethod shall return what methodCallback returns. ]*/ 00385 result = commandDecoderInstance->methodCallback(commandDecoderInstance->methodCallbackContext, relativeMethodPath, methodName, argCount, arguments); 00386 } 00387 00388 for (j = 0; j < i; j++) 00389 { 00390 Destroy_AGENT_DATA_TYPE(&arguments[j]); 00391 } 00392 00393 free(arguments); 00394 } 00395 00396 } 00397 } 00398 00399 } 00400 return result; 00401 } 00402 00403 00404 static EXECUTE_COMMAND_RESULT ScanActionPathAndExecuteAction(COMMAND_DECODER_HANDLE_DATA* commandDecoderInstance, SCHEMA_HANDLE schemaHandle, const char* actionPath, MULTITREE_HANDLE commandNode) 00405 { 00406 EXECUTE_COMMAND_RESULT result; 00407 char* relativeActionPath; 00408 const char* actionName = actionPath; 00409 SCHEMA_MODEL_TYPE_HANDLE modelHandle = commandDecoderInstance->ModelHandle; 00410 00411 /* Codes_SRS_COMMAND_DECODER_99_035:[ CommandDecoder_ExecuteCommand shall support paths to actions that are in child models (i.e. ChildModel/SomeAction.] */ 00412 do 00413 { 00414 /* find the slash */ 00415 const char* slashPos = strchr(actionName, '/'); 00416 if (slashPos == NULL) 00417 { 00418 size_t relativeActionPathLength; 00419 00420 /* Codes_SRS_COMMAND_DECODER_99_037:[ The relative path passed to the actionCallback shall be in the format "childModel1/childModel2/.../childModelN".] */ 00421 if (actionName == actionPath) 00422 { 00423 relativeActionPathLength = 0; 00424 } 00425 else 00426 { 00427 relativeActionPathLength = actionName - actionPath - 1; 00428 } 00429 00430 relativeActionPath = (char*)malloc(relativeActionPathLength + 1); 00431 if (relativeActionPath == NULL) 00432 { 00433 /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */ 00434 LogError("Failed allocating relative action path"); 00435 result = EXECUTE_COMMAND_ERROR; 00436 } 00437 else 00438 { 00439 strncpy(relativeActionPath, actionPath, relativeActionPathLength); 00440 relativeActionPath[relativeActionPathLength] = 0; 00441 00442 /* no slash found, this must be an action */ 00443 result = DecodeAndExecuteModelAction(commandDecoderInstance, schemaHandle, modelHandle, relativeActionPath, actionName, commandNode); 00444 00445 free(relativeActionPath); 00446 actionName = NULL; 00447 } 00448 break; 00449 } 00450 else 00451 { 00452 /* found a slash, get the child model name */ 00453 size_t modelLength = slashPos - actionName; 00454 char* childModelName = (char*)malloc(modelLength + 1); 00455 if (childModelName == NULL) 00456 { 00457 /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */ 00458 LogError("Failed allocating child model name"); 00459 result = EXECUTE_COMMAND_ERROR; 00460 break; 00461 } 00462 else 00463 { 00464 strncpy(childModelName, actionName, modelLength); 00465 childModelName[modelLength] = 0; 00466 00467 /* find the model */ 00468 modelHandle = Schema_GetModelModelByName(modelHandle, childModelName); 00469 if (modelHandle == NULL) 00470 { 00471 /* Codes_SRS_COMMAND_DECODER_99_036:[ If a child model cannot be found by using Schema APIs then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */ 00472 LogError("Getting the model %s failed", childModelName); 00473 free(childModelName); 00474 result = EXECUTE_COMMAND_ERROR; 00475 break; 00476 } 00477 else 00478 { 00479 free(childModelName); 00480 actionName = slashPos + 1; 00481 result = EXECUTE_COMMAND_ERROR; /*this only exists to quench a compiler warning about returning an uninitialized variable, which is not possible by design*/ 00482 } 00483 } 00484 } 00485 } while (actionName != NULL); 00486 return result; 00487 } 00488 00489 static METHODRETURN_HANDLE ScanMethodPathAndExecuteMethod(COMMAND_DECODER_HANDLE_DATA* commandDecoderInstance, SCHEMA_HANDLE schemaHandle, const char* fullMethodName, MULTITREE_HANDLE methodTree) 00490 { 00491 METHODRETURN_HANDLE result; 00492 char* relativeMethodPath; 00493 const char* methodName = fullMethodName; 00494 SCHEMA_MODEL_TYPE_HANDLE modelHandle = commandDecoderInstance->ModelHandle; 00495 00496 /*Codes_SRS_COMMAND_DECODER_02_018: [ CommandDecoder_ExecuteMethod shall validate that consecutive segments of the fullMethodName exist in the model. ]*/ 00497 /*Codes_SRS_COMMAND_DECODER_02_019: [ CommandDecoder_ExecuteMethod shall locate the final model to which the methodName applies. ]*/ 00498 do 00499 { 00500 /* find the slash */ 00501 const char* slashPos = strchr(methodName, '/'); 00502 if (slashPos == NULL) 00503 { 00504 size_t relativeMethodPathLength; 00505 00506 if (methodName == fullMethodName) 00507 { 00508 relativeMethodPathLength = 0; 00509 } 00510 else 00511 { 00512 relativeMethodPathLength = methodName - fullMethodName - 1; 00513 } 00514 00515 relativeMethodPath = (char*)malloc(relativeMethodPathLength + 1); 00516 if (relativeMethodPath == NULL) 00517 { 00518 /*Codes_SRS_COMMAND_DECODER_02_023: [ If any of the previous operations fail, then CommandDecoder_ExecuteMethod shall return NULL. ]*/ 00519 LogError("Failed allocating relative method path"); 00520 result = NULL; 00521 } 00522 else 00523 { 00524 strncpy(relativeMethodPath, fullMethodName, relativeMethodPathLength); 00525 relativeMethodPath[relativeMethodPathLength] = 0; 00526 00527 /* no slash found, this must be an method */ 00528 result = DecodeAndExecuteModelMethod(commandDecoderInstance, schemaHandle, modelHandle, relativeMethodPath, methodName, methodTree); 00529 00530 free(relativeMethodPath); 00531 methodName = NULL; 00532 } 00533 break; 00534 } 00535 else 00536 { 00537 /* found a slash, get the child model name */ 00538 size_t modelLength = slashPos - methodName; 00539 char* childModelName = (char*)malloc(modelLength + 1); 00540 if (childModelName == NULL) 00541 { 00542 /*Codes_SRS_COMMAND_DECODER_02_023: [ If any of the previous operations fail, then CommandDecoder_ExecuteMethod shall return NULL. ]*/ 00543 LogError("Failed allocating child model name"); 00544 result = NULL; 00545 break; 00546 } 00547 else 00548 { 00549 strncpy(childModelName, methodName, modelLength); 00550 childModelName[modelLength] = 0; 00551 00552 /* find the model */ 00553 modelHandle = Schema_GetModelModelByName(modelHandle, childModelName); 00554 if (modelHandle == NULL) 00555 { 00556 /*Codes_SRS_COMMAND_DECODER_02_023: [ If any of the previous operations fail, then CommandDecoder_ExecuteMethod shall return NULL. ]*/ 00557 LogError("Getting the model %s failed", childModelName); 00558 free(childModelName); 00559 result = NULL; 00560 break; 00561 } 00562 else 00563 { 00564 free(childModelName); 00565 methodName = slashPos + 1; 00566 result = NULL; /*this only exists to quench a compiler warning about returning an uninitialized variable, which is not possible by design*/ 00567 } 00568 } 00569 } 00570 } while (methodName != NULL); 00571 return result; 00572 } 00573 00574 static EXECUTE_COMMAND_RESULT DecodeCommand(COMMAND_DECODER_HANDLE_DATA* commandDecoderInstance, MULTITREE_HANDLE commandNode) 00575 { 00576 EXECUTE_COMMAND_RESULT result; 00577 SCHEMA_HANDLE schemaHandle; 00578 00579 /* Codes_SRS_COMMAND_DECODER_99_022:[ CommandDecoder shall use the Schema APIs to obtain the information about the entity set name and namespace] */ 00580 if ((schemaHandle = Schema_GetSchemaForModelType(commandDecoderInstance->ModelHandle)) == NULL) 00581 { 00582 /* Codes_SRS_COMMAND_DECODER_99_010:[ If any Schema API fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/ 00583 LogError("Getting schema information failed"); 00584 result = EXECUTE_COMMAND_ERROR; 00585 } 00586 else 00587 { 00588 const char* actionName; 00589 MULTITREE_HANDLE nameTreeNode; 00590 00591 /* Codes_SRS_COMMAND_DECODER_01_014: [CommandDecoder shall use the MultiTree APIs to extract a specific element from the command JSON.] */ 00592 /* Codes_SRS_COMMAND_DECODER_99_006:[ The action name shall be decoded from the element "name" of the command JSON.] */ 00593 if ((MultiTree_GetChildByName(commandNode, "Name", &nameTreeNode) != MULTITREE_OK) || 00594 (MultiTree_GetValue(nameTreeNode, (const void **)&actionName) != MULTITREE_OK)) 00595 { 00596 /* Codes_SRS_COMMAND_DECODER_01_015: [If any MultiTree API call fails then the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */ 00597 LogError("Getting action name failed."); 00598 result = EXECUTE_COMMAND_ERROR; 00599 } 00600 else if (strlen(actionName) < 2) 00601 { 00602 /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */ 00603 LogError("Invalid action name."); 00604 result = EXECUTE_COMMAND_ERROR; 00605 } 00606 else 00607 { 00608 actionName++; 00609 result = ScanActionPathAndExecuteAction(commandDecoderInstance, schemaHandle, actionName, commandNode); 00610 } 00611 } 00612 return result; 00613 } 00614 00615 static METHODRETURN_HANDLE DecodeMethod(COMMAND_DECODER_HANDLE_DATA* commandDecoderInstance, const char* fullMethodName, MULTITREE_HANDLE methodTree) 00616 { 00617 METHODRETURN_HANDLE result; 00618 SCHEMA_HANDLE schemaHandle; 00619 00620 /*Codes_SRS_COMMAND_DECODER_02_017: [ CommandDecoder_ExecuteMethod shall get the SCHEMA_HANDLE associated with the modelHandle passed at CommandDecoder_Create. ]*/ 00621 if ((schemaHandle = Schema_GetSchemaForModelType(commandDecoderInstance->ModelHandle)) == NULL) 00622 { 00623 LogError("Getting schema information failed"); 00624 result = NULL; 00625 } 00626 else 00627 { 00628 result = ScanMethodPathAndExecuteMethod(commandDecoderInstance, schemaHandle, fullMethodName, methodTree); 00629 00630 } 00631 return result; 00632 } 00633 00634 /*Codes_SRS_COMMAND_DECODER_01_009: [Whenever CommandDecoder_ExecuteCommand is the command shall be decoded and further dispatched to the actionCallback passed in CommandDecoder_Create.]*/ 00635 EXECUTE_COMMAND_RESULT CommandDecoder_ExecuteCommand(COMMAND_DECODER_HANDLE handle, const char* command) 00636 { 00637 EXECUTE_COMMAND_RESULT result; 00638 COMMAND_DECODER_HANDLE_DATA* commandDecoderInstance = (COMMAND_DECODER_HANDLE_DATA*)handle; 00639 /*Codes_SRS_COMMAND_DECODER_01_010: [If either the buffer or the receiveCallbackContext argument is NULL, the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/ 00640 if ( 00641 (command == NULL) || 00642 (commandDecoderInstance == NULL) 00643 ) 00644 { 00645 LogError("Invalid argument, COMMAND_DECODER_HANDLE handle=%p, const char* command=%p", handle, command); 00646 result = EXECUTE_COMMAND_ERROR; 00647 } 00648 else 00649 { 00650 size_t size = strlen(command); 00651 char* commandJSON; 00652 00653 /* Codes_SRS_COMMAND_DECODER_01_011: [If the size of the command is 0 then the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/ 00654 if (size == 0) 00655 { 00656 LogError("Failed because command size is zero"); 00657 result = EXECUTE_COMMAND_ERROR; 00658 } 00659 /*Codes_SRS_COMMAND_DECODER_01_013: [If parsing the JSON to a multi tree fails, the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/ 00660 else if ((commandJSON = (char*)malloc(size + 1)) == NULL) 00661 { 00662 LogError("Failed to allocate temporary storage for the commands JSON"); 00663 result = EXECUTE_COMMAND_ERROR; 00664 } 00665 else 00666 { 00667 MULTITREE_HANDLE commandsTree; 00668 00669 (void)memcpy(commandJSON, command, size); 00670 commandJSON[size] = '\0'; 00671 00672 /* Codes_SRS_COMMAND_DECODER_01_012: [CommandDecoder shall decode the command JSON contained in buffer to a multi-tree by using JSONDecoder_JSON_To_MultiTree.] */ 00673 if (JSONDecoder_JSON_To_MultiTree(commandJSON, &commandsTree) != JSON_DECODER_OK) 00674 { 00675 /* Codes_SRS_COMMAND_DECODER_01_013: [If parsing the JSON to a multi tree fails, the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */ 00676 LogError("Decoding JSON to a multi tree failed"); 00677 result = EXECUTE_COMMAND_ERROR; 00678 } 00679 else 00680 { 00681 result = DecodeCommand(commandDecoderInstance, commandsTree); 00682 00683 /* Codes_SRS_COMMAND_DECODER_01_016: [CommandDecoder shall ensure that the multi-tree resulting from JSONDecoder_JSON_To_MultiTree is freed after the commands are executed.] */ 00684 MultiTree_Destroy(commandsTree); 00685 } 00686 00687 free(commandJSON); 00688 } 00689 } 00690 return result; 00691 } 00692 00693 METHODRETURN_HANDLE CommandDecoder_ExecuteMethod(COMMAND_DECODER_HANDLE handle, const char* fullMethodName, const char* methodPayload) 00694 { 00695 METHODRETURN_HANDLE result; 00696 /*Codes_SRS_COMMAND_DECODER_02_014: [ If handle is NULL then CommandDecoder_ExecuteMethod shall fail and return NULL. ]*/ 00697 /*Codes_SRS_COMMAND_DECODER_02_015: [ If fulMethodName is NULL then CommandDecoder_ExecuteMethod shall fail and return NULL. ]*/ 00698 if ( 00699 (handle == NULL) || 00700 (fullMethodName == NULL) /*methodPayload can be NULL*/ 00701 ) 00702 { 00703 LogError("Invalid argument, COMMAND_DECODER_HANDLE handle=%p, const char* fullMethodName=%p", handle, fullMethodName); 00704 result = NULL; 00705 } 00706 else 00707 { 00708 COMMAND_DECODER_HANDLE_DATA* commandDecoderInstance = (COMMAND_DECODER_HANDLE_DATA*)handle; 00709 /*Codes_SRS_COMMAND_DECODER_02_025: [ If methodCallback is NULL then CommandDecoder_ExecuteMethod shall fail and return NULL. ]*/ 00710 if (commandDecoderInstance->methodCallback == NULL) 00711 { 00712 LogError("unable to execute a method when the methodCallback passed in CommandDecoder_Create is NULL"); 00713 result = NULL; 00714 } 00715 else 00716 { 00717 /*Codes_SRS_COMMAND_DECODER_02_016: [ If methodPayload is not NULL then CommandDecoder_ExecuteMethod shall build a MULTITREE_HANDLE out of methodPayload. ]*/ 00718 if (methodPayload == NULL) 00719 { 00720 result = DecodeMethod(commandDecoderInstance, fullMethodName, NULL); 00721 } 00722 else 00723 { 00724 char* methodJSON; 00725 00726 if (mallocAndStrcpy_s(&methodJSON, methodPayload) != 0) 00727 { 00728 LogError("Failed to allocate temporary storage for the method JSON"); 00729 result = NULL; 00730 } 00731 else 00732 { 00733 MULTITREE_HANDLE methodTree; 00734 if (JSONDecoder_JSON_To_MultiTree(methodJSON, &methodTree) != JSON_DECODER_OK) 00735 { 00736 LogError("Decoding JSON to a multi tree failed"); 00737 result = NULL; 00738 } 00739 else 00740 { 00741 result = DecodeMethod(commandDecoderInstance, fullMethodName, methodTree); 00742 MultiTree_Destroy(methodTree); 00743 } 00744 free(methodJSON); 00745 } 00746 } 00747 } 00748 } 00749 return result; 00750 } 00751 00752 00753 COMMAND_DECODER_HANDLE CommandDecoder_Create(SCHEMA_MODEL_TYPE_HANDLE modelHandle, ACTION_CALLBACK_FUNC actionCallback, void* actionCallbackContext, METHOD_CALLBACK_FUNC methodCallback, void* methodCallbackContext) 00754 { 00755 COMMAND_DECODER_HANDLE_DATA* result; 00756 /* Codes_SRS_COMMAND_DECODER_99_019:[ For all exposed APIs argument validity checks shall precede other checks.] */ 00757 /* Codes_SRS_COMMAND_DECODER_01_003: [ If modelHandle is NULL, CommandDecoder_Create shall return NULL. ]*/ 00758 if (modelHandle == NULL) 00759 { 00760 LogError("Invalid arguments: SCHEMA_MODEL_TYPE_HANDLE modelHandle=%p, ACTION_CALLBACK_FUNC actionCallback=%p, void* actionCallbackContext=%p, METHOD_CALLBACK_FUNC methodCallback=%p, void* methodCallbackContext=%p", 00761 modelHandle, actionCallback, actionCallbackContext, methodCallback, methodCallbackContext); 00762 result = NULL; 00763 } 00764 else 00765 { 00766 /* Codes_SRS_COMMAND_DECODER_01_001: [CommandDecoder_Create shall create a new instance of a CommandDecoder.] */ 00767 result = malloc(sizeof(COMMAND_DECODER_HANDLE_DATA)); 00768 if (result == NULL) 00769 { 00770 /* Codes_SRS_COMMAND_DECODER_01_004: [If any error is encountered during CommandDecoder_Create CommandDecoder_Create shall return NULL.] */ 00771 /*return as is*/ 00772 } 00773 else 00774 { 00775 result->ModelHandle = modelHandle; 00776 result->ActionCallback = actionCallback; 00777 result->ActionCallbackContext = actionCallbackContext; 00778 result->methodCallback = methodCallback; 00779 result->methodCallbackContext = methodCallbackContext; 00780 } 00781 } 00782 00783 return result; 00784 } 00785 00786 void CommandDecoder_Destroy(COMMAND_DECODER_HANDLE commandDecoderHandle) 00787 { 00788 /* Codes_SRS_COMMAND_DECODER_01_007: [If CommandDecoder_Destroy is called with a NULL handle, CommandDecoder_Destroy shall do nothing.] */ 00789 if (commandDecoderHandle != NULL) 00790 { 00791 COMMAND_DECODER_HANDLE_DATA* commandDecoderInstance = (COMMAND_DECODER_HANDLE_DATA*)commandDecoderHandle; 00792 00793 /* Codes_SRS_COMMAND_DECODER_01_005: [CommandDecoder_Destroy shall free all resources associated with the commandDecoderHandle instance.] */ 00794 free(commandDecoderInstance); 00795 } 00796 } 00797 00798 DEFINE_ENUM_STRINGS(AGENT_DATA_TYPE_TYPE, AGENT_DATA_TYPE_TYPE_VALUES); 00799 00800 /*validates that the multitree (coming from a JSON) is actually a serialization of the model (complete or incomplete)*/ 00801 /*if the serialization contains more than the model, then it fails.*/ 00802 /*if the serialization does not contain mandatory items from the model, it fails*/ 00803 static bool validateModel_vs_Multitree(void* startAddress, SCHEMA_MODEL_TYPE_HANDLE modelHandle, MULTITREE_HANDLE desiredPropertiesTree, size_t offset) 00804 { 00805 00806 bool result; 00807 size_t nChildren; 00808 size_t nProcessedChildren = 0; 00809 (void)MultiTree_GetChildCount(desiredPropertiesTree, &nChildren); 00810 for (size_t i = 0;i < nChildren;i++) 00811 { 00812 MULTITREE_HANDLE child; 00813 if (MultiTree_GetChild(desiredPropertiesTree, i, &child) != MULTITREE_OK) 00814 { 00815 LogError("failure in MultiTree_GetChild"); 00816 i = nChildren; 00817 } 00818 else 00819 { 00820 STRING_HANDLE childName = STRING_new(); 00821 if (childName == NULL) 00822 { 00823 LogError("failure to STRING_new"); 00824 i = nChildren; 00825 } 00826 else 00827 { 00828 if (MultiTree_GetName(child, childName) != MULTITREE_OK) 00829 { 00830 LogError("failure to MultiTree_GetName"); 00831 i = nChildren; 00832 } 00833 else 00834 { 00835 const char *childName_str = STRING_c_str(childName); 00836 SCHEMA_MODEL_ELEMENT elementType = Schema_GetModelElementByName(modelHandle, childName_str); 00837 switch (elementType.elementType) 00838 { 00839 default: 00840 { 00841 LogError("INTERNAL ERROR: unexpected function return"); 00842 i = nChildren; 00843 break; 00844 } 00845 case (SCHEMA_PROPERTY): 00846 { 00847 LogError("cannot ingest name (WITH_DATA instead of WITH_DESIRED_PROPERTY): %s", childName_str); 00848 i = nChildren; 00849 break; 00850 } 00851 case (SCHEMA_REPORTED_PROPERTY): 00852 { 00853 LogError("cannot ingest name (WITH_REPORTED_PROPERTY instead of WITH_DESIRED_PROPERTY): %s", childName_str); 00854 i = nChildren; 00855 break; 00856 } 00857 case (SCHEMA_DESIRED_PROPERTY): 00858 { 00859 /*Codes_SRS_COMMAND_DECODER_02_007: [ If the child name corresponds to a desired property then an AGENT_DATA_TYPE shall be constructed from the MULTITREE node. ]*/ 00860 SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle = elementType.elementHandle.desiredPropertyHandle; 00861 00862 const char* desiredPropertyType = Schema_GetModelDesiredPropertyType(desiredPropertyHandle); 00863 AGENT_DATA_TYPE output; 00864 if (DecodeValueFromNode(Schema_GetSchemaForModelType(modelHandle), &output, child, desiredPropertyType) != 0) 00865 { 00866 LogError("failure in DecodeValueFromNode"); 00867 i = nChildren; 00868 } 00869 else 00870 { 00871 /*Codes_SRS_COMMAND_DECODER_02_008: [ The desired property shall be constructed in memory by calling pfDesiredPropertyFromAGENT_DATA_TYPE. ]*/ 00872 pfDesiredPropertyFromAGENT_DATA_TYPE leFunction = Schema_GetModelDesiredProperty_pfDesiredPropertyFromAGENT_DATA_TYPE(desiredPropertyHandle); 00873 if (leFunction(&output, (char*)startAddress + offset + Schema_GetModelDesiredProperty_offset(desiredPropertyHandle)) != 0) 00874 { 00875 LogError("failure in a function that converts from AGENT_DATA_TYPE to C data"); 00876 } 00877 else 00878 { 00879 /*Codes_SRS_COMMAND_DECODER_02_013: [ If the desired property has a non-NULL pfOnDesiredProperty then it shall be called. ]*/ 00880 pfOnDesiredProperty onDesiredProperty = Schema_GetModelDesiredProperty_pfOnDesiredProperty(desiredPropertyHandle); 00881 if (onDesiredProperty != NULL) 00882 { 00883 onDesiredProperty((char*)startAddress + offset); 00884 } 00885 nProcessedChildren++; 00886 } 00887 Destroy_AGENT_DATA_TYPE(&output); 00888 } 00889 00890 break; 00891 } 00892 case(SCHEMA_MODEL_IN_MODEL): 00893 { 00894 SCHEMA_MODEL_TYPE_HANDLE modelModel = elementType.elementHandle.modelHandle; 00895 00896 /*Codes_SRS_COMMAND_DECODER_02_009: [ If the child name corresponds to a model in model then the function shall call itself recursively. ]*/ 00897 if (!validateModel_vs_Multitree(startAddress, modelModel, child, offset + Schema_GetModelModelByName_Offset(modelHandle, childName_str))) 00898 { 00899 LogError("failure in validateModel_vs_Multitree"); 00900 i = nChildren; 00901 } 00902 else 00903 { 00904 /*if the model in model so happened to be a WITH_DESIRED_PROPERTY... (only those has non_NULL pfOnDesiredProperty) */ 00905 /*Codes_SRS_COMMAND_DECODER_02_012: [ If the child model in model has a non-NULL pfOnDesiredProperty then pfOnDesiredProperty shall be called. ]*/ 00906 pfOnDesiredProperty onDesiredProperty = Schema_GetModelModelByName_OnDesiredProperty(modelHandle, childName_str); 00907 if (onDesiredProperty != NULL) 00908 { 00909 onDesiredProperty((char*)startAddress + offset); 00910 } 00911 00912 nProcessedChildren++; 00913 } 00914 00915 break; 00916 } 00917 00918 } /*switch*/ 00919 } 00920 STRING_delete(childName); 00921 } 00922 } 00923 } 00924 00925 if(nProcessedChildren == nChildren) 00926 { 00927 /*Codes_SRS_COMMAND_DECODER_02_010: [ If the complete MULTITREE has been parsed then CommandDecoder_IngestDesiredProperties shall succeed and return EXECUTE_COMMAND_SUCCESS. ]*/ 00928 result = true; 00929 } 00930 else 00931 { 00932 /*Codes_SRS_COMMAND_DECODER_02_011: [ Otherwise CommandDecoder_IngestDesiredProperties shall fail and return EXECUTE_COMMAND_FAILED. ]*/ 00933 LogError("not all constituents of the JSON have been ingested"); 00934 result = false; 00935 } 00936 return result; 00937 } 00938 00939 static EXECUTE_COMMAND_RESULT DecodeDesiredProperties(void* startAddress, COMMAND_DECODER_HANDLE_DATA* handle, MULTITREE_HANDLE desiredPropertiesTree) 00940 { 00941 /*Codes_SRS_COMMAND_DECODER_02_006: [ CommandDecoder_IngestDesiredProperties shall parse the MULTITREEE recursively. ]*/ 00942 return validateModel_vs_Multitree(startAddress, handle->ModelHandle, desiredPropertiesTree, 0 )?EXECUTE_COMMAND_SUCCESS:EXECUTE_COMMAND_FAILED; 00943 } 00944 00945 /* Raw JSON has properties we don't need; potentially nodes other than "desired" for full TWIN as well as a $version we don't pass to callees */ 00946 static bool RemoveUnneededTwinProperties(MULTITREE_HANDLE initialParsedTree, bool parseDesiredNode, MULTITREE_HANDLE *desiredPropertiesTree) 00947 { 00948 MULTITREE_HANDLE updateTree; 00949 bool result; 00950 00951 if (parseDesiredNode) 00952 { 00953 /*Codes_SRS_COMMAND_DECODER_02_014: [ If parseDesiredNode is TRUE, parse only the `desired` part of JSON tree ]*/ 00954 if (MultiTree_GetChildByName(initialParsedTree, "desired", &updateTree) != MULTITREE_OK) 00955 { 00956 LogError("Unable to find 'desired' in tree"); 00957 return false; 00958 } 00959 } 00960 else 00961 { 00962 // Tree already starts on node we want so just use it. 00963 updateTree = initialParsedTree; 00964 } 00965 00966 /*Codes_COMMAND_DECODER_02_015: [ Remove '$version' string from node, if it is present. It not being present is not an error ]*/ 00967 MULTITREE_RESULT deleteChildResult = MultiTree_DeleteChild(updateTree, "$version"); 00968 if ((deleteChildResult == MULTITREE_OK) || (deleteChildResult == MULTITREE_CHILD_NOT_FOUND)) 00969 { 00970 *desiredPropertiesTree = updateTree; 00971 result = true; 00972 } 00973 else 00974 { 00975 *desiredPropertiesTree = NULL; 00976 result = false; 00977 } 00978 00979 return result; 00980 } 00981 00982 EXECUTE_COMMAND_RESULT CommandDecoder_IngestDesiredProperties(void* startAddress, COMMAND_DECODER_HANDLE handle, const char* jsonPayload, bool parseDesiredNode) 00983 { 00984 EXECUTE_COMMAND_RESULT result; 00985 00986 /*Codes_SRS_COMMAND_DECODER_02_001: [ If startAddress is NULL then CommandDecoder_IngestDesiredProperties shall fail and return EXECUTE_COMMAND_ERROR. ]*/ 00987 /*Codes_SRS_COMMAND_DECODER_02_002: [ If handle is NULL then CommandDecoder_IngestDesiredProperties shall fail and return EXECUTE_COMMAND_ERROR. ]*/ 00988 /*Codes_SRS_COMMAND_DECODER_02_003: [ If jsonPayload is NULL then CommandDecoder_IngestDesiredProperties shall fail and return EXECUTE_COMMAND_ERROR. ]*/ 00989 if( 00990 (startAddress == NULL) || 00991 (handle == NULL) || 00992 (jsonPayload == NULL) 00993 ) 00994 { 00995 LogError("invalid argument COMMAND_DECODER_HANDLE handle=%p, const char* jsonPayload=%p", handle, jsonPayload); 00996 result = EXECUTE_COMMAND_ERROR; 00997 } 00998 else 00999 { 01000 /*Codes_SRS_COMMAND_DECODER_02_004: [ CommandDecoder_IngestDesiredProperties shall clone desiredProperties. ]*/ 01001 char* copy; 01002 if (mallocAndStrcpy_s(©, jsonPayload) != 0) 01003 { 01004 LogError("failure in mallocAndStrcpy_s"); 01005 result = EXECUTE_COMMAND_FAILED; 01006 } 01007 else 01008 { 01009 /*Codes_SRS_COMMAND_DECODER_02_005: [ CommandDecoder_IngestDesiredProperties shall create a MULTITREE_HANDLE ouf of the clone of desiredProperties. ]*/ 01010 MULTITREE_HANDLE initialParsedTree; 01011 MULTITREE_HANDLE desiredPropertiesTree; 01012 01013 if (JSONDecoder_JSON_To_MultiTree(copy, &initialParsedTree) != JSON_DECODER_OK) 01014 { 01015 LogError("Decoding JSON to a multi tree failed"); 01016 result = EXECUTE_COMMAND_ERROR; 01017 } 01018 else 01019 { 01020 if (RemoveUnneededTwinProperties(initialParsedTree, parseDesiredNode, &desiredPropertiesTree) == false) 01021 { 01022 LogError("Removing unneeded twin properties failed"); 01023 result = EXECUTE_COMMAND_ERROR; 01024 } 01025 else 01026 { 01027 COMMAND_DECODER_HANDLE_DATA* commandDecoderInstance = (COMMAND_DECODER_HANDLE_DATA*)handle; 01028 01029 /*Codes_SRS_COMMAND_DECODER_02_006: [ CommandDecoder_IngestDesiredProperties shall parse the MULTITREEE recursively. ]*/ 01030 result = DecodeDesiredProperties(startAddress, commandDecoderInstance, desiredPropertiesTree); 01031 01032 // Do NOT free desiredPropertiesTree. It is only a pointer into initialParsedTree. 01033 MultiTree_Destroy(initialParsedTree); 01034 } 01035 } 01036 free(copy); 01037 } 01038 } 01039 return result; 01040 }
Generated on Tue Jul 12 2022 19:56:37 by
1.7.2