diff options
Diffstat (limited to 'hicn-light/src/utils/address.c')
-rwxr-xr-x | hicn-light/src/utils/address.c | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/hicn-light/src/utils/address.c b/hicn-light/src/utils/address.c new file mode 100755 index 000000000..3f6fe2591 --- /dev/null +++ b/hicn-light/src/utils/address.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2017-2019 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 <arpa/inet.h> +#include <errno.h> +#include <src/config.h> +#include <stdio.h> +#include <strings.h> +#include <unistd.h> + +#include <src/utils/address.h> + +#include <parc/algol/parc_Base64.h> +#include <parc/algol/parc_BufferComposer.h> +#include <parc/algol/parc_Hash.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_Network.h> +#include <parc/algol/parc_Object.h> + +#include <parc/assert/parc_Assert.h> + +struct address { + address_type addressType; + PARCBuffer *blob; +}; + +static struct address_type_str { + address_type type; + const char *str; +} addressTypeString[] = { + {.type = ADDR_INET, .str = "INET"}, {.type = ADDR_INET6, .str = "INET6"}, + {.type = ADDR_LINK, .str = "LINK"}, {.type = ADDR_IFACE, .str = "IFACE"}, + {.type = ADDR_UNIX, .str = "UNIX"}, {.type = 0, .str = NULL}}; + +void addressDestroy(Address **addressPtr) { + parcAssertNotNull(addressPtr, "Parameter must be non-null double pointer"); + parcAssertNotNull(*addressPtr, + "Parameter must dereference to non-null pointer"); + + Address *address = *addressPtr; + parcBuffer_Release(&address->blob); + parcMemory_Deallocate((void **)&address); + *addressPtr = NULL; +} + +void addressAssertValid(const Address *address) { + parcAssertNotNull(address, "Parameter must be non-null Address *"); +} + +const char *addressTypeToString(address_type type) { + for (int i = 0; addressTypeString[i].str != NULL; i++) { + if (addressTypeString[i].type == type) { + return addressTypeString[i].str; + } + } + parcTrapIllegalValue(type, "Unknown value: %d", type); + const char *result = NULL; + return result; +} + +address_type addressStringToType(const char *str) { + for (int i = 0; addressTypeString[i].str != NULL; i++) { + if (strcasecmp(addressTypeString[i].str, str) == 0) { + return addressTypeString[i].type; + } + } + parcTrapIllegalValue(str, "Unknown type '%s'", str); + return 0; +} + +static Address *_addressCreate(address_type addressType, PARCBuffer *buffer) { + Address *result = parcMemory_AllocateAndClear(sizeof(Address)); + + parcAssertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", + sizeof(Address)); + if (result != NULL) { + result->addressType = addressType; + result->blob = buffer; + } + return result; +} + +Address *addressCreateFromInet(struct sockaddr_in *addr_in) { + parcAssertNotNull(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); + + Address *result = _addressCreate(ADDR_INET, buffer); + + return result; +} + +Address *addressCreateFromInet6(struct sockaddr_in6 *addr_in6) { + parcAssertNotNull(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); + + Address *result = _addressCreate(ADDR_INET6, buffer); + + return result; +} + +Address *addressCreateFromLink(const uint8_t *linkaddr, size_t length) { + parcAssertNotNull(linkaddr, "Parameter must be non-null"); + + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6)); + parcBuffer_PutArray(buffer, length, linkaddr); + parcBuffer_Flip(buffer); + + Address *result = _addressCreate(ADDR_LINK, buffer); + return result; +} + +Address *addressCreateFromInterface(unsigned interfaceIndex) { + unsigned netbyteorder = htonl(interfaceIndex); + + PARCBuffer *buffer = parcBuffer_Allocate(sizeof(netbyteorder)); + parcBuffer_PutArray(buffer, sizeof(netbyteorder), (uint8_t *)&netbyteorder); + parcBuffer_Flip(buffer); + + Address *result = _addressCreate(ADDR_IFACE, buffer); + return result; +} + +Address *addressCreateFromUnix(struct sockaddr_un *addr_un) { + parcAssertNotNull(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); + + Address *result = _addressCreate(ADDR_UNIX, buffer); + return result; +} + +Address *addressCopy(const Address *original) { + addressAssertValid(original); + + Address *result = + _addressCreate(original->addressType, parcBuffer_Copy(original->blob)); + return result; +} + +bool addressEquals(const Address *a, const Address *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; +} + +address_type addressGetType(const Address *address) { + addressAssertValid(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 addressGetInet(const Address *address, struct sockaddr_in *addr_in) { + addressAssertValid(address); + parcAssertNotNull(addr_in, "Parameter addr_in must be non-null"); + + if (address->addressType == ADDR_INET) { + parcAssertTrue( + parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in), + "Address 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 addressGetInet6(const Address *address, struct sockaddr_in6 *addr_in6) { + addressAssertValid(address); + parcAssertNotNull(addr_in6, "Parameter addr_in6 must be non-null"); + + if (address->addressType == ADDR_INET6) { + parcAssertTrue( + parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in6), + "Address 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 addressGetUnix(const Address *address, struct sockaddr_un *addr_un) { + addressAssertValid(address); + parcAssertNotNull(addr_un, "Parameter addr_in6 must be non-null"); + + if (address->addressType == ADDR_UNIX) { + parcAssertTrue( + parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_un), + "Address 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 addressGetInterfaceIndex(const Address *address, uint32_t *ifidx) { + addressAssertValid(address); + parcAssertNotNull(ifidx, "Parameter ifidx must be non-null"); + + if (address->addressType == ADDR_IFACE) { + parcAssertTrue(parcBuffer_Remaining(address->blob) == sizeof(uint32_t), + "Address 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 *addressGetLinkAddress(const Address *address) { + addressAssertValid(address); + if (address->addressType == ADDR_LINK) { + return address->blob; + } + return NULL; +} + +static PARCBufferComposer *_Inet_BuildString(const Address *address, + PARCBufferComposer *composer) { + addressAssertValid(address); + + struct sockaddr_in *saddr = + (struct sockaddr_in *)parcBuffer_Overlay(address->blob, 0); + return parcNetwork_SockInet4Address_BuildString(saddr, composer); +} + +static PARCBufferComposer *_Inet6_BuildString(const Address *address, + PARCBufferComposer *composer) { + addressAssertValid(address); + + struct sockaddr_in6 *saddr = + (struct sockaddr_in6 *)parcBuffer_Overlay(address->blob, 0); + return parcNetwork_SockInet6Address_BuildString(saddr, composer); +} + +static PARCBufferComposer *_Link_BuildString(const Address *address, + PARCBufferComposer *composer) { + addressAssertValid(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) { + parcAssertNotNull(output, "parameter output must be non-null"); + parcBuffer_AssertValid(addr); + + parcAssertTrue(parcBuffer_Remaining(addr) == sizeof(struct sockaddr_un), + "Address 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; + parcAssertTrue(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) { + parcAssertNotNull(output, "parameter output must be non-null"); + parcBuffer_AssertValid(addr); + + parcAssertTrue(parcBuffer_Remaining(addr) == sizeof(uint32_t), + "Address 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 *addressBuildString(const Address *address, + PARCBufferComposer *composer) { + if (address != NULL) { + char *str = addressToString(address); + parcBufferComposer_PutString(composer, str); + parcMemory_Deallocate((void **)&str); + } + return composer; +} + +char *addressToString(const Address *address) { + addressAssertValid(address); + + char addrstr[256]; + + switch (address->addressType) { + case ADDR_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 ADDR_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 ADDR_LINK: + _UnixToString(addrstr, 256, address->blob); + break; + + case ADDR_IFACE: { + 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 ADDR_UNIX: + _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); + parcAssertNotNull(output, "parcMemory_Allocate(%zu) returned NULL", + alloc_size); + ssize_t output_length = + snprintf(output, alloc_size, "{ .type=%s, .data=%s }", + addressTypeToString(address->addressType), addrstr); + + parcAssertTrue(output_length < alloc_size, + "allocated size too small, needed %zd", output_length); + parcAssertFalse(output_length < 0, "snprintf error: (%d) %s", errno, + strerror(errno)); + + return output; +} + +PARCHashCode addressHashCode(const Address *address) { + addressAssertValid(address); + + PARCHashCode hash = parcBuffer_HashCode(address->blob); + hash = parcHashCode_HashImpl((uint8_t *)&address->addressType, + sizeof(address->addressType), hash); + + return hash; +} |