void ValueTinyint::setInt8Value(int8_t value) { deleteValue(); m_value = new int8_t( value ); setValueLen(1); }
ValueLongBlock::ValueLongBlock( long_data_t long_data ): Value( 10 ), m_raw_data( 0 ) { setLongData( long_data ); setValueLen( 0 ); m_is_long_data = true; }
static void typeCompletion(const char *buf, size_t bufLength, linenoiseCompletions *lc, uint8_t actionCode, const char *nodeString, size_t nodeStringLength, const char *keyString, size_t keyStringLength, const char *partialTypeString, size_t partialTypeStringLength) { UNUSED_ARGUMENT(actionCode); uint8_t dataBuffer[1024]; // Send request for all type names for this key on this node. dataBuffer[0] = GET_TYPES; dataBuffer[1] = 0; // UNUSED. setExtraLen(dataBuffer, 0); // UNUSED. setNodeLen(dataBuffer, (uint16_t) (nodeStringLength + 1)); // +1 for terminating NUL byte. setKeyLen(dataBuffer, (uint16_t) (keyStringLength + 1)); // +1 for terminating NUL byte. setValueLen(dataBuffer, 0); // UNUSED. memcpy(dataBuffer + 10, nodeString, nodeStringLength); dataBuffer[10 + nodeStringLength] = '\0'; memcpy(dataBuffer + 10 + nodeStringLength + 1, keyString, keyStringLength); dataBuffer[10 + nodeStringLength + 1 + keyStringLength] = '\0'; if (!sendUntilDone(sockFd, dataBuffer, 10 + nodeStringLength + 1 + keyStringLength + 1)) { // Failed to contact remote host, no auto-completion! return; } if (!recvUntilDone(sockFd, dataBuffer, 4)) { // Failed to contact remote host, no auto-completion! return; } // Decode response header fields (all in little-endian). uint8_t action = dataBuffer[0]; uint8_t type = dataBuffer[1]; uint16_t msgLength = le16toh(*(uint16_t * )(dataBuffer + 2)); // Total length to get for response. if (!recvUntilDone(sockFd, dataBuffer + 4, msgLength)) { // Failed to contact remote host, no auto-completion! return; } if (action == ERROR || type != STRING) { // Invalid request made, no auto-completion. return; } // At this point we made a valid request and got back a full response. for (size_t i = 0; i < msgLength; i++) { if (strncasecmp((const char *) dataBuffer + 4 + i, partialTypeString, partialTypeStringLength) == 0) { linenoiseAddCompletionSuffix(lc, buf, bufLength - partialTypeStringLength, (const char *) dataBuffer + 4 + i, true, false); } // Jump to the NUL character after this string. i += strlen((const char *) dataBuffer + 4 + i); } }
ValueLongBlock::ValueLongBlock() : Value( 10 ), m_raw_data( 0 ) { setValueLen( 0 ); m_is_long_data = true; m_long_data.raw_data = NULL; m_long_data.total_len = 0; }
void ValueTinyint::deleteValue() { if (m_raw_data) delete [] m_raw_data; if (m_value) { delete (int8_t*) m_value; setValueLen(0); } }
void ValueLongBlock::setLongDataInfo(const long_data_info_t& long_data_info) { deleteValue(); m_value = new long_data_info_t; ( ( long_data_info_t* ) m_value )->page_id = long_data_info.page_id; ( ( long_data_info_t* ) m_value )->nr = long_data_info.nr; ( ( long_data_info_t* ) m_value )->total_len = long_data_info.total_len; if (long_data_info.total_len > 0) { setValueLen( 10 ); } else { setValueLen( 0 ); } }
void ValueTinyint::setRawData(const uint8_t* data, uint16_t len) { deleteValue(); if ( len == 1 ) { int8_t val = ( ( ( int32_t ) ( data[0] ) ) ); setInt8Value(val); } else { setValueLen( 0 ); } }
ValueTinyint::ValueTinyint() : ValueIncrementable( 1 ), m_raw_data( 0 ) { setType( TINYINT_TYPE ); setValueLen( 0 ); }
static void valueCompletion(const char *buf, size_t bufLength, linenoiseCompletions *lc, uint8_t actionCode, const char *nodeString, size_t nodeStringLength, const char *keyString, size_t keyStringLength, const char *typeString, size_t typeStringLength, const char *partialValueString, size_t partialValueStringLength) { UNUSED_ARGUMENT(actionCode); UNUSED_ARGUMENT(typeStringLength); enum sshs_node_attr_value_type type = sshsHelperStringToTypeConverter(typeString); if (type == UNKNOWN) { // Invalid type, no auto-completion. return; } if (partialValueStringLength != 0) { // If there already is content, we can't do any auto-completion here, as // we have no idea about what a valid value would be to complete ... // Unless this is a boolean, then we can propose true/false strings. if (type == BOOL) { if (strncmp("true", partialValueString, partialValueStringLength) == 0) { linenoiseAddCompletionSuffix(lc, buf, bufLength - partialValueStringLength, "true", false, false); } if (strncmp("false", partialValueString, partialValueStringLength) == 0) { linenoiseAddCompletionSuffix(lc, buf, bufLength - partialValueStringLength, "false", false, false); } } return; } uint8_t dataBuffer[1024]; // Send request for the current value, so we can auto-complete with it as default. dataBuffer[0] = GET; dataBuffer[1] = (uint8_t) type; setExtraLen(dataBuffer, 0); // UNUSED. setNodeLen(dataBuffer, (uint16_t) (nodeStringLength + 1)); // +1 for terminating NUL byte. setKeyLen(dataBuffer, (uint16_t) (keyStringLength + 1)); // +1 for terminating NUL byte. setValueLen(dataBuffer, 0); // UNUSED. memcpy(dataBuffer + 10, nodeString, nodeStringLength); dataBuffer[10 + nodeStringLength] = '\0'; memcpy(dataBuffer + 10 + nodeStringLength + 1, keyString, keyStringLength); dataBuffer[10 + nodeStringLength + 1 + keyStringLength] = '\0'; if (!sendUntilDone(sockFd, dataBuffer, 10 + nodeStringLength + 1 + keyStringLength + 1)) { // Failed to contact remote host, no auto-completion! return; } if (!recvUntilDone(sockFd, dataBuffer, 4)) { // Failed to contact remote host, no auto-completion! return; } // Decode response header fields (all in little-endian). uint8_t action = dataBuffer[0]; uint16_t msgLength = le16toh(*(uint16_t * )(dataBuffer + 2)); // Total length to get for response. if (!recvUntilDone(sockFd, dataBuffer + 4, msgLength)) { // Failed to contact remote host, no auto-completion! return; } if (action == ERROR) { // Invalid request made, no auto-completion. return; } // At this point we made a valid request and got back a full response. // We can just use it directly and paste it in as completion. linenoiseAddCompletionSuffix(lc, buf, bufLength, (const char *) dataBuffer + 4, false, false); // If this is a boolean value, we can also add the inverse as a second completion. if (type == BOOL) { if (strcmp((const char *) dataBuffer + 4, "true") == 0) { linenoiseAddCompletionSuffix(lc, buf, bufLength, "false", false, false); } else { linenoiseAddCompletionSuffix(lc, buf, bufLength, "true", false, false); } } }
static void nodeCompletion(const char *buf, size_t bufLength, linenoiseCompletions *lc, uint8_t actionCode, const char *partialNodeString, size_t partialNodeStringLength) { UNUSED_ARGUMENT(actionCode); // If partialNodeString is still empty, the first thing is to complete the root. if (partialNodeStringLength == 0) { linenoiseAddCompletionSuffix(lc, buf, bufLength, "/", false, false); return; } // Get all the children of the last fully defined node (/ or /../../). char *lastNode = strrchr(partialNodeString, '/'); if (lastNode == NULL) { // No / found, invalid, cannot auto-complete. return; } size_t lastNodeLength = (size_t) (lastNode - partialNodeString) + 1; uint8_t dataBuffer[1024]; // Send request for all children names. dataBuffer[0] = GET_CHILDREN; dataBuffer[1] = 0; // UNUSED. setExtraLen(dataBuffer, 0); // UNUSED. setNodeLen(dataBuffer, (uint16_t) (lastNodeLength + 1)); // +1 for terminating NUL byte. setKeyLen(dataBuffer, 0); // UNUSED. setValueLen(dataBuffer, 0); // UNUSED. memcpy(dataBuffer + 10, partialNodeString, lastNodeLength); dataBuffer[10 + lastNodeLength] = '\0'; if (!sendUntilDone(sockFd, dataBuffer, 10 + lastNodeLength + 1)) { // Failed to contact remote host, no auto-completion! return; } if (!recvUntilDone(sockFd, dataBuffer, 4)) { // Failed to contact remote host, no auto-completion! return; } // Decode response header fields (all in little-endian). uint8_t action = dataBuffer[0]; uint8_t type = dataBuffer[1]; uint16_t msgLength = le16toh(*(uint16_t * )(dataBuffer + 2)); // Total length to get for response. if (!recvUntilDone(sockFd, dataBuffer + 4, msgLength)) { // Failed to contact remote host, no auto-completion! return; } if (action == ERROR || type != STRING) { // Invalid request made, no auto-completion. return; } // At this point we made a valid request and got back a full response. for (size_t i = 0; i < msgLength; i++) { if (strncasecmp((const char *) dataBuffer + 4 + i, lastNode + 1, strlen(lastNode + 1)) == 0) { linenoiseAddCompletionSuffix(lc, buf, bufLength - strlen(lastNode + 1), (const char *) dataBuffer + 4 + i, false, true); } // Jump to the NUL character after this string. i += strlen((const char *) dataBuffer + 4 + i); } }
static void handleInputLine(const char *buf, size_t bufLength) { // First let's split up the command into its constituents. char *commandParts[MAX_CMD_PARTS + 1] = { NULL }; // Create a copy of buf, so that strtok_r() can modify it. char bufCopy[bufLength + 1]; strcpy(bufCopy, buf); // Split string into usable parts. size_t idx = 0; char *tokenSavePtr = NULL, *nextCmdPart = NULL, *currCmdPart = bufCopy; while ((nextCmdPart = strtok_r(currCmdPart, " ", &tokenSavePtr)) != NULL) { if (idx < MAX_CMD_PARTS) { commandParts[idx] = nextCmdPart; } else { // Abort, too many parts. fprintf(stderr, "Error: command is made up of too many parts.\n"); return; } idx++; currCmdPart = NULL; } // Check that we got something. if (commandParts[CMD_PART_ACTION] == NULL) { fprintf(stderr, "Error: empty command.\n"); return; } // Let's get the action code first thing. uint8_t actionCode = UINT8_MAX; for (size_t i = 0; i < actionsLength; i++) { if (strcmp(commandParts[CMD_PART_ACTION], actions[i].name) == 0) { actionCode = actions[i].code; } } // Control message format: 1 byte ACTION, 1 byte TYPE, 2 bytes EXTRA_LEN, // 2 bytes NODE_LEN, 2 bytes KEY_LEN, 2 bytes VALUE_LEN, then up to 4086 // bytes split between EXTRA, NODE, KEY, VALUE (with 4 bytes for NUL). // Basically: (EXTRA_LEN + NODE_LEN + KEY_LEN + VALUE_LEN) <= 4086. // EXTRA, NODE, KEY, VALUE have to be NUL terminated, and their length // must include the NUL termination byte. // This results in a maximum message size of 4096 bytes (4KB). uint8_t dataBuffer[4096]; size_t dataBufferLength = 0; // Now that we know what we want to do, let's decode the command line. switch (actionCode) { case NODE_EXISTS: { // Check parameters needed for operation. if (commandParts[CMD_PART_NODE] == NULL) { fprintf(stderr, "Error: missing node parameter.\n"); return; } if (commandParts[CMD_PART_NODE + 1] != NULL) { fprintf(stderr, "Error: too many parameters for command.\n"); return; } size_t nodeLength = strlen(commandParts[CMD_PART_NODE]) + 1; // +1 for terminating NUL byte. dataBuffer[0] = actionCode; dataBuffer[1] = 0; // UNUSED. setExtraLen(dataBuffer, 0); // UNUSED. setNodeLen(dataBuffer, (uint16_t) nodeLength); setKeyLen(dataBuffer, 0); // UNUSED. setValueLen(dataBuffer, 0); // UNUSED. memcpy(dataBuffer + 10, commandParts[CMD_PART_NODE], nodeLength); dataBufferLength = 10 + nodeLength; break; } case ATTR_EXISTS: case GET: { // Check parameters needed for operation. if (commandParts[CMD_PART_NODE] == NULL) { fprintf(stderr, "Error: missing node parameter.\n"); return; } if (commandParts[CMD_PART_KEY] == NULL) { fprintf(stderr, "Error: missing key parameter.\n"); return; } if (commandParts[CMD_PART_TYPE] == NULL) { fprintf(stderr, "Error: missing type parameter.\n"); return; } if (commandParts[CMD_PART_TYPE + 1] != NULL) { fprintf(stderr, "Error: too many parameters for command.\n"); return; } size_t nodeLength = strlen(commandParts[CMD_PART_NODE]) + 1; // +1 for terminating NUL byte. size_t keyLength = strlen(commandParts[CMD_PART_KEY]) + 1; // +1 for terminating NUL byte. enum sshs_node_attr_value_type type = sshsHelperStringToTypeConverter(commandParts[CMD_PART_TYPE]); if (type == UNKNOWN) { fprintf(stderr, "Error: invalid type parameter.\n"); return; } dataBuffer[0] = actionCode; dataBuffer[1] = (uint8_t) type; setExtraLen(dataBuffer, 0); // UNUSED. setNodeLen(dataBuffer, (uint16_t) nodeLength); setKeyLen(dataBuffer, (uint16_t) keyLength); setValueLen(dataBuffer, 0); // UNUSED. memcpy(dataBuffer + 10, commandParts[CMD_PART_NODE], nodeLength); memcpy(dataBuffer + 10 + nodeLength, commandParts[CMD_PART_KEY], keyLength); dataBufferLength = 10 + nodeLength + keyLength; break; } case PUT: { // Check parameters needed for operation. if (commandParts[CMD_PART_NODE] == NULL) { fprintf(stderr, "Error: missing node parameter.\n"); return; } if (commandParts[CMD_PART_KEY] == NULL) { fprintf(stderr, "Error: missing key parameter.\n"); return; } if (commandParts[CMD_PART_TYPE] == NULL) { fprintf(stderr, "Error: missing type parameter.\n"); return; } if (commandParts[CMD_PART_VALUE] == NULL) { fprintf(stderr, "Error: missing value parameter.\n"); return; } if (commandParts[CMD_PART_VALUE + 1] != NULL) { fprintf(stderr, "Error: too many parameters for command.\n"); return; } size_t nodeLength = strlen(commandParts[CMD_PART_NODE]) + 1; // +1 for terminating NUL byte. size_t keyLength = strlen(commandParts[CMD_PART_KEY]) + 1; // +1 for terminating NUL byte. size_t valueLength = strlen(commandParts[CMD_PART_VALUE]) + 1; // +1 for terminating NUL byte. enum sshs_node_attr_value_type type = sshsHelperStringToTypeConverter(commandParts[CMD_PART_TYPE]); if (type == UNKNOWN) { fprintf(stderr, "Error: invalid type parameter.\n"); return; } dataBuffer[0] = actionCode; dataBuffer[1] = (uint8_t) type; setExtraLen(dataBuffer, 0); // UNUSED. setNodeLen(dataBuffer, (uint16_t) nodeLength); setKeyLen(dataBuffer, (uint16_t) keyLength); setValueLen(dataBuffer, (uint16_t) valueLength); memcpy(dataBuffer + 10, commandParts[CMD_PART_NODE], nodeLength); memcpy(dataBuffer + 10 + nodeLength, commandParts[CMD_PART_KEY], keyLength); memcpy(dataBuffer + 10 + nodeLength + keyLength, commandParts[CMD_PART_VALUE], valueLength); dataBufferLength = 10 + nodeLength + keyLength + valueLength; break; } default: fprintf(stderr, "Error: unknown command.\n"); return; } // Send formatted command to configuration server. if (!sendUntilDone(sockFd, dataBuffer, dataBufferLength)) { fprintf(stderr, "Error: unable to send data to config server (%d).\n", errno); return; } // The response from the server follows a simplified version of the request // protocol. A byte for ACTION, a byte for TYPE, 2 bytes for MSG_LEN and then // up to 4092 bytes of MSG, for a maximum total of 4096 bytes again. // MSG must be NUL terminated, and the NUL byte shall be part of the length. if (!recvUntilDone(sockFd, dataBuffer, 4)) { fprintf(stderr, "Error: unable to receive data from config server (%d).\n", errno); return; } // Decode response header fields (all in little-endian). uint8_t action = dataBuffer[0]; uint8_t type = dataBuffer[1]; uint16_t msgLength = le16toh(*(uint16_t * )(dataBuffer + 2)); // Total length to get for response. if (!recvUntilDone(sockFd, dataBuffer + 4, msgLength)) { fprintf(stderr, "Error: unable to receive data from config server (%d).\n", errno); return; } // Convert action back to a string. const char *actionString = NULL; // Detect error response. if (action == ERROR) { actionString = "error"; } else { for (size_t i = 0; i < actionsLength; i++) { if (actions[i].code == action) { actionString = actions[i].name; } } } // Display results. printf("Result: action=%s, type=%s, msgLength=%" PRIu16 ", msg='%s'.\n", actionString, sshsHelperTypeToStringConverter(type), msgLength, dataBuffer + 4); }