diff options
Diffstat (limited to 'libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c')
-rw-r--r-- | libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c new file mode 100644 index 00000000..8f0051a0 --- /dev/null +++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/un.h> +#include <strings.h> +#include <fcntl.h> +#include <limits.h> + +#include <LongBow/unit-test.h> + + +#include <ccnx/api/control/cpi_ControlMessage.h> +#include <ccnx/common/ccnx_ContentObject.h> + +#include <parc/security/parc_Pkcs12KeyStore.h> +#include <parc/security/parc_PublicKeySigner.h> +#include <parc/security/parc_Security.h> +#include <parc/algol/parc_SafeMemory.h> + +#include <ccnx/transport/transport_rta/config/config_All.h> +#include <ccnx/transport/transport_rta/core/rta_Framework.h> +#include <ccnx/transport/transport_rta/core/rta_Framework_Commands.c> +#include <ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.h> + +#include "../../test_tools/bent_pipe.h" +#include <ccnx/transport/test_tools/traffic_tools.h> + +static const char local_name[] = "/tmp/beta"; +static const char alice_keystore_name[] = "/tmp/alice_keystore"; +static const char bob_keystore_name[] = "/tmp/bob_keystore"; + +static int alice_fd; +static int bob_fd; +static TransportContext *transport_context; +static CCNxTransportConfig *alice_params; +static CCNxTransportConfig *bob_params; + +// reflector for FWD_LOCAL +static BentPipeState *bentpipe; + +static int rnd_fd; + +// for statistics +static double total_delay; +static double total_bytes_per_sec; +static unsigned item_count; + +// ====================================================== + +static CCNxTransportConfig * +MultipleConnections_createParams(const char *local_name, const char *keystore_name, const char *keystore_passwd, const char *nonce) +{ + assertNotNull(local_name, "Got null keystore name\n"); + assertNotNull(keystore_name, "Got null keystore name\n"); + assertNotNull(keystore_passwd, "Got null keystore passwd\n"); + + CCNxStackConfig *stackConfig = ccnxStackConfig_Create(); + + apiConnector_ProtocolStackConfig( + tlvCodec_ProtocolStackConfig( + localForwarder_ProtocolStackConfig( + protocolStack_ComponentsConfigArgs(stackConfig, + apiConnector_GetName(), + tlvCodec_GetName(), + localForwarder_GetName(), + NULL) + ))); + + CCNxConnectionConfig *connConfig = apiConnector_ConnectionConfig( + tlvCodec_ConnectionConfig( + localForwarder_ConnectionConfig(ccnxConnectionConfig_Create(), local_name))); + + publicKeySigner_ConnectionConfig(connConfig, keystore_name, keystore_passwd); + + + // add the special nonce + PARCJSONValue *value = parcJSONValue_CreateFromCString(nonce); + ccnxStackConfig_Add(stackConfig, "nonce", value); + parcJSONValue_Release(&value); + + CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig); + ccnxStackConfig_Release(&stackConfig); + + return result; +} + +/** + * @function sendRandomObject + * @abstract Sends a content object over the given socket. + * @discussion + * The payload of the content object is a "struct timeval" for timing purposes. + * + * @param Transport socket to use + * @return A copy of the content object sent + */ +static CCNxContentObject * +sendRandomObject(int output_fd, int fixed_size) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + + if (fixed_size < (int) sizeof(tv)) { + fixed_size = sizeof(tv); + } + + uint8_t *buffer = parcMemory_Allocate(fixed_size); + assertNotNull(buffer, "parcMemory_Allocate(%d) returned NULL", fixed_size); + memcpy(buffer, (uint8_t *) &tv, sizeof(tv)); + + PARCBuffer *contents = parcBuffer_Flip(parcBuffer_CreateFromArray(buffer, fixed_size)); + CCNxContentObject *object = trafficTools_CreateContentObjectWithPayload(contents); + parcBuffer_Release(&contents); + + // Return value not checked. + // This creates a reference to object, so we still hold the memory and can return it + CCNxMetaMessage *meta = ccnxMetaMessage_CreateFromContentObject(object); + Transport_Send(output_fd, meta); + ccnxMetaMessage_Release(&meta); + + parcMemory_Deallocate((void **) &buffer); + + // truth_co and truth_msg will be freed by Transport_Send + return object; +} + +/** + * @function recvAndCompare + * @abstract Block on receiving a message on the input_fd, then assert its the same as the truth_obj. + * @discussion + * <#Discussion#> + * + * @param <#param1#> + * @return <#return#> + */ +static bool +recvAndCompare(int input_fd, CCNxContentObject *truth_obj) +{ + struct timeval now, *then, delta; + + CCNxMetaMessage *test_msg; + int res = Transport_Recv(input_fd, &test_msg); + + assertTrue(res == 0, "got error from Transport_Recv (%d)", res); + + // We can't directly compare the two dictionaries with CCNxTlvDictionary_Equals(), + // because the test_obj that we read in was signed in the Transport when + // it was sent. So the dictionaries are different. + + // So, instead, compare the payload - which should have the time at which the ContentObject + // was created. + + CCNxContentObject *testObject = ccnxMetaMessage_GetContentObject(test_msg); + PARCBuffer *contentsA = ccnxContentObject_GetPayload(testObject); + PARCBuffer *contentsB = ccnxContentObject_GetPayload(truth_obj); + assertTrue(parcBuffer_Equals(contentsA, contentsB), "Payloads do not compare"); + + then = (struct timeval *) parcBuffer_Overlay(contentsA, 0); + + gettimeofday(&now, NULL); + timersub(&now, then, &delta); + + double delay = delta.tv_sec + 1E-6 * delta.tv_usec; + double bytes_per_sec = parcBuffer_Remaining(parcBuffer_Rewind(contentsA)) / delay; + + total_delay += delay; + total_bytes_per_sec += bytes_per_sec; + item_count++; + + ccnxMetaMessage_Release(&test_msg); + return true; +} + +static void +assertConnectionOpen(int fd) +{ + // wait for the CONNECTION_OPEN messages + CCNxMetaMessage *firstMessage; + Transport_Recv(fd, &firstMessage); + + assertTrue(ccnxMetaMessage_IsControl(firstMessage), "Expected first message to be a control message"); + + CCNxControl *control = ccnxMetaMessage_GetControl(firstMessage); + + if (ccnxControl_IsNotification(control)) { + NotifyStatus *status = ccnxControl_GetNotifyStatus(control); + + assertTrue(notifyStatus_IsConnectionOpen(status), "Expected notifyStatus_IsConnectionOpen to be true"); + + notifyStatus_Release(&status); + } + + ccnxMetaMessage_Release(&firstMessage); +} + +static void +stackSetup(const char *alice_nonce, const char *bob_nonce) +{ + unlink(local_name); + + bentpipe = bentpipe_Create(local_name); + bentpipe_SetChattyOutput(bentpipe, false); + bentpipe_Start(bentpipe); + + transport_context = Transport_Create(TRANSPORT_RTA); + + assertNotNull(transport_context, "transportRta_Create() returned null"); + + unlink(alice_keystore_name); + unlink(bob_keystore_name); + + bool success = parcPkcs12KeyStore_CreateFile(alice_keystore_name, "23456", "alice", 1024, 30); + assertTrue(success, "parcPkcs12Store_CreateFile() failed."); + success = parcPkcs12KeyStore_CreateFile(bob_keystore_name, "34567", "bob", 2048, 15); + assertTrue(success, "parcPkcs12Store_CreateFile() failed."); + + alice_params = MultipleConnections_createParams(local_name, alice_keystore_name, "23456", alice_nonce); + bob_params = MultipleConnections_createParams(local_name, bob_keystore_name, "34567", bob_nonce); + + // open a connection, this will cause accpet() to fire + alice_fd = Transport_Open(alice_params); + bob_fd = Transport_Open(bob_params); + + assertFalse(alice_fd < 0, "Transport_Open returned error"); + assertFalse(bob_fd < 0, "Transport_Open returned error"); + + assertConnectionOpen(alice_fd); + assertConnectionOpen(bob_fd); +} + +static void +stackTearDown(const char *alice_nonce, const char *bob_nonce) +{ + assertTrue(unlink(alice_keystore_name) == 0 || errno == ENOENT, + "Unable to unlink the file %s: %s", alice_keystore_name, strerror(errno)); + + assertTrue(unlink(bob_keystore_name) == 0 || errno == ENOENT, + "Unable to unlink the file %s: %s", bob_keystore_name, strerror(errno)); + + Transport_Destroy(&transport_context); + bentpipe_Stop(bentpipe); + bentpipe_Destroy(&bentpipe); + + ccnxTransportConfig_Destroy(&alice_params); + ccnxTransportConfig_Destroy(&bob_params); +} + +#include <parc/algol/parc_Object.h> + +/** + * @function ping + * @abstract Send a message from one socket to another socket + * @discussion + * Send a content object from one socket to another, then esure the + * unsigned parts of the received message compare to the sent message. + * + * There's a minimum size (sizeof struct timeval). If the fixed_size is + * larger than that minimum, we'll pad out to the fixed size. + * + * @param fixed_size is the payload content size. + * @return <#return#> + */ +static bool +ping(int from_fd, int to_fd, int fixed_size) +{ + CCNxContentObject *object = sendRandomObject(from_fd, fixed_size); + bool success = recvAndCompare(to_fd, object); + assertTrue(success, "sent and received didn't compare!\n"); + ccnxContentObject_Release(&object); + return success; +} +/** + * use -1 for random size, othewise anything larger than 16 works + * for the payload size + */ +static void +playPingPong(int fixed_size) +{ + int loops = 10; + while (loops-- > 0) { + // send down alice and up bob, then bob to alice + ping(alice_fd, bob_fd, fixed_size); + ping(bob_fd, alice_fd, fixed_size); + } +} + +// ====================================================== + + +LONGBOW_TEST_RUNNER(MultipleConnections) +{ + LONGBOW_RUN_TEST_FIXTURE(SameStack); + LONGBOW_RUN_TEST_FIXTURE(DifferentStacks); +} + +LONGBOW_TEST_RUNNER_SETUP(MultipleConnections) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + rnd_fd = open("/dev/urandom", O_RDONLY); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(MultipleConnections) +{ + close(rnd_fd); + return LONGBOW_STATUS_SUCCEEDED; +} + +// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + +/* + * Same Stack tests multiple connections within the same + * protocol stack + */ + +LONGBOW_TEST_FIXTURE(SameStack) +{ + LONGBOW_RUN_TEST_CASE(SameStack, alice_bob_pingpong); +} + +LONGBOW_TEST_FIXTURE_SETUP(SameStack) +{ + parcSecurity_Init(); + stackSetup("apple", "apple"); + + total_delay = total_bytes_per_sec = 0.0; + item_count = 0; + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(SameStack) +{ + longBowDebug("average delay %.6f sec, avg bytes/sec %.3f\n", + total_delay / item_count, total_bytes_per_sec / item_count); + + stackTearDown("apple", "apple"); + + parcSecurity_Fini(); + + if (parcMemory_Outstanding() != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(SameStack, alice_bob_pingpong) +{ + playPingPong(8192); +} + +// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + +/* + * DifferentStacks tests multiple connections through + * different stacks in the same transport + */ + +LONGBOW_TEST_FIXTURE(DifferentStacks) +{ + LONGBOW_RUN_TEST_CASE(DifferentStacks, alice_bob_pingpong); +} + +LONGBOW_TEST_FIXTURE_SETUP(DifferentStacks) +{ + parcSecurity_Init(); + stackSetup("apple", "oranges"); + total_delay = total_bytes_per_sec = 0.0; + item_count = 0; + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(DifferentStacks) +{ + stackTearDown("apple", "oranges"); + + parcSecurity_Fini(); + + if (parcMemory_Outstanding() != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(DifferentStacks, alice_bob_pingpong) +{ + playPingPong(-1); +} + +// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(MultipleConnections); + exit(longBowMain(argc, argv, testRunner, NULL)); +} |