示例#1
0
文件: sshs.cpp 项目: inilabs/caer
void sshsAttributeUpdaterAdd(sshsNode node, const char *key, enum sshs_node_attr_value_type type,
	sshsAttributeUpdater updater, void *updaterUserData) {
	sshs_attribute_updater attrUpdater(node, key, type, updater, updaterUserData);

	sshs tree = sshsNodeGetGlobal(node);
	std::lock_guard<std::mutex> lock(tree->attributeUpdatersLock);

	// Check no other updater already exists that matches this one.
	if (!findBool(tree->attributeUpdaters.begin(), tree->attributeUpdaters.end(), attrUpdater)) {
		// Verify referenced attribute actually exists.
		if (!sshsNodeAttributeExists(node, key, type)) {
			sshsNodeErrorNoAttribute("sshsAttributeUpdaterAdd", key, type);
		}

		tree->attributeUpdaters.push_back(attrUpdater);
	}
}
示例#2
0
static void caerConfigServerHandleRequest(int connectedClientSocket, uint8_t action, uint8_t type, const uint8_t *extra,
	size_t extraLength, const uint8_t *node, size_t nodeLength, const uint8_t *key, size_t keyLength,
	const uint8_t *value, size_t valueLength) {
	UNUSED_ARGUMENT(extra);

	caerLog(CAER_LOG_DEBUG, "Config Server",
		"Handling request: action=%" PRIu8 ", type=%" PRIu8 ", extraLength=%zu, nodeLength=%zu, keyLength=%zu, valueLength=%zu.",
		action, type, extraLength, nodeLength, keyLength, valueLength);

	// Interpretation of data is up to each action individually.
	sshs configStore = sshsGetGlobal();

	switch (action) {
		case NODE_EXISTS: {
			// We only need the node name here. Type is not used (ignored)!
			bool result = sshsExistsNode(configStore, (const char *) node);

			// Send back result to client. Format is the same as incoming data.
			const uint8_t *sendResult = (const uint8_t *) ((result) ? ("true") : ("false"));
			size_t sendResultLength = (result) ? (5) : (6);
			caerConfigSendResponse(connectedClientSocket, NODE_EXISTS, BOOL, sendResult, sendResultLength);

			break;
		}

		case ATTR_EXISTS: {
			bool nodeExists = sshsExistsNode(configStore, (const char *) node);

			// Only allow operations on existing nodes, this is for remote
			// control, so we only manipulate what's already there!
			if (!nodeExists) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket,
					"Node doesn't exist. Operations are only allowed on existing data.");

				break;
			}

			// This cannot fail, since we know the node exists from above.
			sshsNode wantedNode = sshsGetNode(configStore, (const char *) node);

			// Check if attribute exists.
			bool result = sshsNodeAttributeExists(wantedNode, (const char *) key, type);

			// Send back result to client. Format is the same as incoming data.
			const uint8_t *sendResult = (const uint8_t *) ((result) ? ("true") : ("false"));
			size_t sendResultLength = (result) ? (5) : (6);
			caerConfigSendResponse(connectedClientSocket, ATTR_EXISTS, BOOL, sendResult, sendResultLength);

			break;
		}

		case GET: {
			bool nodeExists = sshsExistsNode(configStore, (const char *) node);

			// Only allow operations on existing nodes, this is for remote
			// control, so we only manipulate what's already there!
			if (!nodeExists) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket,
					"Node doesn't exist. Operations are only allowed on existing data.");

				break;
			}

			// This cannot fail, since we know the node exists from above.
			sshsNode wantedNode = sshsGetNode(configStore, (const char *) node);

			// Check if attribute exists. Only allow operations on existing attributes!
			bool attrExists = sshsNodeAttributeExists(wantedNode, (const char *) key, type);

			if (!attrExists) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket,
					"Attribute of given type doesn't exist. Operations are only allowed on existing data.");

				break;
			}

			union sshs_node_attr_value result = sshsNodeGetAttribute(wantedNode, (const char *) key, type);

			char *resultStr = sshsHelperValueToStringConverter(type, result);

			if (resultStr == NULL) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket, "Failed to allocate memory for value string.");
			}
			else {
				caerConfigSendResponse(connectedClientSocket, GET, type, (const uint8_t *) resultStr,
					strlen(resultStr) + 1);

				free(resultStr);
			}

			// If this is a string, we must remember to free the original result.str
			// too, since it will also be a copy of the string coming from SSHS.
			if (type == STRING) {
				free(result.string);
			}

			break;
		}

		case PUT: {
			bool nodeExists = sshsExistsNode(configStore, (const char *) node);

			// Only allow operations on existing nodes, this is for remote
			// control, so we only manipulate what's already there!
			if (!nodeExists) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket,
					"Node doesn't exist. Operations are only allowed on existing data.");

				break;
			}

			// This cannot fail, since we know the node exists from above.
			sshsNode wantedNode = sshsGetNode(configStore, (const char *) node);

			// Check if attribute exists. Only allow operations on existing attributes!
			bool attrExists = sshsNodeAttributeExists(wantedNode, (const char *) key, type);

			if (!attrExists) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket,
					"Attribute of given type doesn't exist. Operations are only allowed on existing data.");

				break;
			}

			// Put given value into config node. Node, attr and type are already verified.
			const char *typeStr = sshsHelperTypeToStringConverter(type);
			if (!sshsNodeStringToNodeConverter(wantedNode, (const char *) key, typeStr, (const char *) value)) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket, "Impossible to convert value according to type.");

				break;
			}

			// Send back confirmation to the client.
			caerConfigSendResponse(connectedClientSocket, PUT, BOOL, (const uint8_t *) "true", 5);

			break;
		}

		case GET_CHILDREN: {
			bool nodeExists = sshsExistsNode(configStore, (const char *) node);

			// Only allow operations on existing nodes, this is for remote
			// control, so we only manipulate what's already there!
			if (!nodeExists) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket,
					"Node doesn't exist. Operations are only allowed on existing data.");

				break;
			}

			// This cannot fail, since we know the node exists from above.
			sshsNode wantedNode = sshsGetNode(configStore, (const char *) node);

			// Get the names of all the child nodes and return them.
			size_t numNames;
			const char **childNames = sshsNodeGetChildNames(wantedNode, &numNames);

			// No children at all, return empty.
			if (childNames == NULL) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket, "Node has no children.");

				break;
			}

			// We need to return a big string with all of the child names,
			// separated by a NUL character.
			size_t namesLength = 0;

			for (size_t i = 0; i < numNames; i++) {
				namesLength += strlen(childNames[i]) + 1; // +1 for terminating NUL byte.
			}

			// Allocate a buffer for the names and copy them over.
			char namesBuffer[namesLength];

			for (size_t i = 0, acc = 0; i < numNames; i++) {
				size_t len = strlen(childNames[i]) + 1;
				memcpy(namesBuffer + acc, childNames[i], len);
				acc += len;
			}

			caerConfigSendResponse(connectedClientSocket, GET_CHILDREN, STRING, (const uint8_t *) namesBuffer,
				namesLength);

			break;
		}

		case GET_ATTRIBUTES: {
			bool nodeExists = sshsExistsNode(configStore, (const char *) node);

			// Only allow operations on existing nodes, this is for remote
			// control, so we only manipulate what's already there!
			if (!nodeExists) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket,
					"Node doesn't exist. Operations are only allowed on existing data.");

				break;
			}

			// This cannot fail, since we know the node exists from above.
			sshsNode wantedNode = sshsGetNode(configStore, (const char *) node);

			// Get the keys of all the attributes and return them.
			size_t numKeys;
			const char **attrKeys = sshsNodeGetAttributeKeys(wantedNode, &numKeys);

			// No attributes at all, return empty.
			if (attrKeys == NULL) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket, "Node has no attributes.");

				break;
			}

			// We need to return a big string with all of the attribute keys,
			// separated by a NUL character.
			size_t keysLength = 0;

			for (size_t i = 0; i < numKeys; i++) {
				keysLength += strlen(attrKeys[i]) + 1; // +1 for terminating NUL byte.
			}

			// Allocate a buffer for the keys and copy them over.
			char keysBuffer[keysLength];

			for (size_t i = 0, acc = 0; i < numKeys; i++) {
				size_t len = strlen(attrKeys[i]) + 1;
				memcpy(keysBuffer + acc, attrKeys[i], len);
				acc += len;
			}

			caerConfigSendResponse(connectedClientSocket, GET_ATTRIBUTES, STRING, (const uint8_t *) keysBuffer,
				keysLength);

			break;
		}

		case GET_TYPES: {
			bool nodeExists = sshsExistsNode(configStore, (const char *) node);

			// Only allow operations on existing nodes, this is for remote
			// control, so we only manipulate what's already there!
			if (!nodeExists) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket,
					"Node doesn't exist. Operations are only allowed on existing data.");

				break;
			}

			// This cannot fail, since we know the node exists from above.
			sshsNode wantedNode = sshsGetNode(configStore, (const char *) node);

			// Check if any keys match the given one and return its types.
			size_t numTypes;
			enum sshs_node_attr_value_type *attrTypes = sshsNodeGetAttributeTypes(wantedNode, (const char *) key,
				&numTypes);

			// No attributes for specified key, return empty.
			if (attrTypes == NULL) {
				// Send back error message to client.
				caerConfigSendError(connectedClientSocket, "Node has no attributes with specified key.");

				break;
			}

			// We need to return a big string with all of the attribute types,
			// separated by a NUL character.
			size_t typesLength = 0;

			for (size_t i = 0; i < numTypes; i++) {
				const char *typeString = sshsHelperTypeToStringConverter(attrTypes[i]);
				typesLength += strlen(typeString) + 1; // +1 for terminating NUL byte.
			}

			// Allocate a buffer for the types and copy them over.
			char typesBuffer[typesLength];

			for (size_t i = 0, acc = 0; i < numTypes; i++) {
				const char *typeString = sshsHelperTypeToStringConverter(attrTypes[i]);
				size_t len = strlen(typeString) + 1;
				memcpy(typesBuffer + acc, typeString, len);
				acc += len;
			}

			caerConfigSendResponse(connectedClientSocket, GET_TYPES, STRING, (const uint8_t *) typesBuffer,
				typesLength);

			break;
		}

		default:
			// Unknown action, send error back to client.
			caerConfigSendError(connectedClientSocket, "Unknown action.");

			break;
	}
}