diff options
Diffstat (limited to 'libccnx-transport-rta/ccnx/api/control/cpi_Address.c')
-rw-r--r-- | libccnx-transport-rta/ccnx/api/control/cpi_Address.c | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/libccnx-transport-rta/ccnx/api/control/cpi_Address.c b/libccnx-transport-rta/ccnx/api/control/cpi_Address.c new file mode 100644 index 00000000..6dd44f69 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/cpi_Address.c @@ -0,0 +1,502 @@ +/* + * 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 <unistd.h> +#include <strings.h> +#include <arpa/inet.h> +#include <errno.h> + +#include <ccnx/api/control/cpi_Address.h> + +#include <parc/algol/parc_Object.h> +#include <parc/algol/parc_Base64.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_Hash.h> +#include <parc/algol/parc_BufferComposer.h> +#include <parc/algol/parc_Network.h> + +#include <LongBow/runtime.h> + +const char *cpiAddressType = "ADDRESSTYPE"; +const char *cpiAddrData = "DATA"; + +struct cpi_address { + CPIAddressType addressType; + PARCBuffer *blob; +}; + +static struct cpi_address_type_str { + CPIAddressType type; + const char *str; +} cpiAddressTypeString[] = { + { .type = cpiAddressType_INET, .str = "INET" }, + { .type = cpiAddressType_INET6, .str = "INET6" }, + { .type = cpiAddressType_LINK, .str = "LINK" }, + { .type = cpiAddressType_IFACE, .str = "IFACE" }, + { .type = cpiAddressType_UNIX, .str = "UNIX" }, + { .type = 0, .str = NULL } +}; + +void +cpiAddress_Destroy(CPIAddress **addressPtr) +{ + assertNotNull(addressPtr, "Parameter must be non-null double pointer"); + assertNotNull(*addressPtr, "Parameter must dereference to non-null pointer"); + + CPIAddress *address = *addressPtr; + parcBuffer_Release(&address->blob); + parcMemory_Deallocate((void **) &address); + *addressPtr = NULL; +} + +void +cpiAddress_AssertValid(const CPIAddress *address) +{ + assertNotNull(address, "Parameter must be non-null CPIAddress *"); +} + +const char * +cpiAddress_TypeToString(CPIAddressType type) +{ + for (int i = 0; cpiAddressTypeString[i].str != NULL; i++) { + if (cpiAddressTypeString[i].type == type) { + return cpiAddressTypeString[i].str; + } + } + trapIllegalValue(type, "Unknown value: %d", type); +} + +CPIAddressType +cpiAddress_StringToType(const char *str) +{ + for (int i = 0; cpiAddressTypeString[i].str != NULL; i++) { + if (strcasecmp(cpiAddressTypeString[i].str, str) == 0) { + return cpiAddressTypeString[i].type; + } + } + trapIllegalValue(str, "Unknown type '%s'", str); +} + +static CPIAddress * +_cpiAddress_Create(CPIAddressType addressType, PARCBuffer *buffer) +{ + CPIAddress *result = parcMemory_AllocateAndClear(sizeof(CPIAddress)); + + assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CPIAddress)); + if (result != NULL) { + result->addressType = addressType; + result->blob = buffer; + } + return result; +} + +CPIAddress * +cpiAddress_CreateFromInet(struct sockaddr_in *addr_in) +{ + assertNotNull(addr_in, "Parameter must be non-null"); + + addr_in->sin_family = AF_INET; + + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in)); + parcBuffer_PutArray(buffer, sizeof(struct sockaddr_in), (uint8_t *) addr_in); + parcBuffer_Flip(buffer); + + CPIAddress *result = _cpiAddress_Create(cpiAddressType_INET, buffer); + + return result; +} + +CPIAddress * +cpiAddress_CreateFromInet6(struct sockaddr_in6 *addr_in6) +{ + assertNotNull(addr_in6, "Parameter must be non-null"); + + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6)); + parcBuffer_PutArray(buffer, sizeof(struct sockaddr_in6), (uint8_t *) addr_in6); + parcBuffer_Flip(buffer); + + CPIAddress *result = _cpiAddress_Create(cpiAddressType_INET6, buffer); + + return result; +} + +CPIAddress * +cpiAddress_CreateFromLink(const uint8_t *linkaddr, size_t length) +{ + assertNotNull(linkaddr, "Parameter must be non-null"); + + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6)); + parcBuffer_PutArray(buffer, length, linkaddr); + parcBuffer_Flip(buffer); + + CPIAddress *result = _cpiAddress_Create(cpiAddressType_LINK, buffer); + return result; +} + +CPIAddress * +cpiAddress_CreateFromInterface(unsigned interfaceIndex) +{ + unsigned netbyteorder = htonl(interfaceIndex); + + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(netbyteorder)); + parcBuffer_PutArray(buffer, sizeof(netbyteorder), (uint8_t *) &netbyteorder); + parcBuffer_Flip(buffer); + + CPIAddress *result = _cpiAddress_Create(cpiAddressType_IFACE, buffer); + return result; +} + +CPIAddress * +cpiAddress_CreateFromUnix(struct sockaddr_un *addr_un) +{ + assertNotNull(addr_un, "Parameter must be non-null"); + + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_un)); + parcBuffer_PutArray(buffer, sizeof(struct sockaddr_un), (uint8_t *) addr_un); + parcBuffer_Flip(buffer); + + CPIAddress *result = _cpiAddress_Create(cpiAddressType_UNIX, buffer); + return result; +} + +CPIAddress * +cpiAddress_Copy(const CPIAddress *original) +{ + cpiAddress_AssertValid(original); + + CPIAddress *result = _cpiAddress_Create(original->addressType, parcBuffer_Copy(original->blob)); + return result; +} + +bool +cpiAddress_Equals(const CPIAddress *a, const CPIAddress *b) +{ + if (a == b) { + return true; + } + + if (a == NULL || b == NULL) { + return false; + } + + if (a->addressType == b->addressType) { + if (parcBuffer_Equals(a->blob, b->blob)) { + return true; + } + } + + return false; +} + +PARCJSON * +cpiAddress_ToJson(const CPIAddress *address) +{ + cpiAddress_AssertValid(address); + + PARCJSON *json = parcJSON_Create(); + PARCBufferComposer *encoded = parcBase64_Encode(parcBufferComposer_Create(), address->blob); + + // we need a NULL at the end of the string. + parcBufferComposer_PutUint8(encoded, 0); + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(encoded); + char *str = parcBuffer_Overlay(buffer, 0); + + parcJSON_AddString(json, cpiAddressType, cpiAddress_TypeToString(address->addressType)); + parcJSON_AddString(json, cpiAddrData, str); + + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&encoded); + + return json; +} + +CPIAddress * +cpiAddress_CreateFromJson(PARCJSON *json) +{ + assertNotNull(json, "Parameter must be non-null"); + + PARCJSONValue *addrFamilyValue = parcJSON_GetValueByName(json, cpiAddressType); + + assertNotNull(addrFamilyValue, "json is not valid, missing %s: %s", cpiAddressType, parcJSON_ToString(json)); + assertTrue(parcJSONValue_IsString(addrFamilyValue), + "%s key is not a number: %s", cpiAddressType, parcJSON_ToString(json)); + + PARCJSONValue *addrDataValue = parcJSON_GetValueByName(json, cpiAddrData); + + assertNotNull(addrDataValue, "json is not valid, missing %s: %s", cpiAddrData, parcJSON_ToString(json)); + + PARCBufferComposer *composer = + parcBase64_Decode(parcBufferComposer_Create(), parcJSONValue_GetString(addrDataValue)); + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + parcBufferComposer_Release(&composer); + + PARCBuffer *sBuf = parcJSONValue_GetString(addrFamilyValue); + + CPIAddress *result = + _cpiAddress_Create(cpiAddress_StringToType(parcBuffer_Overlay(sBuf, 0)), buffer); + + return result; +} + +CPIAddressType +cpiAddress_GetType(const CPIAddress *address) +{ + cpiAddress_AssertValid(address); + + return address->addressType; +} + +// The Get functions need better names, what they do (Get from what? Put to what?) +// is not clear from their names. Case 1028 +bool +cpiAddress_GetInet(const CPIAddress *address, struct sockaddr_in *addr_in) +{ + cpiAddress_AssertValid(address); + assertNotNull(addr_in, "Parameter addr_in must be non-null"); + + if (address->addressType == cpiAddressType_INET) { + assertTrue(parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in), + "CPIAddress corrupted. Expected length %zu, actual length %zu", + sizeof(struct sockaddr_in), + parcBuffer_Remaining(address->blob)); + + memcpy(addr_in, parcBuffer_Overlay(address->blob, 0), sizeof(struct sockaddr_in)); + return true; + } + return false; +} + +bool +cpiAddress_GetInet6(const CPIAddress *address, struct sockaddr_in6 *addr_in6) +{ + cpiAddress_AssertValid(address); + assertNotNull(addr_in6, "Parameter addr_in6 must be non-null"); + + if (address->addressType == cpiAddressType_INET6) { + assertTrue(parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in6), + "CPIAddress corrupted. Expected length %zu, actual length %zu", + sizeof(struct sockaddr_in6), + parcBuffer_Remaining(address->blob)); + + memcpy(addr_in6, parcBuffer_Overlay(address->blob, 0), sizeof(struct sockaddr_in6)); + return true; + } + return false; +} + +bool +cpiAddress_GetUnix(const CPIAddress *address, struct sockaddr_un *addr_un) +{ + cpiAddress_AssertValid(address); + assertNotNull(addr_un, "Parameter addr_in6 must be non-null"); + + if (address->addressType == cpiAddressType_UNIX) { + assertTrue(parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_un), + "CPIAddress corrupted. Expected length %zu, actual length %zu", + sizeof(struct sockaddr_un), + parcBuffer_Remaining(address->blob)); + + memcpy(addr_un, parcBuffer_Overlay(address->blob, 0), sizeof(struct sockaddr_un)); + return true; + } + return false; +} + +bool +cpiAddress_GetInterfaceIndex(const CPIAddress *address, uint32_t *ifidx) +{ + cpiAddress_AssertValid(address); + assertNotNull(ifidx, "Parameter ifidx must be non-null"); + + if (address->addressType == cpiAddressType_IFACE) { + assertTrue(parcBuffer_Remaining(address->blob) == sizeof(uint32_t), + "CPIAddress corrupted. Expected length %zu, actual length %zu", + sizeof(uint32_t), + parcBuffer_Remaining(address->blob)); + + uint32_t netbyteorder; + memcpy(&netbyteorder, parcBuffer_Overlay(address->blob, 0), sizeof(uint32_t)); + *ifidx = ntohl(netbyteorder); + return true; + } + return false; +} + +PARCBuffer * +cpiAddress_GetLinkAddress(const CPIAddress *address) +{ + cpiAddress_AssertValid(address); + if (address->addressType == cpiAddressType_LINK) { + return address->blob; + } + return NULL; +} + +static PARCBufferComposer * +_Inet_BuildString(const CPIAddress *address, PARCBufferComposer *composer) +{ + cpiAddress_AssertValid(address); + + struct sockaddr_in *saddr = (struct sockaddr_in *) parcBuffer_Overlay(address->blob, 0); + return parcNetwork_SockInet4Address_BuildString(saddr, composer); +} + +static PARCBufferComposer * +_Inet6_BuildString(const CPIAddress *address, PARCBufferComposer *composer) +{ + cpiAddress_AssertValid(address); + + struct sockaddr_in6 *saddr = (struct sockaddr_in6 *) parcBuffer_Overlay(address->blob, 0); + return parcNetwork_SockInet6Address_BuildString(saddr, composer); +} + +static PARCBufferComposer * +_Link_BuildString(const CPIAddress *address, PARCBufferComposer *composer) +{ + cpiAddress_AssertValid(address); + + const unsigned char *addr = parcBuffer_Overlay(address->blob, 0); + + size_t length = parcBuffer_Remaining(address->blob); + + return parcNetwork_LinkAddress_BuildString(addr, length, composer); +} + +static ssize_t +_UnixToString(char *output, size_t remaining_size, const PARCBuffer *addr) +{ + assertNotNull(output, "parameter output must be non-null"); + parcBuffer_AssertValid(addr); + + assertTrue(parcBuffer_Remaining(addr) == sizeof(struct sockaddr_un), + "CPIAddress corrupted. Expected %zu actual %zu", + sizeof(struct sockaddr_un), parcBuffer_Remaining(addr)); + + // sockaddr length for the path, 16 for the ascii stuff, 3 for the length number + struct sockaddr_un *saddr = (struct sockaddr_un *) parcBuffer_Overlay((PARCBuffer *) addr, 0); + size_t min_remaining = strlen(saddr->sun_path) + 16 + 3; + assertTrue(remaining_size >= min_remaining, + "Remaining size too small, need at least %zu", min_remaining); + + ssize_t output_length = sprintf(output, "{ .path=%s, .len=%zu }", saddr->sun_path, strlen(saddr->sun_path)); + return output_length; +} + +static ssize_t +_IfaceToString(char *output, size_t remaining_size, const PARCBuffer *addr) +{ + assertNotNull(output, "parameter output must be non-null"); + parcBuffer_AssertValid(addr); + + assertTrue(parcBuffer_Remaining(addr) == sizeof(uint32_t), + "CPIAddress corrupted. Expected %zu actual %zu", + sizeof(uint32_t), parcBuffer_Remaining(addr)); + + uint32_t *ifidx = (uint32_t *) parcBuffer_Overlay((PARCBuffer *) addr, 0); + + ssize_t output_length = sprintf(output, "{ .ifidx=%u }", ntohl(*ifidx)); + + return output_length; +} + +PARCBufferComposer * +cpiAddress_BuildString(const CPIAddress *address, PARCBufferComposer *composer) +{ + if (address != NULL) { + char *str = cpiAddress_ToString(address); + parcBufferComposer_PutString(composer, str); + parcMemory_Deallocate((void **) &str); + } + return composer; +} + +char * +cpiAddress_ToString(const CPIAddress *address) +{ + cpiAddress_AssertValid(address); + + char addrstr[256]; + + switch (address->addressType) { + case cpiAddressType_INET: { + PARCBufferComposer *composer = parcBufferComposer_Create(); + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(_Inet_BuildString(address, composer)); + char *result = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + return result; + } + break; + + case cpiAddressType_INET6: { + PARCBufferComposer *composer = parcBufferComposer_Create(); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(_Inet6_BuildString(address, composer)); + char *result = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + parcBufferComposer_Release(&composer); + return result; + } + break; + + case cpiAddressType_UNIX: + _UnixToString(addrstr, 256, address->blob); + break; + + case cpiAddressType_LINK: { + PARCBufferComposer *composer = parcBufferComposer_Create(); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(_Link_BuildString(address, composer)); + char *result = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + + parcBufferComposer_Release(&composer); + return result; + } + break; + + case cpiAddressType_IFACE: + _IfaceToString(addrstr, 256, address->blob); + break; + + default: + sprintf(addrstr, "UNKNOWN type = %d", address->addressType); + break; + } + + ssize_t alloc_size = 1024; + char *output = parcMemory_Allocate(alloc_size); + assertNotNull(output, "parcMemory_Allocate(%zu) returned NULL", alloc_size); + ssize_t output_length = snprintf(output, alloc_size, "{ .type=%s, .data=%s }", cpiAddress_TypeToString(address->addressType), addrstr); + + assertTrue(output_length < alloc_size, "allocated size too small, needed %zd", output_length); + assertFalse(output_length < 0, "snprintf error: (%d) %s", errno, strerror(errno)); + + return output; +} + +PARCHashCode +cpiAddress_HashCode(const CPIAddress *address) +{ + cpiAddress_AssertValid(address); + + PARCHashCode hash = parcBuffer_HashCode(address->blob); + hash = parcHashCode_HashImpl((uint8_t *) &address->addressType, sizeof(address->addressType), hash); + + return hash; +} |