void test_KineticPDU_Send_should_send_the_PDU_and_return_true_upon_successful_transmission_of_full_PDU_with_value_payload(void) { LOG_LOCATION; ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); uint8_t valueData[128]; ByteBuffer valueBuffer = ByteBuffer_Create(valueData, sizeof(valueData)); ByteBuffer_AppendCString(&valueBuffer, "Some arbitrary value"); KineticEntry entry = {.value = valueBuffer}; KineticPDU_AttachEntry(&PDU, &entry); KineticHMAC_Init_Expect(&PDU.hmac, KINETIC_PROTO_SECURITY_ACL_HMACALGORITHM_HmacSHA1); KineticHMAC_Populate_Expect(&PDU.hmac, &PDU.protoData.message.proto, PDU.connection->session.hmacKey); KineticSocket_Write_ExpectAndReturn(Connection.socket, &headerNBO, KINETIC_STATUS_SUCCESS); KineticSocket_WriteProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS); KineticSocket_Write_ExpectAndReturn(Connection.socket, &PDU.entry.value, KINETIC_STATUS_SUCCESS); TEST_IGNORE_MESSAGE("Need to figure out how to handle address of PDU header"); KineticStatus status = KineticPDU_Send(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); }
void test_kinetic_client_should_store_a_binary_object_split_across_entries_via_overlapped_asynchronous_IO_operations(void) { ByteBuffer test_data = ByteBuffer_Malloc(PAYLOAD_SIZE); ByteBuffer_AppendDummyData(&test_data, test_data.array.len); uint8_t tag_data[] = {0x00, 0x01, 0x02, 0x03}; ByteBuffer tag = ByteBuffer_Create(tag_data, sizeof(tag_data), sizeof(tag_data)); for (size_t i = 0; i < NUM_PUTS; i++) { put_statuses[i] = (PutStatus) { .sem = KineticSemaphore_Create(), .status = KINETIC_STATUS_INVALID, }; }; printf("Waiting for put finish\n"); struct timeval start_time; gettimeofday(&start_time, NULL); for (uint32_t put = 0; put < NUM_PUTS; put++) { keys[put] = put; ByteBuffer key = ByteBuffer_Create(&keys[put], sizeof(keys[put]), sizeof(keys[put])); KineticSynchronization sync = (put == NUM_PUTS - 1) ? KINETIC_SYNCHRONIZATION_FLUSH : KINETIC_SYNCHRONIZATION_WRITEBACK; entries[put] = (KineticEntry) { .key = key, .tag = tag, .algorithm = KINETIC_ALGORITHM_SHA1, .value = test_data, .synchronization = sync, }; KineticStatus status = KineticClient_Put(Fixture.session, &entries[put], &(KineticCompletionClosure) { .callback = put_finished, .clientData = &put_statuses[put], } ); if (status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "PUT failed w/status: %s\n", Kinetic_GetStatusDescription(status)); TEST_FAIL(); } }
void test_KineticPDU_Send_should_send_the_PDU_and_return_true_upon_successful_transmission_of_full_PDU_with_no_value_payload(void) { LOG_LOCATION; KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); KineticEntry entry = {.value = BYTE_BUFFER_NONE}; KineticPDU_AttachEntry(&PDU, &entry); // Create NBO copy of header for sending PDU.headerNBO.versionPrefix = 'F'; PDU.headerNBO.protobufLength = KineticNBO_FromHostU32(KineticProto__get_packed_size(PDU.proto)); PDU.headerNBO.valueLength = 0; KineticHMAC_Init_Expect(&PDU.hmac, KINETIC_PROTO_SECURITY_ACL_HMACALGORITHM_HmacSHA1); KineticHMAC_Populate_Expect(&PDU.hmac, &PDU.protoData.message.proto, PDU.connection->session.hmacKey); KineticSocket_Write_ExpectAndReturn(Connection.socket, &headerNBO, KINETIC_STATUS_SUCCESS); KineticSocket_WriteProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS); TEST_IGNORE_MESSAGE("Need to figure out how to handle address of PDU header"); KineticStatus status = KineticPDU_Send(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); }
void setUp(void) { KineticLogger_Init("stdout", 3); // Configure start and end key buffers StartKey = ByteBuffer_Create(StartKeyData, sizeof(StartKeyData), sizeof(StartKeyData)); EndKey = ByteBuffer_Create(EndKeyData, sizeof(EndKeyData), sizeof(EndKeyData)); // Initialize buffers to hold returned keys in requested range for (int i = 0; i < MAX_KEYS_RETRIEVED; i++) { Keys[i] = ByteBuffer_Create(&KeyRangeData[i], sizeof(KeyRangeData[i]), sizeof(KeyRangeData[i])); char keyBuf[64]; snprintf(keyBuf, sizeof(keyBuf), "key_range_00_%02d", i); ByteBuffer_AppendCString(&Keys[i], keyBuf); } }
void test_KineticClient_GetPrevious_should_expose_memory_errors(void) { uint8_t key[] = "schlage"; ByteBuffer KeyBuffer = ByteBuffer_Create(key, sizeof(key), sizeof(key)); uint8_t value[1024]; ByteBuffer ValueBuffer = ByteBuffer_Create(value, sizeof(value), 0); KineticEntry entry = { .key = KeyBuffer, .value = ValueBuffer, }; KineticAllocator_NewOperation_ExpectAndReturn(&Session, NULL); KineticStatus status = KineticClient_GetPrevious(&Session, &entry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_MEMORY_ERROR, status); }
void test_KineticPDU_Receive_should_receive_a_message_with_no_value_payload_and_forward_status_upon_receipt_of_valid_PDU_with_non_successful_status(void) { LOG_LOCATION; KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); PDU.protoData.message.status.code = KINETIC_PROTO_STATUS_STATUS_CODE_PERM_DATA_ERROR; PDU.protoData.message.status.has_code = true; ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); // Fake value/payload length uint8_t data[1024]; ByteArray expectedValue = {.data = data, .len = sizeof(data)}; ByteArray_FillWithDummyData(expectedValue); KineticEntry entry = {.value = ByteBuffer_CreateWithArray(expectedValue)}; KineticPDU_AttachEntry(&PDU, &entry); PDU.headerNBO.valueLength = KineticNBO_FromHostU32(0); KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS); KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS); KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true); EnableAndSetPDUStatus(&PDU, KINETIC_PROTO_STATUS_STATUS_CODE_PERM_DATA_ERROR); KineticStatus status = KineticPDU_Receive(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DATA_ERROR, status); TEST_ASSERT_EQUAL( KINETIC_PROTO_STATUS_STATUS_CODE_PERM_DATA_ERROR, PDU.protoData.message.status.code); } void test_KineticPDU_Receive_should_receive_a_message_for_the_exchange_and_return_false_upon_failure_to_read_header(void) { LOG_LOCATION; KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_CONNECTION_ERROR); KineticStatus status = KineticPDU_Receive(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_CONNECTION_ERROR, status); }
void test_ByteBuffer_Create_should_create_ByteBuffer_with_specified_array_and_max_length_and_used_bytes(void) { uint8_t data[] = {0x1u, 0x2u, 0x3u, 0x4u}; size_t len = sizeof(data); ByteBuffer buffer = ByteBuffer_Create(data, len, 2); TEST_ASSERT_EQUAL_PTR(data, buffer.array.data); TEST_ASSERT_EQUAL(len, buffer.array.len); TEST_ASSERT_EQUAL_HEX8_ARRAY(data, buffer.array.data, len); TEST_ASSERT_EQUAL(2, buffer.bytesUsed); }
void test_KineticClient_GetPrevious_should_execute_GETNEXT(void) { uint8_t key[] = "schlage"; ByteBuffer KeyBuffer = ByteBuffer_Create(key, sizeof(key), sizeof(key)); uint8_t value[1024]; ByteBuffer ValueBuffer = ByteBuffer_Create(value, sizeof(value), 0); KineticEntry entry = { .key = KeyBuffer, .value = ValueBuffer, }; KineticOperation operation; KineticAllocator_NewOperation_ExpectAndReturn(&Session, &operation); KineticBuilder_BuildGetPrevious_ExpectAndReturn(&operation, &entry, KINETIC_STATUS_SUCCESS); KineticController_ExecuteOperation_ExpectAndReturn(&operation, NULL, KINETIC_STATUS_SUCCESS); KineticStatus status = KineticClient_GetPrevious(&Session, &entry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); }
void test_KineticPDU_Receive_should_receive_a_message_for_the_exchange_and_return_false_upon_failure_to_read_protobuf(void) { LOG_LOCATION; KineticPDU_Init(&PDU, &Connection); PDU.protoData.message.status.code = KINETIC_PROTO_STATUS_STATUS_CODE_PERM_DATA_ERROR; PDU.protoData.message.status.has_code = true; ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); PDU.headerNBO = (KineticPDUHeader) { .versionPrefix = (uint8_t)'F', .protobufLength = KineticNBO_FromHostU32(12), .valueLength = 0 }; KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS); KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_DEVICE_BUSY); KineticStatus status = KineticPDU_Receive(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DEVICE_BUSY, status) } void test_KineticPDU_Receive_should_receive_a_message_for_the_exchange_and_return_false_upon_HMAC_validation_failure(void) { LOG_LOCATION; KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS); KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS); KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, false); KineticStatus status = KineticPDU_Receive(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DATA_ERROR, status); }
void test_KineticPDU_Receive_should_receive_a_message_with_no_value_payload_and_return_true_upon_successful_receipt_of_valid_PDU(void) { LOG_LOCATION; Connection.connectionID = 98765; KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS); KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS); KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true); EnableAndSetPDUConnectionID(&PDU, 12345); EnableAndSetPDUStatus(&PDU, KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS); KineticStatus status = KineticPDU_Receive(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); TEST_ASSERT_EQUAL(KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS, PDU.protoData.message.status.code); }
KineticStatus KineticSocket_ReadProtobuf(int socket, KineticPDU* pdu) { size_t bytesToRead = pdu->header.protobufLength; #ifdef KINETIC_LOG_SOCKET_OPERATIONS LOGF("Reading %zd bytes of protobuf", bytesToRead); #endif uint8_t* packed = (uint8_t*)malloc(bytesToRead); if (packed == NULL) { LOG("Failed allocating memory for protocol buffer"); return KINETIC_STATUS_MEMORY_ERROR; } ByteBuffer recvBuffer = ByteBuffer_Create(packed, bytesToRead); KineticStatus status = KineticSocket_Read(socket, &recvBuffer, bytesToRead); if (status != KINETIC_STATUS_SUCCESS) { LOG("Protobuf read failed!"); free(packed); return status; } else { pdu->proto = KineticProto__unpack( NULL, recvBuffer.bytesUsed, recvBuffer.array.data); } free(packed); if (pdu->proto == NULL) { pdu->protobufDynamicallyExtracted = false; LOG("Error unpacking incoming Kinetic protobuf message!"); return KINETIC_STATUS_DATA_ERROR; } else { pdu->protobufDynamicallyExtracted = true; #ifdef KINETIC_LOG_SOCKET_OPERATIONS LOG("Protobuf unpacked successfully!"); #endif return KINETIC_STATUS_SUCCESS; } }
KineticStatus KineticSocket_WriteProtobuf(int socket, KineticPDU* pdu) { assert(pdu != NULL); LOGF1("Writing protobuf (%zd bytes)...", pdu->header.protobufLength); uint8_t* packed = (uint8_t*)malloc(pdu->header.protobufLength); if (packed == NULL) { LOG0("Failed allocating memory for protocol buffer"); return KINETIC_STATUS_MEMORY_ERROR; } size_t len = KineticProto_Message__pack(&pdu->protoData.message.message, packed); assert(len == pdu->header.protobufLength); ByteBuffer buffer = ByteBuffer_Create(packed, len, len); KineticStatus status = KineticSocket_Write(socket, &buffer); free(packed); return status; }
KineticStatus KineticSocket_WriteProtobuf(int socket, KineticPDU* pdu) { assert(pdu != NULL); #ifdef KINETIC_LOG_SOCKET_OPERATIONS LOGF("Writing protobuf (%zd bytes)...", pdu->header.protobufLength); #endif uint8_t* packed = (uint8_t*)malloc(pdu->header.protobufLength); if (packed == NULL) { LOG("Failed allocating memory for protocol buffer"); return KINETIC_STATUS_MEMORY_ERROR; } size_t len = KineticProto__pack(&pdu->protoData.message.proto, packed); assert(len == pdu->header.protobufLength); ByteBuffer buffer = ByteBuffer_Create(packed, len); buffer.bytesUsed = len; KineticStatus status = KineticSocket_Write(socket, &buffer); free(packed); return status; }
peerConfig.port = GetSystemTestPort2(); status = KineticClient_CreateSession(&peerConfig, client, &peerSession); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); KineticSessionConfig peerAdminConfig = { .clusterVersion = 0, .useSsl = true, .identity = 1, .hmacKey = ByteArray_CreateWithCString(HmacKeyString), }; strncpy(peerAdminConfig.host, GetSystemTestHost2(), sizeof(peerAdminConfig.host)-1); peerAdminConfig.port = GetSystemTestTlsPort2(); status = KineticAdminClient_CreateSession(&peerAdminConfig, client, &peerAdminSession); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); // Create some test entries to have content to copy TagBuffer = ByteBuffer_Create(dummyTagData, sizeof(dummyTagData), sizeof(dummyTagData)); Key1Buffer = ByteBuffer_Create(key1Data, sizeof(key1Data), sizeof(key1Data)); Value1Buffer = ByteBuffer_Create(value1Data, sizeof(value1Data), sizeof(value1Data)); KineticEntry putEntry1 = { .key = Key1Buffer, .tag = TagBuffer, .algorithm = KINETIC_ALGORITHM_SHA1, .value = Value1Buffer, .force = true, .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH, }; status = KineticClient_Put(session, &putEntry1, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); Key2Buffer = ByteBuffer_Create(key2Data, sizeof(key2Data), sizeof(key2Data)); Value2Buffer = ByteBuffer_Create(value2Data, sizeof(value2Data), sizeof(value2Data)); KineticEntry putEntry2 = {
static void do_put_and_getkeyrange(KineticSession * const session) { for (int i = 0; i < 5; i++) { char key[] = "keyX"; key[3] = '0' + i; ByteBuffer put_key_buf = ByteBuffer_MallocAndAppend(key, strlen(key)); uint8_t value[] = "valueX"; value[5] = '0' + i; ByteBuffer put_value_buf = ByteBuffer_MallocAndAppend(value, sizeof(value)); /* Populate tag with SHA1 of value */ ByteBuffer put_tag_buf = ByteBuffer_Malloc(20); uint8_t sha1[20]; SHA1(put_value_buf.array.data, put_value_buf.bytesUsed, &sha1[0]); ByteBuffer_Append(&put_tag_buf, sha1, sizeof(sha1)); KineticEntry put_entry = { .key = put_key_buf, .value = put_value_buf, .tag = put_tag_buf, .algorithm = KINETIC_ALGORITHM_SHA1, /* Set sync to WRITETHROUGH, which will wait to complete * until the drive has persistend the write. (WRITEBACK * returns as soon as the drive has buffered the write.) */ .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH, }; /* Put "keyX" => "valueX", where 'X' is 0..4. * This will block, because the callback field (arg 3) is NULL. */ KineticStatus status = KineticClient_Put(session, &put_entry, NULL); printf("Put status: %s\n", Kinetic_GetStatusDescription(status)); ByteBuffer_Free(put_key_buf); ByteBuffer_Free(put_value_buf); ByteBuffer_Free(put_tag_buf); } const size_t max_key_count = 5; const size_t max_key_length = 64; uint8_t first_key[max_key_length]; uint8_t last_key[max_key_length]; KineticKeyRange range = { .startKey = ByteBuffer_CreateAndAppendCString(first_key, sizeof(first_key), "key"), .endKey = ByteBuffer_CreateAndAppendCString(last_key, sizeof(last_key), "key\xFF"), .startKeyInclusive = true, .endKeyInclusive = true, .maxReturned = max_key_count, }; uint8_t key_mem[max_key_count][max_key_length]; memset(key_mem, 0, sizeof(key_mem)); ByteBuffer key_buffers[max_key_count]; for (size_t i = 0; i < max_key_count; i++) { key_buffers[i] = ByteBuffer_Create(&key_buffers[i], max_key_length, 0); } ByteBufferArray keys = { .buffers = key_buffers, .count = max_key_count, }; /* Request the key range as specified in &range, populating the keys in &keys. */ KineticStatus status = KineticClient_GetKeyRange(session, &range, &keys, NULL); printf("GetKeyRange status: %s\n", Kinetic_GetStatusDescription(status)); if (status == KINETIC_STATUS_SUCCESS) { for (size_t i = 0; i < max_key_count; i++) { printf("%zd: %s\n", i, key_buffers[i].array.data); } } /* No cleanup necessary */ } int main(int argc, char** argv) { (void)argc; (void)argv; // Initialize kinetic-c and configure sessions KineticSession* session; KineticClientConfig clientConfig = { .logFile = "stdout", .logLevel = 1, }; KineticClient * client = KineticClient_Init(&clientConfig); if (client == NULL) { return 1; } const char HmacKeyString[] = "asdfasdf"; KineticSessionConfig sessionConfig = { .host = "localhost", .port = KINETIC_PORT, .clusterVersion = 0, .identity = 1, .hmacKey = ByteArray_CreateWithCString(HmacKeyString), }; KineticStatus status = KineticClient_CreateSession(&sessionConfig, client, &session); if (status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n", Kinetic_GetStatusDescription(status)); exit(1); } do_put_and_getkeyrange(session); // Shutdown client connection and cleanup KineticClient_DestroySession(session); KineticClient_Shutdown(client); return 0; }
void ConfigureEntry(struct UtilConfig * cfg, const char* key, const char* tag, const char* version, KineticAlgorithm algorithm, bool force, const char* value) { assert(cfg != NULL); // Setup to write some test data cfg->entry = (KineticEntry) { .key = ByteBuffer_CreateAndAppendCString(cfg->keyData, sizeof(cfg->keyData), key), .tag = ByteBuffer_CreateAndAppendCString(cfg->tagData, sizeof(cfg->tagData), tag), .newVersion = ByteBuffer_CreateAndAppendCString(cfg->newVersionData, sizeof(cfg->newVersionData), version), .dbVersion = ByteBuffer_Create(cfg->versionData, sizeof(cfg->versionData), 0), .algorithm = algorithm, .value = ByteBuffer_CreateAndAppendCString(cfg->valueData, sizeof(cfg->valueData), value), .force = force, }; } int ParseOptions( const int argc, char** const argv, struct UtilConfig * cfg) { // Create an ArgP processor to parse arguments struct { OptionID opID; int logLevel; char host[HOST_NAME_MAX]; int port; int tlsPort; int64_t clusterVersion; int64_t identity; char hmacKey[KINETIC_MAX_KEY_LEN]; char logType[64]; char deviceLogName[64]; char key[64]; char version[64]; char tag[64]; KineticAlgorithm algorithm; bool force; char value[1024]; } opts = { .logLevel = 0, .host = "localhost", .port = KINETIC_PORT, .tlsPort = KINETIC_TLS_PORT, .clusterVersion = 0, .identity = 1, .hmacKey = "asdfasdf", .logType = "utilizations", .key = "foo", .tag = "SomeTagValue", .algorithm = KINETIC_ALGORITHM_SHA1, .force = true, .value = "Hello!", }; // Create configuration for long format options struct option long_options[] = { // Help {"help", no_argument, 0, OPT_HELP}, // Commands {"noop", no_argument, 0, OPT_NOOP}, {"put", no_argument, 0, OPT_PUT}, {"get", no_argument, 0, OPT_GET}, {"delete", no_argument, 0, OPT_DELETE}, {"getnext", no_argument, 0, OPT_GETNEXT}, {"getprevious", no_argument, 0, OPT_GETPREVIOUS}, {"getlog", no_argument, 0, OPT_GETLOG}, {"getdevicespecificlog", no_argument, 0, OPT_GETDEVICESPECIFICLOG}, {"seterasepin", no_argument, 0, OPT_SETERASEPIN}, {"instanterase", no_argument, 0, OPT_INSTANTERASE}, {"secureerase", no_argument, 0, OPT_SECUREERASE}, {"setlockpin", no_argument, 0, OPT_SETLOCKPIN}, {"lockdevice", no_argument, 0, OPT_LOCKDEVICE}, {"unlockdevice", no_argument, 0, OPT_UNLOCKDEVICE}, {"setclusterversion", no_argument, 0, OPT_SETCLUSTERVERSION}, {"setacl", no_argument, 0, OPT_SETACL}, {"updatefirmware", no_argument, 0, OPT_UPDATEFIRMWARE}, // Options {"loglevel", required_argument, 0, OPT_LOGLEVEL}, {"host", required_argument, 0, OPT_HOST}, {"port", required_argument, 0, OPT_PORT}, {"tlsport", required_argument, 0, OPT_TLSPORT}, {"identity", required_argument, 0, OPT_IDENTITY}, {"hmackey", required_argument, 0, OPT_HMACKEY}, {"clusterversion", required_argument, 0, OPT_CLUSTERVERSION}, {"file", required_argument, 0, OPT_FILE}, {"newclusterversion", required_argument, 0, OPT_NEWCLUSTERVERSION}, {"pin", required_argument, 0, OPT_PIN}, {"newpin", required_argument, 0, OPT_NEWPIN}, {"logtype", required_argument, 0, OPT_LOGTYPE}, {"devicelogname", required_argument, 0, OPT_DEVICELOGNAME}, {"key", required_argument, 0, OPT_KEY}, {"value", required_argument, 0, OPT_VALUE}, {0, 0, 0, 0}, }; // Parse the options from the command line extern char *optarg; extern int optind; int option, optionIndex = 0; while ((option = getopt_long(argc, argv, "?lhptics:", long_options, &optionIndex)) != -1) { switch (option) { case 0: // If this option, just set the flag if (long_options[optionIndex].flag != 0) {break;} // assert(false); // break; case OPT_LOGLEVEL: opts.logLevel = atoi(optarg); break; case OPT_HOST: strncpy(opts.host, optarg, sizeof(opts.host)); break; case OPT_PORT: opts.port = atoi(optarg); break; case OPT_TLSPORT: opts.tlsPort = atoi(optarg); break; case OPT_IDENTITY: opts.identity = atoi(optarg); break; case OPT_HMACKEY: strncpy(opts.hmacKey, optarg, sizeof(opts.hmacKey)-1); break; case OPT_KEY: strncpy(opts.key, optarg, sizeof(opts.key)-1); break; case OPT_VALUE: strncpy(opts.value, optarg, sizeof(opts.value)-1); break; case OPT_CLUSTERVERSION: opts.clusterVersion = (int64_t)atol(optarg); break; case OPT_NEWCLUSTERVERSION: cfg->newClusterVersion = (int64_t)atol(optarg); break; case OPT_FILE: strncpy(cfg->file, optarg, sizeof(cfg->file)-1); break; case OPT_PIN: strncpy(cfg->pin, optarg, sizeof(cfg->pin)-1); break; case OPT_NEWPIN: strncpy(cfg->newPin, optarg, sizeof(cfg->newPin)-1); break; case OPT_LOGTYPE: strncpy(opts.logType, optarg, sizeof(opts.logType)-1); break; case OPT_DEVICELOGNAME: strncpy(cfg->deviceLogName, optarg, sizeof(cfg->deviceLogName)-1); break; case OPT_NOOP: case OPT_PUT: case OPT_GET: case OPT_DELETE: case OPT_GETNEXT: case OPT_GETPREVIOUS: case OPT_GETLOG: case OPT_GETDEVICESPECIFICLOG: case OPT_SETERASEPIN: case OPT_INSTANTERASE: case OPT_SECUREERASE: case OPT_SETLOCKPIN: case OPT_LOCKDEVICE: case OPT_UNLOCKDEVICE: case OPT_SETCLUSTERVERSION: case OPT_SETACL: case OPT_UPDATEFIRMWARE: if ((int)opts.opID == 0) { opts.opID = option; break; } fprintf(stderr, "Multiple operations specified!\n"); PrintUsage(argv[0]); exit(-1); case OPT_HELP: PrintUsage(argv[0]); exit(0); default: PrintUsage(argv[0]); exit(-1); } } // Configure client cfg->logLevel = opts.logLevel; // Configure session cfg->config = (KineticSessionConfig) { .port = opts.port, .clusterVersion = opts.clusterVersion, .identity = opts.identity, .hmacKey = ByteArray_Create(cfg->hmacKeyData, strlen(opts.hmacKey)), }; memcpy(cfg->hmacKeyData, opts.hmacKey, strlen(opts.hmacKey)); strncpy(cfg->config.host, opts.host, sizeof(cfg->config.host)-1); // Configure admin session cfg->adminConfig = cfg->config; cfg->adminConfig.port = opts.tlsPort; cfg->adminConfig.useSsl = true; // Populate and configure the entry to be used for operations ConfigureEntry(cfg, opts.key, opts.tag, opts.version, opts.algorithm, opts.force, opts.value); cfg->opID = opts.opID; // Parse log type from string if (strcmp("utilizations", opts.logType) == 0) { cfg->logType = KINETIC_DEVICE_INFO_TYPE_UTILIZATIONS; } else if (strcmp("temperatures", opts.logType) == 0) { cfg->logType = KINETIC_DEVICE_INFO_TYPE_TEMPERATURES; } else if (strcmp("capacities", opts.logType) == 0) { cfg->logType = KINETIC_DEVICE_INFO_TYPE_CAPACITIES; } else if (strcmp("configuration", opts.logType) == 0) { cfg->logType = KINETIC_DEVICE_INFO_TYPE_CONFIGURATION; } else if (strcmp("statistics", opts.logType) == 0) { cfg->logType = KINETIC_DEVICE_INFO_TYPE_STATISTICS; } else if (strcmp("messages", opts.logType) == 0) { cfg->logType = KINETIC_DEVICE_INFO_TYPE_MESSAGES; } else if (strcmp("limits", opts.logType) == 0) { cfg->logType = KINETIC_DEVICE_INFO_TYPE_LIMITS; } else { fprintf(stderr, "Invalid log info type: %s\n", opts.logType); exit(1); } return optind; }
void test_kinetic_client_should_be_able_to_store_an_arbitrarily_large_binary_object_and_split_across_entries_via_ovelapped_IO_operations(void) { const int maxIterations = 4; const int numCopiesToStore = 4; const KineticSession sessionConfig = { .host = "localhost", .port = KINETIC_PORT, .nonBlocking = false, .clusterVersion = 0, .identity = 1, .hmacKey = ByteArray_CreateWithCString("asdfasdf"), }; for (int iteration = 0; iteration < maxIterations; iteration++) { printf("Overlapped PUT operation (iteration %d of %d)\n", iteration + 1, maxIterations); char* buf = malloc(sizeof(char) * BUFSIZE); int fd = open("test/support/data/test.data", O_RDONLY); int dataLen = read(fd, buf, BUFSIZE); close(fd); TEST_ASSERT_MESSAGE(dataLen > 0, "read error"); /* thread structure */ struct kinetic_thread_arg* kt_arg; pthread_t thread_id[KINETIC_MAX_THREADS]; kinetic_client = malloc(sizeof(KineticSessionHandle) * numCopiesToStore); TEST_ASSERT_NOT_NULL_MESSAGE(kinetic_client, "kinetic_client malloc failed"); kt_arg = malloc(sizeof(struct kinetic_thread_arg) * numCopiesToStore); TEST_ASSERT_NOT_NULL_MESSAGE(kt_arg, "kinetic_thread_arg malloc failed"); for (int i = 0; i < numCopiesToStore; i++) { printf(" Overlapped PUT operations (writing copy %d of %d) on IP (iteration %d of %d):%s\n", i + 1, numCopiesToStore, iteration + 1, maxIterations, sessionConfig.host); // Establish connection TEST_ASSERT_EQUAL_KineticStatus( KINETIC_STATUS_SUCCESS, KineticClient_Connect(&sessionConfig, &kinetic_client[i])); strcpy(kt_arg[i].ip, sessionConfig.host); // Configure the KineticEntry char keyPrefix[128]; snprintf(keyPrefix, sizeof(keyPrefix), "pre_%02d%02d", iteration, i); LOGF("NEW HUNK PREFIX: %s", keyPrefix); ByteBuffer keyBuf = ByteBuffer_Create(kt_arg[i].key, sizeof(kt_arg[i].key)); ByteBuffer_AppendCString(&keyBuf, keyPrefix); kt_arg[i].keyPrefixLength = keyBuf.bytesUsed; ByteBuffer verBuf = ByteBuffer_Create(kt_arg[i].version, sizeof(kt_arg[i].version)); ByteBuffer_AppendCString(&verBuf, "v1.0"); ByteBuffer tagBuf = ByteBuffer_Create(kt_arg[i].tag, sizeof(kt_arg[i].tag)); ByteBuffer_AppendCString(&tagBuf, "some_value_tag..."); ByteBuffer valBuf = ByteBuffer_Create(kt_arg[i].value, sizeof(kt_arg[i].value)); kt_arg[i].entry = (KineticEntry) { .key = keyBuf, .newVersion = verBuf, .tag = tagBuf, .metadataOnly = false, .algorithm = KINETIC_ALGORITHM_SHA1, .value = valBuf, }; // Create a ByteBuffer for consuming chunks of data out of for overlapped PUTs kt_arg[i].data = ByteBuffer_Create(buf, dataLen); // Spawn the worker thread kt_arg[i].sessionHandle = kinetic_client[i]; int create_status = pthread_create(&thread_id[i], NULL, kinetic_put, &kt_arg[i]); TEST_ASSERT_EQUAL_MESSAGE(0, create_status, "pthread create failed"); } // Wait for each overlapped PUT operations to complete and cleanup printf(" Waiting for PUT threads to exit...\n"); for (int i = 0; i < numCopiesToStore; i++) { int join_status = pthread_join(thread_id[i], NULL); TEST_ASSERT_EQUAL_MESSAGE(0, join_status, "pthread join failed"); KineticClient_Disconnect(&kinetic_client[i]); } // Cleanup the rest of the reources free(kinetic_client); free(kt_arg); free(buf); printf(" Iteration complete!\n"); } printf("Overlapped PUT operation test complete!\n"); }
void test_KineticPDU_Send_should_send_the_specified_message_and_return_false_upon_failure_to_send_header(void) { LOG_LOCATION; ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); char valueData[] = "Some arbitrary value"; KineticEntry entry = {.value = ByteBuffer_Create(valueData, strlen(valueData))}; KineticPDU_AttachEntry(&PDU, &entry); KineticHMAC_Init_Expect(&PDU.hmac, KINETIC_PROTO_SECURITY_ACL_HMACALGORITHM_HmacSHA1); KineticHMAC_Populate_Expect(&PDU.hmac, &PDU.protoData.message.proto, PDU.connection->session.hmacKey); KineticSocket_Write_ExpectAndReturn(Connection.socket, &headerNBO, KINETIC_STATUS_SOCKET_ERROR); TEST_IGNORE_MESSAGE("Need to figure out how to handle address of PDU header"); KineticStatus status = KineticPDU_Send(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SOCKET_ERROR, status); } void test_KineticPDU_Send_should_send_the_specified_message_and_return_false_upon_failure_to_send_protobuf(void) { LOG_LOCATION; ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); char valueData[] = "Some arbitrary value"; KineticEntry entry = {.value = ByteBuffer_Create(valueData, strlen(valueData))}; KineticPDU_AttachEntry(&PDU, &entry); KineticHMAC_Init_Expect(&PDU.hmac, KINETIC_PROTO_SECURITY_ACL_HMACALGORITHM_HmacSHA1); KineticHMAC_Populate_Expect(&PDU.hmac, &PDU.protoData.message.proto, PDU.connection->session.hmacKey); KineticSocket_Write_ExpectAndReturn(Connection.socket, &headerNBO, KINETIC_STATUS_SUCCESS); KineticSocket_WriteProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SOCKET_TIMEOUT); TEST_IGNORE_MESSAGE("Need to figure out how to handle address of PDU header"); KineticStatus status = KineticPDU_Send(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SOCKET_TIMEOUT, status); } void test_KineticPDU_Send_should_send_the_specified_message_and_return_KineticStatus_if_value_write_fails(void) { LOG_LOCATION; ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); uint8_t valueData[128]; KineticEntry entry = {.value = ByteBuffer_Create(valueData, sizeof(valueData))}; ByteBuffer_AppendCString(&entry.value, "Some arbitrary value"); KineticPDU_AttachEntry(&PDU, &entry); KineticHMAC_Init_Expect(&PDU.hmac, KINETIC_PROTO_SECURITY_ACL_HMACALGORITHM_HmacSHA1); KineticHMAC_Populate_Expect(&PDU.hmac, &PDU.protoData.message.proto, PDU.connection->session.hmacKey); KineticSocket_Write_ExpectAndReturn(Connection.socket, &headerNBO, KINETIC_STATUS_SUCCESS); KineticSocket_WriteProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS); KineticSocket_Write_ExpectAndReturn(Connection.socket, &entry.value, KINETIC_STATUS_SOCKET_TIMEOUT); TEST_IGNORE_MESSAGE("Need to figure out how to handle address of PDU header"); KineticStatus status = KineticPDU_Send(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SOCKET_TIMEOUT, status); } void test_KineticPDU_Receive_should_receive_a_message_with_value_payload_and_return_true_upon_receipt_of_valid_PDU(void) { LOG_LOCATION; Connection.connectionID = 98765; KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); // Fake value/payload length uint8_t data[1024]; ByteArray expectedValue = ByteArray_Create(data, sizeof(data)); ByteArray_FillWithDummyData(expectedValue); KineticEntry entry = {.value = ByteBuffer_CreateWithArray(expectedValue)}; KineticPDU_AttachEntry(&PDU, &entry); KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS); KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS); KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true); KineticSocket_Read_ExpectAndReturn(Connection.socket, &entry.value, expectedValue.len, KINETIC_STATUS_SUCCESS); PDU.headerNBO.valueLength = KineticNBO_FromHostU32(expectedValue.len); EnableAndSetPDUConnectionID(&PDU, 12345); EnableAndSetPDUStatus(&PDU, KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS); KineticStatus status = KineticPDU_Receive(&PDU); TEST_ASSERT_EQUAL(KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS, PDU.protoData.message.status.code); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); }
static void do_put_and_getprevious_getnext(KineticSession *session) { for (int i = 0; i < 3; i++) { char key[] = "keyX"; key[3] = '0' + i; ByteBuffer put_key_buf = ByteBuffer_MallocAndAppend(key, strlen(key)); uint8_t value[] = "valueX"; value[5] = '0' + i; ByteBuffer put_value_buf = ByteBuffer_MallocAndAppend(value, sizeof(value)); /* Populate tag with SHA1 of value */ ByteBuffer put_tag_buf = ByteBuffer_Malloc(20); uint8_t sha1[20]; SHA1(put_value_buf.array.data, put_value_buf.bytesUsed, &sha1[0]); ByteBuffer_Append(&put_tag_buf, sha1, sizeof(sha1)); KineticEntry put_entry = { .key = put_key_buf, .value = put_value_buf, .tag = put_tag_buf, .algorithm = KINETIC_ALGORITHM_SHA1, /* Set sync to WRITETHROUGH, which will wait to complete * until the drive has persistend the write. (WRITEBACK * returns as soon as the drive has buffered the write.) */ .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH, }; /* Put "keyX" => "valueX", where 'X' is 0..4. * This will block, because the callback field (arg 3) is NULL. */ KineticStatus status = KineticClient_Put(session, &put_entry, NULL); printf("Put status: %s\n", Kinetic_GetStatusDescription(status)); ByteBuffer_Free(put_key_buf); ByteBuffer_Free(put_value_buf); ByteBuffer_Free(put_tag_buf); } printf("\n\n\n"); for (int i = 1; i < 3; i++) { KineticStatus status = KINETIC_STATUS_INVALID; static const ssize_t sz = 100; char key_buf[sz]; char tag_buf[sz]; char value_buf[sz]; ByteBuffer keyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key%d", i); ByteBuffer tagBuffer = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag%d", i); ByteBuffer valueBuffer = ByteBuffer_Create(value_buf, sz, 0); KineticEntry entry = { .key = keyBuffer, .tag = tagBuffer, .value = valueBuffer, .algorithm = KINETIC_ALGORITHM_SHA1, }; if (i > 0) { status = KineticClient_GetPrevious(session, &entry, NULL); printf("GetPrevious status: %s\n", Kinetic_GetStatusDescription(status)); if (status == KINETIC_STATUS_SUCCESS) { printf("Previous key before 'key%d': '%s', value '%s'\n", i, key_buf, value_buf); } } } for (int i = 0; i < 2; i++) { KineticStatus status = KINETIC_STATUS_INVALID; static const ssize_t sz = 100; char key_buf[sz]; char tag_buf[sz]; char value_buf[sz]; ByteBuffer keyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key%d", i); ByteBuffer tagBuffer = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag%d", i); ByteBuffer valueBuffer = ByteBuffer_Create(value_buf, sz, 0); KineticEntry entry = { .key = keyBuffer, .tag = tagBuffer, .value = valueBuffer, .algorithm = KINETIC_ALGORITHM_SHA1, }; if (i < 2) { status = KineticClient_GetNext(session, &entry, NULL); printf("GetNext status: %s\n", Kinetic_GetStatusDescription(status)); if (status == KINETIC_STATUS_SUCCESS) { printf("Next key after 'key%d': '%s', value '%s'\n", i, key_buf, value_buf); } } } /* No cleanup necessary */ }
int KineticSocket_Connect(const char* host, int port, bool nonBlocking) { char port_str[32]; struct addrinfo hints; struct addrinfo* ai_result = NULL; struct addrinfo* ai = NULL; socket99_result result; // Setup server address info socket99_config cfg = { .host = (char*)host, .port = port, .nonblocking = nonBlocking, }; sprintf(port_str, "%d", port); // Open socket LOGF0("Connecting to %s:%d", host, port); if (!socket99_open(&cfg, &result)) { LOGF0("Failed to open socket connection with host: status %d, errno %d", result.status, result.saved_errno); return KINETIC_SOCKET_DESCRIPTOR_INVALID; } // Configure the socket socket99_set_hints(&cfg, &hints); if (getaddrinfo(cfg.host, port_str, &hints, &ai_result) != 0) { LOGF0("Failed to get socket address info: errno %d", errno); close(result.fd); return KINETIC_SOCKET_DESCRIPTOR_INVALID; } for (ai = ai_result; ai != NULL; ai = ai->ai_next) { int setsockopt_result; int buffer_size = KINETIC_OBJ_SIZE; #if defined(SO_NOSIGPIPE) && !defined(__APPLE__) // On BSD-like systems we can set SO_NOSIGPIPE on the socket to // prevent it from sending a PIPE signal and bringing down the whole // application if the server closes the socket forcibly int enable = 1; setsockopt_result = setsockopt(result.fd, SOL_SOCKET, SO_NOSIGPIPE, &enable, sizeof(enable)); // Allow ENOTSOCK because it allows tests to use pipes instead of // real sockets if (setsockopt_result != 0 && setsockopt_result != ENOTSOCK) { LOG0("Failed to set SO_NOSIGPIPE on socket"); continue; } #endif // Increase send buffer to KINETIC_OBJ_SIZE // Note: OS allocates 2x this value for its overhead setsockopt_result = setsockopt(result.fd, SOL_SOCKET, SO_SNDBUF, &buffer_size, sizeof(buffer_size)); if (setsockopt_result == -1) { LOG0("Error setting socket send buffer size"); continue; } // Increase receive buffer to KINETIC_OBJ_SIZE // Note: OS allocates 2x this value for its overheadbuffer_size setsockopt_result = setsockopt(result.fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, sizeof(buffer_size)); if (setsockopt_result == -1) { LOG0("Error setting socket receive buffer size"); continue; } break; } freeaddrinfo(ai_result); if (ai == NULL || result.fd == KINETIC_SOCKET_DESCRIPTOR_INVALID) { // we went through all addresses without finding one we could bind to LOGF0("Could not connect to %s:%d", host, port); return KINETIC_SOCKET_DESCRIPTOR_INVALID; } else { LOGF1("Successfully connected to %s:%d (fd=%d)", host, port, result.fd); return result.fd; } } void KineticSocket_Close(int socket) { if (socket == -1) { LOG1("Not connected so no cleanup needed"); } else { LOGF0("Closing socket with fd=%d", socket); if (close(socket) == 0) { LOG2("Socket closed successfully"); } else { LOGF0("Error closing socket file descriptor!" " (fd=%d, errno=%d, desc='%s')", socket, errno, strerror(errno)); } } } KineticWaitStatus KineticSocket_WaitUntilDataAvailable(int socket, int timeout) { if (socket < 0) {return -1;} struct pollfd fd = { .fd = socket, .events = POLLIN, .revents = 0, }; int res = poll(&fd, 1, timeout); if (res > 0) { //if (fd.revents & POLLHUP) // hung up if (fd.revents & POLLIN) { return KINETIC_WAIT_STATUS_DATA_AVAILABLE; } else { return KINETIC_WAIT_STATUS_FATAL_ERROR; } } else if (res == 0) { return KINETIC_WAIT_STATUS_TIMED_OUT; } else if ((errno & (EAGAIN | EINTR)) != 0) { return KINETIC_WAIT_STATUS_RETRYABLE_ERROR; } else { return KINETIC_WAIT_STATUS_FATAL_ERROR; } } int KineticSocket_DataBytesAvailable(int socket) { if (socket < 0) {return -1;} int count = -1; ioctl(socket, FIONREAD, &count); return count; } KineticStatus KineticSocket_Read(int socket, ByteBuffer* dest, size_t len) { LOGF2("Reading %zd bytes into buffer @ 0x%zX from fd=%d", len, (size_t)dest->array.data, socket); KineticStatus status = KINETIC_STATUS_INVALID; // Read "up to" the allocated number of bytes into dest buffer size_t bytesToReadIntoBuffer = len; if (dest->array.len < len) { bytesToReadIntoBuffer = dest->array.len; } while (dest->bytesUsed < bytesToReadIntoBuffer) { int opStatus; fd_set readSet; struct timeval timeout; // Time out after 5 seconds timeout.tv_sec = 5; timeout.tv_usec = 0; FD_ZERO(&readSet); FD_SET(socket, &readSet); opStatus = select(socket + 1, &readSet, NULL, NULL, &timeout); if (opStatus < 0) { // Error occurred LOGF0("Failed waiting to read from socket!" " status=%d, errno=%d, desc='%s'", opStatus, errno, strerror(errno)); return KINETIC_STATUS_SOCKET_ERROR; } else if (opStatus == 0) { // Timeout occurred LOG0("Timed out waiting for socket data to arrive!"); return KINETIC_STATUS_SOCKET_TIMEOUT; } else if (opStatus > 0) { // Data available to read // The socket is ready for reading opStatus = read(socket, &dest->array.data[dest->bytesUsed], dest->array.len - dest->bytesUsed); // Retry if no data yet... if (opStatus == -1 && ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK) )) { continue; } else if (opStatus <= 0) { LOGF0("Failed to read from socket!" " status=%d, errno=%d, desc='%s'", opStatus, errno, strerror(errno)); return KINETIC_STATUS_SOCKET_ERROR; } else { dest->bytesUsed += opStatus; LOGF3("Received %d bytes (%zd of %zd)", opStatus, dest->bytesUsed, len); } } } // Flush any remaining data, in case of a truncated read w/short dest buffer if (dest->bytesUsed < len) { bool abortFlush = false; uint8_t* discardedBytes = malloc(len - dest->bytesUsed); if (discardedBytes == NULL) { LOG0("Failed allocating a socket read discard buffer!"); abortFlush = true; status = KINETIC_STATUS_MEMORY_ERROR; } while (!abortFlush && dest->bytesUsed < len) { int opStatus; fd_set readSet; struct timeval timeout; size_t remainingLen = len - dest->bytesUsed; // Time out after 5 seconds timeout.tv_sec = 5; timeout.tv_usec = 0; FD_ZERO(&readSet); FD_SET(socket, &readSet); opStatus = select(socket + 1, &readSet, NULL, NULL, &timeout); if (opStatus < 0) { // Error occurred LOGF0("Failure trying to flush read socket data!" " status=%d, errno=%d, desc='%s'", status, errno, strerror(errno)); abortFlush = true; status = KINETIC_STATUS_SOCKET_ERROR; continue; } else if (opStatus == 0) { // Timeout occurred LOG0("Timed out waiting to flush socket data!"); abortFlush = true; status = KINETIC_STATUS_SOCKET_TIMEOUT; continue; } else if (opStatus > 0) { // Data available to read // The socket is ready for reading opStatus = read(socket, discardedBytes, remainingLen); // Retry if no data yet... if (opStatus == -1 && ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK) )) { continue; } else if (opStatus <= 0) { LOGF0("Failed to read from socket while flushing!" " status=%d, errno=%d, desc='%s'", opStatus, errno, strerror(errno)); abortFlush = true; status = KINETIC_STATUS_SOCKET_ERROR; } else { dest->bytesUsed += opStatus; LOGF3("Flushed %d bytes from socket read pipe (%zd of %zd)", opStatus, dest->bytesUsed, len); } } } // Free up dynamically allocated memory before returning if (discardedBytes != NULL) { free(discardedBytes); } // Report any error that occurred during socket flush if (abortFlush) { LOG0("Socket read pipe flush aborted!"); assert(status == KINETIC_STATUS_SUCCESS); return status; } // Report truncation of data for any variable length byte arrays LOGF1("Socket read buffer was truncated due to buffer overrun!" " received=%zu, copied=%zu", len, dest->array.len); return KINETIC_STATUS_BUFFER_OVERRUN; } LOGF3("Received %zd of %zd bytes requested", dest->bytesUsed, len); return KINETIC_STATUS_SUCCESS; } KineticStatus KineticSocket_ReadProtobuf(int socket, KineticPDU* pdu) { size_t bytesToRead = pdu->header.protobufLength; LOGF2("Reading %zd bytes of protobuf", bytesToRead); uint8_t* packed = (uint8_t*)malloc(bytesToRead); if (packed == NULL) { LOG0("Failed allocating memory for protocol buffer"); return KINETIC_STATUS_MEMORY_ERROR; } ByteBuffer recvBuffer = ByteBuffer_Create(packed, bytesToRead, 0); KineticStatus status = KineticSocket_Read(socket, &recvBuffer, bytesToRead); if (status != KINETIC_STATUS_SUCCESS) { LOG0("Protobuf read failed!"); free(packed); return status; } else { pdu->proto = KineticProto_Message__unpack( NULL, recvBuffer.bytesUsed, recvBuffer.array.data); } free(packed); if (pdu->proto == NULL) { pdu->protobufDynamicallyExtracted = false; LOG0("Error unpacking incoming Kinetic protobuf message!"); return KINETIC_STATUS_DATA_ERROR; } else { pdu->protobufDynamicallyExtracted = true; LOG3("Protobuf unpacked successfully!"); return KINETIC_STATUS_SUCCESS; } }
void test_KineticPDU_Receive_should_receive_a_message_for_the_exchange_and_return_false_upon_value_field_receive_failure(void) { LOG_LOCATION; KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); PDU.protoData.message.status.code = KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS; PDU.protoData.message.status.has_code = true; ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); PDU.headerNBO = (KineticPDUHeader) { .versionPrefix = 'F', .protobufLength = KineticNBO_ToHostU32(17), .valueLength = KineticNBO_ToHostU32(124) }; // Fake value/payload length uint8_t data[124]; size_t bytesToRead = sizeof(data); ByteArray expectedValue = ByteArray_Create(data, sizeof(data)); ByteArray_FillWithDummyData(expectedValue); KineticEntry entry = {.value = ByteBuffer_CreateWithArray(expectedValue)}; KineticPDU_AttachEntry(&PDU, &entry); KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS); KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS); KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true); KineticSocket_Read_ExpectAndReturn(Connection.socket, &entry.value, bytesToRead, KINETIC_STATUS_SOCKET_ERROR); KineticStatus status = KineticPDU_Receive(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SOCKET_ERROR, status); TEST_ASSERT_EQUAL(17, PDU.header.protobufLength); TEST_ASSERT_EQUAL(bytesToRead, expectedValue.len); TEST_ASSERT_EQUAL(expectedValue.len, PDU.header.valueLength); } void test_KineticPDU_Receive_should_receive_a_message_and_update_the_ConnectionID_for_the_connection_when_provided(void) { LOG_LOCATION; Connection.connectionID = 98765; KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); PDU.protoData.message.status.code = KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS; PDU.protoData.message.status.has_code = true; ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); // Fake value/payload length uint8_t data[124]; size_t bytesToRead = sizeof(data); ByteArray expectedValue = {.data = data, .len = sizeof(data)}; ByteArray_FillWithDummyData(expectedValue); KineticEntry entry = {.value = ByteBuffer_CreateWithArray(expectedValue)}; KineticPDU_AttachEntry(&PDU, &entry); KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS); KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS); KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true); KineticSocket_Read_ExpectAndReturn(Connection.socket, &entry.value, bytesToRead, KINETIC_STATUS_SUCCESS); PDU.headerNBO.valueLength = KineticNBO_FromHostU32(expectedValue.len); EnableAndSetPDUConnectionID(&PDU, 12345); EnableAndSetPDUStatus(&PDU, KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS); KineticStatus status = KineticPDU_Receive(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); TEST_ASSERT_EQUAL(KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS, PDU.protoData.message.status.code); TEST_ASSERT_EQUAL(12345, PDU.proto->command->header->connectionID); TEST_ASSERT_EQUAL(12345, PDU.connection->connectionID); } void test_KineticPDU_Receive_should_receive_a_message_and_NOT_update_the_ConnectionID_for_the_connection_if_not_provided(void) { LOG_LOCATION; Connection.connectionID = 98765; KINETIC_PDU_INIT_WITH_MESSAGE(&PDU, &Connection); PDU.protoData.message.status.code = KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS; PDU.protoData.message.status.has_code = true; ByteBuffer headerNBO = ByteBuffer_Create(&PDU.headerNBO, sizeof(KineticPDUHeader)); // Fake value/payload length uint8_t data[124]; size_t bytesToRead = sizeof(data); ByteArray expectedValue = {.data = data, .len = sizeof(data)}; ByteArray_FillWithDummyData(expectedValue); KineticEntry entry = {.value = ByteBuffer_CreateWithArray(expectedValue)}; KineticPDU_AttachEntry(&PDU, &entry); KineticSocket_Read_ExpectAndReturn(Connection.socket, &headerNBO, sizeof(KineticPDUHeader), KINETIC_STATUS_SUCCESS); KineticSocket_ReadProtobuf_ExpectAndReturn(Connection.socket, &PDU, KINETIC_STATUS_SUCCESS); KineticHMAC_Validate_ExpectAndReturn(PDU.proto, PDU.connection->session.hmacKey, true); KineticSocket_Read_ExpectAndReturn(Connection.socket, &entry.value, bytesToRead, KINETIC_STATUS_SUCCESS); PDU.headerNBO.valueLength = KineticNBO_FromHostU32(expectedValue.len); EnableAndSetPDUStatus(&PDU, KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS); KineticStatus status = KineticPDU_Receive(&PDU); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); TEST_ASSERT_EQUAL(KINETIC_PROTO_STATUS_STATUS_CODE_SUCCESS, PDU.protoData.message.status.code); TEST_ASSERT_EQUAL(98765, PDU.proto->command->header->connectionID); TEST_ASSERT_EQUAL(98765, PDU.connection->connectionID); } void test_KineticPDU_GetStatus_should_return_KINETIC_STATUS_INVALID_if_no_KineticProto_Status_StatusCode_in_response(void) { LOG_LOCATION; KineticStatus status; status = KineticPDU_GetStatus(NULL); TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status); PDU.proto = NULL; status = KineticPDU_GetStatus(&PDU); TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status); PDU.proto = &PDU.protoData.message.proto; PDU.proto->command = NULL; status = KineticPDU_GetStatus(&PDU); TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status); PDU.proto->command = &PDU.protoData.message.command; status = KineticPDU_GetStatus(&PDU); TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status); PDU.proto->command->status = &PDU.protoData.message.status; PDU.proto->command->status->has_code = false; status = KineticPDU_GetStatus(&PDU); TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status); PDU.proto->command->status->has_code = true; PDU.proto->command->status->code = KINETIC_PROTO_STATUS_STATUS_CODE_INVALID_STATUS_CODE; status = KineticPDU_GetStatus(&PDU); TEST_ASSERT_EQUAL(KINETIC_STATUS_INVALID, status); }
int main(int argc, char** argv) { (void)argc; (void)argv; // Initialize kinetic-c and configure sessions KineticSession* session; KineticClientConfig clientConfig = { .logFile = "stdout", .logLevel = 1, }; KineticClient * client = KineticClient_Init(&clientConfig); if (client == NULL) { return 1; } const char HmacKeyString[] = "asdfasdf"; KineticSessionConfig sessionConfig = { .host = "localhost", .port = KINETIC_PORT, .clusterVersion = 0, .identity = 1, .hmacKey = ByteArray_CreateWithCString(HmacKeyString), }; KineticStatus status = KineticClient_CreateSession(&sessionConfig, client, &session); if (status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n", Kinetic_GetStatusDescription(status)); return -1; } // Read in file contents to store const char* dataFile = "test/support/data/test.data"; struct stat st; stat(dataFile, &st); char* buf = malloc(st.st_size); int fd = open(dataFile, O_RDONLY); long dataLen = read(fd, buf, st.st_size); close(fd); if (dataLen <= 0) { fprintf(stderr, "Failed reading data file to store: %s\n", dataFile); exit(-1); } write_args* writeArgs = calloc(NUM_FILES, sizeof(write_args)); if (writeArgs == NULL) { fprintf(stderr, "Failed allocating overlapped thread arguments!\n"); } // Kick off a thread for each file to store for (int i = 0; i < NUM_FILES; i++) { // Establish connection status = KineticClient_CreateSession(&sessionConfig, client, &writeArgs[i].session); if (status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n", Kinetic_GetStatusDescription(status)); return -1; } strcpy(writeArgs[i].ip, sessionConfig.host); // Create a ByteBuffer for consuming chunks of data out of for overlapped PUTs writeArgs[i].data = ByteBuffer_Create(buf, dataLen, 0); // Configure common entry attributes struct timeval now; gettimeofday(&now, NULL); snprintf(writeArgs[i].keyPrefix, sizeof(writeArgs[i].keyPrefix), "%010llu_%02d_", (unsigned long long)now.tv_sec, i); ByteBuffer valBuf = ByteBuffer_Create(writeArgs[i].value, sizeof(writeArgs[i].value), 0); writeArgs[i].entry = (KineticEntry) { .key = ByteBuffer_CreateAndAppendCString( writeArgs[i].key, sizeof(writeArgs[i].key), writeArgs[i].keyPrefix), .tag = ByteBuffer_CreateAndAppendCString( writeArgs[i].tag, sizeof(writeArgs[i].tag), "some_value_tag..."), .algorithm = KINETIC_ALGORITHM_SHA1, .value = valBuf, }; // Store the entry int threadCreateStatus = pthread_create(&writeArgs[i].threadID, NULL, store_data, &writeArgs[i]); REPORT_ERRNO(threadCreateStatus, "pthread_create"); if (threadCreateStatus != 0) { fprintf(stderr, "pthread create failed!\n"); exit(-2); } } // Wait for all PUT operations to complete and cleanup for (int i = 0; i < NUM_FILES; i++) { int joinStatus = pthread_join(writeArgs[i].threadID, NULL); if (joinStatus != 0) { fprintf(stderr, "pthread join failed!\n"); } KineticClient_DestroySession(writeArgs[i].session); } // Shutdown client connection and cleanup KineticClient_Shutdown(client); free(writeArgs); free(buf); return 0; }
void run_throughput_tests(KineticClient * client, size_t num_ops, size_t value_size) { LOGF0("STRESS THREAD: object_size: %zu bytes, count: %zu entries", value_size, num_ops); // Configure and establish a session with the specified device KineticSession* session; const char HmacKeyString[] = "asdfasdf"; KineticSessionConfig config = { .clusterVersion = 0, .identity = 1, .hmacKey = ByteArray_CreateWithCString(HmacKeyString), }; strncpy(config.host, GetSystemTestHost1(), sizeof(config.host)-1); config.port = GetSystemTestPort1(); KineticStatus status = KineticClient_CreateSession(&config, client, &session); if (status != KINETIC_STATUS_SUCCESS) { char msg[128]; sprintf(msg, "Failed connecting to the Kinetic device w/status: %s", Kinetic_GetStatusDescription(status)); TEST_FAIL_MESSAGE(msg); } // Generate test entry data ByteBuffer test_data = ByteBuffer_Malloc(value_size); ByteBuffer_AppendDummyData(&test_data, test_data.array.len); uint8_t tag_data[] = {0x00, 0x01, 0x02, 0x03}; ByteBuffer tag = ByteBuffer_Create(tag_data, sizeof(tag_data), sizeof(tag_data)); uint64_t r = rand(); uint64_t keys[num_ops]; KineticEntry entries[num_ops]; for (uint32_t put = 0; put < num_ops; put++) { keys[put] = put | (r << 16); } // Measure PUT performance { OpStatus put_statuses[num_ops]; for (size_t i = 0; i < num_ops; i++) { put_statuses[i] = (OpStatus){ .sem = KineticSemaphore_Create(), .status = KINETIC_STATUS_INVALID, }; }; struct timeval start_time; gettimeofday(&start_time, NULL); for (uint32_t put = 0; put < num_ops; put++) { ByteBuffer key = ByteBuffer_Create(&keys[put], sizeof(keys[put]), sizeof(keys[put])); KineticSynchronization sync = (put == num_ops - 1) ? KINETIC_SYNCHRONIZATION_FLUSH : KINETIC_SYNCHRONIZATION_WRITEBACK; entries[put] = (KineticEntry) { .key = key, .tag = tag, .algorithm = KINETIC_ALGORITHM_SHA1, .value = test_data, .synchronization = sync, }; KineticStatus status = KineticClient_Put( session, &entries[put], &(KineticCompletionClosure) { .callback = op_finished, .clientData = &put_statuses[put], } ); if (status != KINETIC_STATUS_SUCCESS) { char msg[128]; sprintf(msg, "PUT failed w/status: %s", Kinetic_GetStatusDescription(status)); TEST_FAIL_MESSAGE(msg); } } for (size_t i = 0; i < num_ops; i++) { KineticSemaphore_WaitForSignalAndDestroy(put_statuses[i].sem); if (put_statuses[i].status != KINETIC_STATUS_SUCCESS) { char msg[128]; sprintf(msg, "PUT failed w/status: %s", Kinetic_GetStatusDescription(put_statuses[i].status)); TEST_FAIL_MESSAGE(msg); } } struct timeval stop_time; gettimeofday(&stop_time, NULL); size_t bytes_written = num_ops * test_data.array.len; int64_t elapsed_us = ((stop_time.tv_sec - start_time.tv_sec) * 1000000) + (stop_time.tv_usec - start_time.tv_usec); float elapsed_ms = elapsed_us / 1000.0f; float bandwidth = (bytes_written * 1000.0f) / (elapsed_ms * 1024 * 1024); LOGF0("PUT Performance: wrote: %.1f kB, duration: %.3f sec, throughput: %.2f MB/sec", bytes_written / 1024.0f, elapsed_ms / 1000.0f, bandwidth); } // Measure GET performance { OpStatus get_statuses[num_ops]; for (size_t i = 0; i < num_ops; i++) { get_statuses[i] = (OpStatus){ .sem = KineticSemaphore_Create(), .status = KINETIC_STATUS_INVALID, }; }; ByteBuffer test_get_datas[num_ops]; for (size_t i = 0; i < num_ops; i++) { test_get_datas[i] = ByteBuffer_Malloc(value_size); } struct timeval start_time; gettimeofday(&start_time, NULL); for (uint32_t get = 0; get < num_ops; get++) { ByteBuffer key = ByteBuffer_Create(&keys[get], sizeof(keys[get]), sizeof(keys[get])); entries[get] = (KineticEntry) { .key = key, .tag = tag, .value = test_get_datas[get], }; KineticStatus status = KineticClient_Get( session, &entries[get], &(KineticCompletionClosure) { .callback = op_finished, .clientData = &get_statuses[get], } ); if (status != KINETIC_STATUS_SUCCESS) { char msg[128]; sprintf(msg, "GET failed w/status: %s", Kinetic_GetStatusDescription(status)); TEST_FAIL_MESSAGE(msg); } } size_t bytes_read = 0; for (size_t i = 0; i < num_ops; i++) { KineticSemaphore_WaitForSignalAndDestroy(get_statuses[i].sem); if (get_statuses[i].status != KINETIC_STATUS_SUCCESS) { char msg[128]; sprintf(msg, "GET failed w/status: %s", Kinetic_GetStatusDescription(get_statuses[i].status)); TEST_FAIL_MESSAGE(msg); } else { bytes_read += entries[i].value.bytesUsed; } } // Check data for integrity size_t numFailures = 0; for (size_t i = 0; i < num_ops; i++) { int res = memcmp(test_data.array.data, test_get_datas[i].array.data, test_data.array.len); if (res != 0) { LOGF0("Failed validating data in object %zu of %zu!", i+1, num_ops); numFailures++; } } TEST_ASSERT_EQUAL_MESSAGE(0, numFailures, "DATA INTEGRITY CHECK FAILED UPON READBACK!"); // Calculate and report performance struct timeval stop_time; gettimeofday(&stop_time, NULL); int64_t elapsed_us = ((stop_time.tv_sec - start_time.tv_sec) * 1000000) + (stop_time.tv_usec - start_time.tv_usec); float elapsed_ms = elapsed_us / 1000.0f; float bandwidth = (bytes_read * 1000.0f) / (elapsed_ms * 1024 * 1024); LOGF0("GET Performance: read: %.1f kB, duration: %.3f sec, throughput: %.2f MB/sec", bytes_read / 1024.0f, elapsed_ms / 1000.0f, bandwidth); for (size_t i = 0; i < num_ops; i++) { ByteBuffer_Free(test_get_datas[i]); } }
KineticStatus KineticPDU_ReceiveMain(KineticPDU* const response) { assert(response != NULL); assert(response->connection != NULL); const int fd = response->connection->socket; assert(fd >= 0); LOGF1("\nReceiving PDU via fd=%d", fd); KineticStatus status; KineticMessage* msg = &response->protoData.message; // Receive the PDU header ByteBuffer rawHeader = ByteBuffer_Create(&response->headerNBO, sizeof(KineticPDUHeader), 0); status = KineticSocket_Read(fd, &rawHeader, rawHeader.array.len); if (status != KINETIC_STATUS_SUCCESS) { LOG0("Failed to receive PDU header!"); return status; } else { LOG3("PDU header received successfully"); KineticPDUHeader* headerNBO = &response->headerNBO; response->header = (KineticPDUHeader) { .versionPrefix = headerNBO->versionPrefix, .protobufLength = KineticNBO_ToHostU32(headerNBO->protobufLength), .valueLength = KineticNBO_ToHostU32(headerNBO->valueLength), }; KineticLogger_LogHeader(1, &response->header); } // Receive the protobuf message status = KineticSocket_ReadProtobuf(fd, response); if (status != KINETIC_STATUS_SUCCESS) { LOG0("Failed to receive PDU protobuf message!"); return status; } else { LOG3("Received PDU protobuf"); KineticLogger_LogProtobuf(2, response->proto); } // Validate the HMAC for the recevied protobuf message if (response->proto->authType == KINETIC_PROTO_MESSAGE_AUTH_TYPE_HMACAUTH) { if(!KineticHMAC_Validate( response->proto, response->connection->session.hmacKey)) { LOG0("Received PDU protobuf message has invalid HMAC!"); msg->has_command = true; msg->command.status = &msg->status; msg->status.code = KINETIC_PROTO_COMMAND_STATUS_STATUS_CODE_DATA_ERROR; return KINETIC_STATUS_DATA_ERROR; } else { LOG3("Received protobuf HMAC validation succeeded"); } } else if (response->proto->authType == KINETIC_PROTO_MESSAGE_AUTH_TYPE_PINAUTH) { LOG0("PIN-based authentication not yet supported!"); return KINETIC_STATUS_DATA_ERROR; } else if (response->proto->authType == KINETIC_PROTO_MESSAGE_AUTH_TYPE_UNSOLICITEDSTATUS) { LOG3("Unsolicited status message is not authenticated"); } // Extract embedded command, if supplied KineticProto_Message* pMsg = response->proto; if (pMsg->has_commandBytes && pMsg->commandBytes.data != NULL && pMsg->commandBytes.len > 0) { response->command = KineticProto_command__unpack( NULL, pMsg->commandBytes.len, pMsg->commandBytes.data); } status = KineticPDU_GetStatus(response); if (status == KINETIC_STATUS_SUCCESS) { LOG2("PDU received successfully!"); } return status; } KineticStatus KineticPDU_ReceiveValue(int socket_desc, ByteBuffer* value, size_t value_length) { assert(socket_desc >= 0); assert(value != NULL); assert(value->array.data != NULL); // Receive value payload LOGF1("Receiving value payload (%lld bytes)...", value_length); ByteBuffer_Reset(value); KineticStatus status = KineticSocket_Read(socket_desc, value, value_length); if (status != KINETIC_STATUS_SUCCESS) { LOG0("Failed to receive PDU value payload!"); return status; } LOG1("Received value payload successfully"); KineticLogger_LogByteBuffer(3, "Value Buffer", *value); return status; }
int main(int argc, char** argv) { (void)argc; (void)argv; // Initialize kinetic-c and configure sessions KineticSession* session; KineticClientConfig clientConfig = { .logFile = "stdout", .logLevel = 1, }; KineticClient * client = KineticClient_Init(&clientConfig); if (client == NULL) { return 1; } const char HmacKeyString[] = "asdfasdf"; KineticSessionConfig sessionConfig = { .host = "localhost", .port = KINETIC_PORT, .clusterVersion = 0, .identity = 1, .hmacKey = ByteArray_CreateWithCString(HmacKeyString), }; KineticStatus status = KineticClient_CreateSession(&sessionConfig, client, &session); if (status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n", Kinetic_GetStatusDescription(status)); exit(1); } // Read in file contents to store const char* dataFile = "test/support/data/test.data"; struct stat st; stat(dataFile, &st); char* buf = malloc(st.st_size); int fd = open(dataFile, O_RDONLY); long dataLen = read(fd, buf, st.st_size); close(fd); if (dataLen <= 0) { fprintf(stderr, "Failed reading data file to store: %s\n", dataFile); exit(-1); } write_args* writeArgs = calloc(1, sizeof(write_args)); writeArgs->session = session; // Create a ByteBuffer for consuming chunks of data out of for overlapped PUTs writeArgs->data = ByteBuffer_Create(buf, dataLen, 0); // Configure common meta-data for the entries struct timeval now; gettimeofday(&now, NULL); snprintf(writeArgs->keyPrefix, sizeof(writeArgs->keyPrefix), "%010ld_", now.tv_sec); ByteBuffer verBuf = ByteBuffer_Create(writeArgs->version, sizeof(writeArgs->version), 0); ByteBuffer_AppendCString(&verBuf, "v1.0"); ByteBuffer tagBuf = ByteBuffer_Create(writeArgs->tag, sizeof(writeArgs->tag), 0); ByteBuffer_AppendCString(&tagBuf, "some_value_tag..."); writeArgs->entry = (KineticEntry) { .key = ByteBuffer_Create(writeArgs->key, sizeof(writeArgs->key), 0), // .newVersion = verBuf, .tag = tagBuf, .algorithm = KINETIC_ALGORITHM_SHA1, .value = ByteBuffer_Create(writeArgs->value, sizeof(writeArgs->value), 0), .synchronization = KINETIC_SYNCHRONIZATION_WRITEBACK, }; strcpy(writeArgs->ip, sessionConfig.host); // Store the data printf("\nWriting data file to the Kinetic device...\n"); store_data(writeArgs); // Shutdown client connection and cleanup KineticClient_DestroySession(writeArgs->session); KineticClient_Shutdown(client); free(writeArgs); free(buf); return 0; }
void test_KineticBuilder_BuildPut_should_build_and_execute_a_PUT_operation_to_create_a_new_object_with_calculated_tag(void) { ByteArray value = ByteArray_CreateWithCString("Luke, I am your father"); ByteArray key = ByteArray_CreateWithCString("foobar"); ByteArray newVersion = ByteArray_CreateWithCString("v1.0"); ByteArray tag = ByteArray_CreateWithCString("some_tag"); KineticEntry entry = { .key = ByteBuffer_CreateWithArray(key), .newVersion = ByteBuffer_CreateWithArray(newVersion), .tag = ByteBuffer_CreateWithArray(tag), .algorithm = KINETIC_ALGORITHM_SHA1, .value = ByteBuffer_CreateWithArray(value), .computeTag = true, }; KineticOperation_ValidateOperation_Expect(&Operation); KineticMessage_ConfigureKeyValue_Expect(&Operation.request->message, &entry); // Build the operation KineticBuilder_BuildPut(&Operation, &entry); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL_PTR(entry.value.array.data, Operation.value.data); TEST_ASSERT_EQUAL(entry.value.bytesUsed, Operation.value.len); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__PUT, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_ByteArray(value, Operation.entry->value.array); TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); } uint8_t ValueData[KINETIC_OBJ_SIZE]; void test_KineticBuilder_BuildGet_should_build_a_GET_operation(void) { const ByteArray key = ByteArray_CreateWithCString("foobar"); ByteArray value = {.data = ValueData, .len = sizeof(ValueData)}; KineticEntry entry = { .key = ByteBuffer_CreateWithArray(key), .value = ByteBuffer_CreateWithArray(value), }; entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0 KineticOperation_ValidateOperation_Expect(&Operation); KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry); KineticBuilder_BuildGet(&Operation, &entry); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GET, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback); TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data); TEST_ASSERT_EQUAL(value.len, Operation.entry->value.array.len); TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); TEST_ASSERT_FALSE(Operation.entry->metadataOnly); } void test_KineticBuilder_BuildGet_should_build_a_GET_operation_requesting_metadata_only(void) { const ByteArray key = ByteArray_CreateWithCString("foobar"); ByteArray value = ByteArray_Create(ValueData, sizeof(ValueData)); KineticEntry entry = { .key = ByteBuffer_CreateWithArray(key), .metadataOnly = true, .value = ByteBuffer_CreateWithArray(value), }; entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0 for a metadata-only request KineticOperation_ValidateOperation_Expect(&Operation); KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry); KineticBuilder_BuildGet(&Operation, &entry); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GET, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback); TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data); TEST_ASSERT_EQUAL_PTR(value.len, Operation.entry->value.array.len); TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); TEST_ASSERT_TRUE(Operation.entry->metadataOnly); } void test_KineticBuilder_BuildGetNext_should_build_a_GETNEXT_operation(void) { const ByteArray key = ByteArray_CreateWithCString("foobar"); ByteArray value = {.data = ValueData, .len = sizeof(ValueData)}; KineticEntry entry = { .key = ByteBuffer_CreateWithArray(key), .value = ByteBuffer_CreateWithArray(value), }; entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0 KineticOperation_ValidateOperation_Expect(&Operation); KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry); KineticBuilder_BuildGetNext(&Operation, &entry); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETNEXT, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback); TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data); TEST_ASSERT_EQUAL(value.len, Operation.entry->value.array.len); TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); TEST_ASSERT_FALSE(Operation.entry->metadataOnly); } void test_KineticBuilder_BuildGetNext_should_build_a_GETNEXT_operation_with_metadata_only(void) { const ByteArray key = ByteArray_CreateWithCString("foobar"); ByteArray value = ByteArray_Create(ValueData, sizeof(ValueData)); KineticEntry entry = { .key = ByteBuffer_CreateWithArray(key), .metadataOnly = true, .value = ByteBuffer_CreateWithArray(value), }; entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0 for a metadata-only request KineticOperation_ValidateOperation_Expect(&Operation); KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry); KineticBuilder_BuildGetNext(&Operation, &entry); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETNEXT, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback); TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data); TEST_ASSERT_EQUAL_PTR(value.len, Operation.entry->value.array.len); TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); TEST_ASSERT_TRUE(Operation.entry->metadataOnly); } void test_KineticBuilder_BuildGetPrevious_should_build_a_GETPREVIOUS_operation(void) { const ByteArray key = ByteArray_CreateWithCString("foobar"); ByteArray value = {.data = ValueData, .len = sizeof(ValueData)}; KineticEntry entry = { .key = ByteBuffer_CreateWithArray(key), .value = ByteBuffer_CreateWithArray(value), }; entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0 KineticOperation_ValidateOperation_Expect(&Operation); KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry); KineticBuilder_BuildGetPrevious(&Operation, &entry); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETPREVIOUS, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback); TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data); TEST_ASSERT_EQUAL(value.len, Operation.entry->value.array.len); TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); TEST_ASSERT_FALSE(Operation.entry->metadataOnly); } void test_KineticBuilder_BuildGetPrevious_should_build_a_GETPREVIOUS_operation_with_metadata_only(void) { const ByteArray key = ByteArray_CreateWithCString("foobar"); ByteArray value = ByteArray_Create(ValueData, sizeof(ValueData)); KineticEntry entry = { .key = ByteBuffer_CreateWithArray(key), .metadataOnly = true, .value = ByteBuffer_CreateWithArray(value), }; entry.value.bytesUsed = 123; // Set to non-empty state, since it should be reset to 0 for a metadata-only request KineticOperation_ValidateOperation_Expect(&Operation); KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry); KineticBuilder_BuildGetPrevious(&Operation, &entry); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETPREVIOUS, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Get, Operation.opCallback); TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data); TEST_ASSERT_EQUAL_PTR(value.len, Operation.entry->value.array.len); TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); TEST_ASSERT_TRUE(Operation.entry->metadataOnly); } void test_KineticBuilder_BuildFlush_should_build_a_FLUSHALLDATA_operation(void) { KineticOperation_ValidateOperation_Expect(&Operation); KineticBuilder_BuildFlush(&Operation); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__FLUSHALLDATA, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Basic, Operation.opCallback); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); } void test_KineticBuilder_BuildDelete_should_build_a_DELETE_operation(void) { const ByteArray key = ByteArray_CreateWithCString("foobar"); ByteArray value = ByteArray_Create(ValueData, sizeof(ValueData)); KineticEntry entry = {.key = ByteBuffer_CreateWithArray(key), .value = ByteBuffer_CreateWithArray(value)}; KineticOperation_ValidateOperation_Expect(&Operation); KineticMessage_ConfigureKeyValue_Expect(&Request.message, &entry); KineticBuilder_BuildDelete(&Operation, &entry); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__DELETE, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(KineticCallbacks_Delete, Operation.opCallback); TEST_ASSERT_EQUAL_PTR(value.data, Operation.entry->value.array.data); TEST_ASSERT_EQUAL_PTR(value.len, Operation.entry->value.array.len); TEST_ASSERT_EQUAL(0, Operation.entry->value.bytesUsed); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); } void test_KineticBuilder_BuildGetKeyRange_should_build_a_GetKeyRange_request(void) { const int maxKeyLen = 32; // arbitrary key length for test uint8_t startKeyData[maxKeyLen]; uint8_t endKeyData[maxKeyLen]; ByteBuffer startKey, endKey; startKey = ByteBuffer_Create(startKeyData, sizeof(startKeyData), 0); ByteBuffer_AppendCString(&startKey, "key_range_00_00"); endKey = ByteBuffer_Create(endKeyData, sizeof(endKeyData), 0); ByteBuffer_AppendCString(&endKey, "key_range_00_03"); const int numKeysInRange = 4; KineticKeyRange range = { .startKey = startKey, .endKey = endKey, .startKeyInclusive = true, .endKeyInclusive = true, .maxReturned = numKeysInRange, .reverse = false, }; uint8_t keysData[numKeysInRange][maxKeyLen]; ByteBuffer keyBuffers[numKeysInRange]; for (int i = 0; i < numKeysInRange; i++) { keyBuffers[i] = ByteBuffer_Create(keysData[i], maxKeyLen, 0); } ByteBufferArray keys = {.buffers = keyBuffers, .count = numKeysInRange}; KineticOperation_ValidateOperation_Expect(&Operation); KineticMessage_ConfigureKeyRange_Expect(&Request.message, &range); KineticBuilder_BuildGetKeyRange(&Operation, &range, &keys); TEST_ASSERT_TRUE(Request.command->header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETKEYRANGE, Request.command->header->messagetype); TEST_ASSERT_EQUAL_PTR(KineticCallbacks_GetKeyRange, Operation.opCallback); TEST_ASSERT_NULL(Operation.entry); TEST_ASSERT_EQUAL_PTR(&Request, Operation.request); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); TEST_ASSERT_EQUAL_PTR(&Request.message.command, Request.command); } void test_KineticBuilder_BuildP2POperation_should_build_a_P2POperation_request(void) { ByteBuffer oldKey1 = ByteBuffer_Create((void*)0x1234, 10, 10); ByteBuffer newKey1 = ByteBuffer_Create((void*)0x4321, 33, 33); ByteBuffer version1 = ByteBuffer_Create((void*)0xABC, 6, 6); ByteBuffer oldKey2 = ByteBuffer_Create((void*)0x5678, 12, 12); ByteBuffer newKey2 = ByteBuffer_Create((void*)0x8765, 200, 200); KineticP2P_OperationData ops2[] ={ { .key = oldKey2, .newKey = newKey2, } }; KineticP2P_Operation chained_p2pOp = { .peer = { .hostname = "hostname1", .port = 4321, }, .numOperations = 1, .operations = ops2 }; KineticP2P_OperationData ops[] ={ { .key = oldKey1, .version = version1, .newKey = newKey1, .chainedOperation = &chained_p2pOp, }, { .key = oldKey2, .newKey = newKey2, } }; KineticP2P_Operation p2pOp = { .peer = { .hostname = "hostname", .port = 1234, .tls = true, }, .numOperations = 2, .operations = ops }; KineticOperation_ValidateOperation_Expect(&Operation); KineticBuilder_BuildP2POperation(&Operation, &p2pOp); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__PEER2PEERPUSH, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(&Request.message.body, Request.command->body); TEST_ASSERT_NOT_NULL(Request.command->body->p2poperation); TEST_ASSERT_EQUAL("hostname", Request.command->body->p2poperation->peer->hostname); TEST_ASSERT_TRUE(Request.command->body->p2poperation->peer->has_port); TEST_ASSERT_EQUAL(1234, Request.command->body->p2poperation->peer->port); TEST_ASSERT_TRUE(Request.command->body->p2poperation->peer->has_tls); TEST_ASSERT_TRUE(Request.command->body->p2poperation->peer->tls); TEST_ASSERT_FALSE(Request.command->body->p2poperation->allchildoperationssucceeded); TEST_ASSERT_FALSE(Request.command->body->p2poperation->has_allchildoperationssucceeded); TEST_ASSERT_EQUAL(2, Request.command->body->p2poperation->n_operation); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->has_key); TEST_ASSERT_EQUAL(oldKey1.array.data, Request.command->body->p2poperation->operation[0]->key.data); TEST_ASSERT_EQUAL(oldKey1.bytesUsed, Request.command->body->p2poperation->operation[0]->key.len); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->has_newkey); TEST_ASSERT_EQUAL(newKey1.array.data, Request.command->body->p2poperation->operation[0]->newkey.data); TEST_ASSERT_EQUAL(newKey1.bytesUsed, Request.command->body->p2poperation->operation[0]->newkey.len); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->has_version); TEST_ASSERT_EQUAL(version1.array.data, Request.command->body->p2poperation->operation[0]->version.data); TEST_ASSERT_EQUAL(version1.bytesUsed, Request.command->body->p2poperation->operation[0]->version.len); TEST_ASSERT_FALSE(Request.command->body->p2poperation->operation[0]->has_force); TEST_ASSERT_FALSE(Request.command->body->p2poperation->operation[0]->force); TEST_ASSERT_NOT_NULL(Request.command->body->p2poperation->operation[0]->p2pop); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->peer->has_port); TEST_ASSERT_EQUAL(4321, Request.command->body->p2poperation->operation[0]->p2pop->peer->port); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->peer->has_tls); TEST_ASSERT_FALSE(Request.command->body->p2poperation->operation[0]->p2pop->peer->tls); TEST_ASSERT_EQUAL(1, Request.command->body->p2poperation->operation[0]->p2pop->n_operation); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->has_key); TEST_ASSERT_EQUAL(oldKey2.array.data, Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->key.data); TEST_ASSERT_EQUAL(oldKey2.bytesUsed, Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->key.len); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->has_newkey); TEST_ASSERT_EQUAL(newKey2.array.data, Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->newkey.data); TEST_ASSERT_EQUAL(newKey2.bytesUsed, Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->newkey.len); TEST_ASSERT_FALSE(Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->has_version); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->has_force); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[0]->p2pop->operation[0]->force); TEST_ASSERT_NULL(Request.command->body->p2poperation->operation[0]->status); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[1]->has_key); TEST_ASSERT_EQUAL(oldKey2.array.data, Request.command->body->p2poperation->operation[1]->key.data); TEST_ASSERT_EQUAL(oldKey2.bytesUsed, Request.command->body->p2poperation->operation[1]->key.len); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[1]->has_newkey); TEST_ASSERT_EQUAL(newKey2.array.data, Request.command->body->p2poperation->operation[1]->newkey.data); TEST_ASSERT_EQUAL(newKey2.bytesUsed, Request.command->body->p2poperation->operation[1]->newkey.len); TEST_ASSERT_FALSE(Request.command->body->p2poperation->operation[1]->has_version); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[1]->has_force); TEST_ASSERT_TRUE(Request.command->body->p2poperation->operation[1]->force); TEST_ASSERT_NULL(Request.command->body->p2poperation->operation[1]->p2pop); TEST_ASSERT_NULL(Request.command->body->p2poperation->operation[1]->status); TEST_ASSERT_EQUAL_PTR(&p2pOp, Operation.p2pOp); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); // This just free's the malloc'd memory and sets statuses to "invalid" (since no operation was actually performed) KineticAllocator_FreeP2PProtobuf(Request.command->body->p2poperation); } /******************************************************************************* * Admin Client Operations *******************************************************************************/ void test_KineticBuilder_BuildGetLog_should_build_a_GetLog_request(void) { KineticLogInfo* pInfo; KineticOperation_ValidateOperation_Expect(&Operation); KineticStatus status = KineticBuilder_BuildGetLog(&Operation, KINETIC_DEVICE_INFO_TYPE_STATISTICS, BYTE_ARRAY_NONE, &pInfo); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETLOG, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(&Request.message.body, Request.command->body); TEST_ASSERT_EQUAL_PTR(&Request.message.getLog, Request.command->body->getlog); TEST_ASSERT_NOT_NULL(Request.command->body->getlog->types); TEST_ASSERT_EQUAL(1, Request.command->body->getlog->n_types); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__STATISTICS, Request.command->body->getlog->types[0]); TEST_ASSERT_EQUAL_PTR(&pInfo, Operation.deviceInfo); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); } void test_KineticBuilder_BuildGetLog_should_build_a_GetLog_request_to_retrieve_device_specific_log_info(void) { KineticLogInfo* pInfo; const char nameData[] = "com.WD"; ByteArray name = ByteArray_CreateWithCString(nameData); KineticOperation_ValidateOperation_Expect(&Operation); KineticStatus status = KineticBuilder_BuildGetLog(&Operation, COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE, name, &pInfo); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); TEST_ASSERT_TRUE(Request.message.command.header->has_messagetype); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__MESSAGE_TYPE__GETLOG, Request.message.command.header->messagetype); TEST_ASSERT_EQUAL_PTR(&Request.message.body, Request.command->body); TEST_ASSERT_EQUAL_PTR(&Request.message.getLog, Request.command->body->getlog); TEST_ASSERT_NOT_NULL(Request.command->body->getlog->types); TEST_ASSERT_EQUAL(1, Request.command->body->getlog->n_types); TEST_ASSERT_EQUAL(COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE, Request.command->body->getlog->types[0]); TEST_ASSERT_EQUAL_PTR(&Request.message.getLogDevice, Request.command->body->getlog->device); TEST_ASSERT_TRUE(Request.command->body->getlog->device->has_name); TEST_ASSERT_EQUAL_PTR(nameData, Request.command->body->getlog->device->name.data); TEST_ASSERT_EQUAL(strlen(nameData), Request.command->body->getlog->device->name.len); TEST_ASSERT_EQUAL_PTR(&pInfo, Operation.deviceInfo); TEST_ASSERT_FALSE(Request.pinAuth); TEST_ASSERT_EQUAL(0, Operation.timeoutSeconds); TEST_ASSERT_NULL(Operation.response); } void test_KineticBuilder_BuildGetLog_should_return_KINETIC_STATUS_DEVICE_NAME_REQUIRED_if_name_not_specified_correctly(void) { KineticLogInfo* pInfo; char nameData[] = "com.WD"; ByteArray name; KineticStatus status; // Length is zero name.data = (uint8_t*)nameData; name.len = 0; KineticOperation_ValidateOperation_Expect(&Operation); status = KineticBuilder_BuildGetLog(&Operation, COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE, name, &pInfo); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DEVICE_NAME_REQUIRED, status); // Data is NULL name.data = NULL; name.len = strlen(nameData); KineticOperation_ValidateOperation_Expect(&Operation); status = KineticBuilder_BuildGetLog(&Operation, COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE, name, &pInfo); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DEVICE_NAME_REQUIRED, status); // Length is zero and data is NULL name.data = NULL; name.len = 0; KineticOperation_ValidateOperation_Expect(&Operation); status = KineticBuilder_BuildGetLog(&Operation, COM__SEAGATE__KINETIC__PROTO__COMMAND__GET_LOG__TYPE__DEVICE, name, &pInfo); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DEVICE_NAME_REQUIRED, status); }
static bool add_keys(int count) { static const ssize_t sz = 10; char key_buf[sz]; char tag_buf[sz]; char value_buf[sz]; for (int i = 0; i < count; i++) { KineticEntry entry = { .key = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key_%d", i), .tag = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag_%d", i), .value = ByteBuffer_CreateAndAppendFormattedCString(value_buf, sz, "val_%d", i), .algorithm = KINETIC_ALGORITHM_SHA1, .force = true, }; KineticStatus status = KineticClient_Put(Fixture.session, &entry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); } return true; } typedef enum { CMD_NEXT, CMD_PREVIOUS } GET_CMD; static void compare_against_offset_key(GET_CMD cmd, bool metadataOnly) { static const ssize_t sz = 10; char key_buf[sz]; char tag_buf[sz]; char value_buf[sz]; char key_exp_buf[sz]; char value_exp_buf[sz]; const int count = 3; TEST_ASSERT_TRUE(add_keys(count)); /* add keys [key_X -> test_X] */ int low = 0; int high = count; int8_t offset = 0; switch (cmd) { case CMD_NEXT: low = 1; offset = -1; break; case CMD_PREVIOUS: high = count - 1; offset = +1; break; default: TEST_ASSERT(false); } for (int i = low; i < high; i++) { ByteBuffer keyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key_%d", i + offset); ByteBuffer tagBuffer = ByteBuffer_CreateAndAppendFormattedCString(tag_buf, sz, "tag_%d", i + offset); ByteBuffer valueBuffer = ByteBuffer_Create(value_buf, sz, 0); printf("KEY '%s'\n", key_buf); KineticEntry entry = { .key = keyBuffer, .tag = tagBuffer, .value = valueBuffer, .algorithm = KINETIC_ALGORITHM_SHA1, .metadataOnly = metadataOnly, }; KineticStatus status = KINETIC_STATUS_INVALID; switch (cmd) { case CMD_NEXT: status = KineticClient_GetNext(Fixture.session, &entry, NULL); break; case CMD_PREVIOUS: status = KineticClient_GetPrevious(Fixture.session, &entry, NULL); break; default: TEST_ASSERT(false); } TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); ByteBuffer expectedKeyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_exp_buf, sz, "key_%d", i); ByteBuffer expectedValueBuffer = ByteBuffer_CreateAndAppendFormattedCString(value_exp_buf, sz, "val_%d", i); TEST_ASSERT_EQUAL_ByteBuffer(expectedKeyBuffer, entry.key); if (!metadataOnly) { TEST_ASSERT_EQUAL_ByteBuffer(expectedValueBuffer, entry.value); } } } void test_GetNext_should_retrieve_object_and_metadata_from_device(void) { compare_against_offset_key(CMD_NEXT, false); }
void test_put_get_delete_one_entry_by_one_entry(void) { uint8_t version_data[DEFAULT_BUFFER_SIZE], tag_data[DEFAULT_BUFFER_SIZE], value_data[DEFAULT_BUFFER_SIZE]; ByteBuffer version_buffer, tag_buffer, value_buffer; version_buffer = ByteBuffer_CreateAndAppendCString(version_data, sizeof(version_data), "v1.0"); ExpectedVersionBuffer = ByteBuffer_CreateAndAppendCString(version_data, sizeof(version_data), "v1.0"); tag_buffer = ByteBuffer_CreateAndAppendCString(tag_data, sizeof(tag_data), "SomeTagValue"); ExpectedTagBuffer = ByteBuffer_CreateAndAppendCString(tag_data, sizeof(tag_data), "SomeTagValue"); value_buffer = ByteBuffer_Create(value_data, DEFAULT_BUFFER_SIZE, 0); unsigned int i; for (i=0; i<KV_PAIRS_PER_GROUP; i++) { // put object KineticEntry putEntry = { .key = generate_entry_key_by_index(i), .tag = tag_buffer, .newVersion = version_buffer, .algorithm = KINETIC_ALGORITHM_SHA1, .value = generate_entry_value_by_index(i), .force = true, .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH, }; KineticStatus status = KineticClient_Put(Fixture.session, &putEntry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); ByteBuffer_Reset(&value_buffer); // get object value_buffer = ByteBuffer_Create(value_data, DEFAULT_BUFFER_SIZE, 0); KineticEntry getEntry = { .key = generate_entry_key_by_index(i), .dbVersion = version_buffer, .tag = tag_buffer, .value = value_buffer, }; status = KineticClient_Get(Fixture.session, &getEntry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, getEntry.dbVersion); TEST_ASSERT_ByteBuffer_NULL(getEntry.newVersion); TEST_ASSERT_EQUAL_ByteBuffer(generate_entry_key_by_index(i), getEntry.key); TEST_ASSERT_EQUAL_ByteBuffer(ExpectedTagBuffer, getEntry.tag); TEST_ASSERT_EQUAL(KINETIC_ALGORITHM_SHA1, getEntry.algorithm); TEST_ASSERT_EQUAL_ByteBuffer(generate_entry_value_by_index(i), getEntry.value); TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, version_buffer); // delete object KineticEntry deleteEntry = { .key = generate_entry_key_by_index(i), .dbVersion = version_buffer, }; TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, version_buffer); status = KineticClient_Delete(Fixture.session, &deleteEntry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); TEST_ASSERT_EQUAL(0, deleteEntry.value.bytesUsed); // get object again status = KineticClient_Get(Fixture.session, &getEntry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_NOT_FOUND, status); } } void test_put_get_delete_one_group_by_one_group(void) { uint8_t version_data[DEFAULT_BUFFER_SIZE], tag_data[DEFAULT_BUFFER_SIZE], value_data[DEFAULT_BUFFER_SIZE]; ByteBuffer version_buffer, tag_buffer, value_buffer; version_buffer = ByteBuffer_CreateAndAppendCString(version_data, sizeof(version_data), "v1.0"); ExpectedVersionBuffer = ByteBuffer_CreateAndAppendCString(version_data, sizeof(version_data), "v1.0"); tag_buffer = ByteBuffer_CreateAndAppendCString(tag_data, sizeof(tag_data), "SomeTagValue"); ExpectedTagBuffer = ByteBuffer_CreateAndAppendCString(tag_data, sizeof(tag_data), "SomeTagValue"); value_buffer = ByteBuffer_Create(value_data, DEFAULT_BUFFER_SIZE, 0); unsigned int i, j; for (i =0; i<TOTAL_GROUPS; i++) { KineticStatus status; // put a group of entries for (j=0; j<KV_PAIRS_PER_GROUP; j++) { KineticEntry putEntry = { .key = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j), .tag = tag_buffer, .newVersion = version_buffer, .algorithm = KINETIC_ALGORITHM_SHA1, .value = generate_entry_value_by_index(i*KV_PAIRS_PER_GROUP + j), .force = true, .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH, }; status = KineticClient_Put(Fixture.session, &putEntry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); } // get key_range KineticKeyRange range = { .startKey = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP), .endKey = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + KV_PAIRS_PER_GROUP -1), .startKeyInclusive = true, .endKeyInclusive = true, .maxReturned = KV_PAIRS_PER_GROUP, }; ByteBuffer keyBuff[KV_PAIRS_PER_GROUP]; uint8_t keysData[KV_PAIRS_PER_GROUP][DEFAULT_BUFFER_SIZE]; for (j = 0; j < KV_PAIRS_PER_GROUP; j++) { memset(&keysData[j], 0, DEFAULT_BUFFER_SIZE); keyBuff[j] = ByteBuffer_Create(&keysData[j], DEFAULT_BUFFER_SIZE, 0); } ByteBufferArray keys = {.buffers = keyBuff, .count = KV_PAIRS_PER_GROUP, .used = 0}; status = KineticClient_GetKeyRange(Fixture.session, &range, &keys, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); TEST_ASSERT_EQUAL(KV_PAIRS_PER_GROUP, keys.used); for (j = 0; j < KV_PAIRS_PER_GROUP; j++) { TEST_ASSERT_EQUAL_ByteBuffer(generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j), keys.buffers[j]); } // delete a group of entries for (j=0; j<KV_PAIRS_PER_GROUP; j++) { ByteBuffer_Reset(&value_buffer); // get object value_buffer = ByteBuffer_Create(value_data, DEFAULT_BUFFER_SIZE, 0); KineticEntry getEntry = { .key = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j), .dbVersion = version_buffer, .tag = tag_buffer, .value = value_buffer, }; status = KineticClient_Get(Fixture.session, &getEntry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, getEntry.dbVersion); TEST_ASSERT_ByteBuffer_NULL(getEntry.newVersion); TEST_ASSERT_EQUAL_ByteBuffer(generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j), getEntry.key); TEST_ASSERT_EQUAL_ByteBuffer(ExpectedTagBuffer, getEntry.tag); TEST_ASSERT_EQUAL(KINETIC_ALGORITHM_SHA1, getEntry.algorithm); TEST_ASSERT_EQUAL_ByteBuffer(generate_entry_value_by_index(i*KV_PAIRS_PER_GROUP + j), getEntry.value); TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, version_buffer); } // delete a group of entries for (j=0; j<KV_PAIRS_PER_GROUP; j++) { // delete object KineticEntry deleteEntry = { .key = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j), .dbVersion = version_buffer, }; TEST_ASSERT_EQUAL_ByteBuffer(ExpectedVersionBuffer, version_buffer); status = KineticClient_Delete(Fixture.session, &deleteEntry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status); TEST_ASSERT_EQUAL(0, deleteEntry.value.bytesUsed); // get object again ByteBuffer_Reset(&value_buffer); // get object value_buffer = ByteBuffer_Create(value_data, DEFAULT_BUFFER_SIZE, 0); KineticEntry getEntry = { .key = generate_entry_key_by_index(i*KV_PAIRS_PER_GROUP + j), .dbVersion = version_buffer, .tag = tag_buffer, .value = value_buffer, }; status = KineticClient_Get(Fixture.session, &getEntry, NULL); TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_NOT_FOUND, status); } } }
int main(int argc, char** argv) { (void)argc; (void)argv; // Initialize kinetic-c and configure sessions KineticSession* session; KineticClientConfig clientConfig = { .logFile = "stdout", .logLevel = 1, }; KineticClient * client = KineticClient_Init(&clientConfig); if (client == NULL) { return 1; } const char HmacKeyString[] = "asdfasdf"; KineticSessionConfig sessionConfig = { .host = "localhost", .port = KINETIC_PORT, .clusterVersion = 0, .identity = 1, .hmacKey = ByteArray_CreateWithCString(HmacKeyString), }; KineticStatus status = KineticClient_CreateSession(&sessionConfig, client, &session); if (status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "Failed connecting to the Kinetic device w/status: %s\n", Kinetic_GetStatusDescription(status)); exit(1); } // Create some entries so that we can query the keys printf("Storing some entries on the device...\n"); const size_t numKeys = 3; if (!create_entries(session, numKeys)) { return 2; } // Query a range of keys const size_t keyLen = 64; uint8_t startKeyData[keyLen], endKeyData[keyLen]; KineticKeyRange range = { .startKey = ByteBuffer_CreateAndAppendCString(startKeyData, sizeof(startKeyData), "key_prefix_00"), .endKey = ByteBuffer_CreateAndAppendCString(endKeyData, sizeof(endKeyData), "key_prefix_01"), .startKeyInclusive = true, .endKeyInclusive = true, .maxReturned = 3, }; uint8_t keysData[numKeys][keyLen]; ByteBuffer keyBuff[] = { ByteBuffer_Create(&keysData[0], keyLen, 0), ByteBuffer_Create(&keysData[1], keyLen, 0), ByteBuffer_Create(&keysData[2], keyLen, 0), }; ByteBufferArray keys = {.buffers = &keyBuff[0], .count = numKeys}; status = KineticClient_GetKeyRange(session, &range, &keys, NULL); if (status != KINETIC_STATUS_SUCCESS) { fprintf(stderr, "FAILURE: Failed retrieving key range from device!\n"); return 3; } if (keys.used != 2) { fprintf(stderr, "FAILURE: Unexpected number of keys in returned range!\n"); return 4; }; if (keyBuff[0].bytesUsed != strlen("key_prefix_00")) { fprintf(stderr, "FAILURE: Key 0 length check failed!\n"); return 4; } if (keyBuff[1].bytesUsed != strlen("key_prefix_01")) { fprintf(stderr, "FAILURE: Key 1 length check failed!\n"); return 4; } if (keyBuff[2].bytesUsed != 0) { fprintf(stderr, "FAILURE: Key 2 was not empty as expected!\n"); return 4; } // Shutdown client connection and cleanup KineticClient_DestroySession(session); KineticClient_Shutdown(client); printf("Key range retrieved successfully!\n"); return 0; } static bool create_entries(KineticSession * const session, const int count) { static const ssize_t sz = 20; char key_buf[sz]; char value_buf[sz]; for (int i = 0; i < count; i++) { ByteBuffer KeyBuffer = ByteBuffer_CreateAndAppendFormattedCString(key_buf, sz, "key_prefix_%02d", i); ByteBuffer ValueBuffer = ByteBuffer_CreateAndAppendFormattedCString(value_buf, sz, "val_%02d", i); /* Populate tag with SHA1 of value */ ByteBuffer put_tag_buf = ByteBuffer_Malloc(20); uint8_t sha1[20]; SHA1(ValueBuffer.array.data, ValueBuffer.bytesUsed, &sha1[0]); ByteBuffer_Append(&put_tag_buf, sha1, sizeof(sha1)); KineticEntry entry = { .key = KeyBuffer, .value = ValueBuffer, .tag = put_tag_buf, .algorithm = KINETIC_ALGORITHM_SHA1, .force = true, .synchronization = KINETIC_SYNCHRONIZATION_WRITETHROUGH, }; KineticStatus status = KineticClient_Put(session, &entry, NULL); if (KINETIC_STATUS_SUCCESS != status) { return false; } } return true; }