From eb323e056e747d71867cf965434811c1de925de2 Mon Sep 17 00:00:00 2001 From: Luca Muscariello Date: Sat, 23 Mar 2019 14:13:53 +0100 Subject: [HICN-141] Definition of a C API for hicn-light Change-Id: Id861f0abe58b1e3c9ba8cc76701da0f9c6801748 Signed-off-by: Luca Muscariello Signed-off-by: Angelo Mantellini --- hicn-light/src/hicn/utils/CMakeLists.txt | 42 +++ hicn-light/src/hicn/utils/address.c | 450 ++++++++++++++++++++++++++ hicn-light/src/hicn/utils/address.h | 524 +++++++++++++++++++++++++++++++ hicn-light/src/hicn/utils/addressList.c | 133 ++++++++ hicn-light/src/hicn/utils/addressList.h | 196 ++++++++++++ hicn-light/src/hicn/utils/commands.h | 332 ++++++++++++++++++++ hicn-light/src/hicn/utils/interface.c | 168 ++++++++++ hicn-light/src/hicn/utils/interface.h | 208 ++++++++++++ hicn-light/src/hicn/utils/interfaceSet.c | 149 +++++++++ hicn-light/src/hicn/utils/interfaceSet.h | 198 ++++++++++++ hicn-light/src/hicn/utils/punting.c | 98 ++++++ hicn-light/src/hicn/utils/punting.h | 72 +++++ hicn-light/src/hicn/utils/utils.c | 236 ++++++++++++++ hicn-light/src/hicn/utils/utils.h | 70 +++++ 14 files changed, 2876 insertions(+) create mode 100644 hicn-light/src/hicn/utils/CMakeLists.txt create mode 100644 hicn-light/src/hicn/utils/address.c create mode 100644 hicn-light/src/hicn/utils/address.h create mode 100644 hicn-light/src/hicn/utils/addressList.c create mode 100644 hicn-light/src/hicn/utils/addressList.h create mode 100644 hicn-light/src/hicn/utils/commands.h create mode 100644 hicn-light/src/hicn/utils/interface.c create mode 100644 hicn-light/src/hicn/utils/interface.h create mode 100644 hicn-light/src/hicn/utils/interfaceSet.c create mode 100644 hicn-light/src/hicn/utils/interfaceSet.h create mode 100644 hicn-light/src/hicn/utils/punting.c create mode 100644 hicn-light/src/hicn/utils/punting.h create mode 100644 hicn-light/src/hicn/utils/utils.c create mode 100644 hicn-light/src/hicn/utils/utils.h (limited to 'hicn-light/src/hicn/utils') diff --git a/hicn-light/src/hicn/utils/CMakeLists.txt b/hicn-light/src/hicn/utils/CMakeLists.txt new file mode 100644 index 000000000..120061211 --- /dev/null +++ b/hicn-light/src/hicn/utils/CMakeLists.txt @@ -0,0 +1,42 @@ +# 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. + +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +list(APPEND HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/address.h + ${CMAKE_CURRENT_SOURCE_DIR}/addressList.h + ${CMAKE_CURRENT_SOURCE_DIR}/commands.h + ${CMAKE_CURRENT_SOURCE_DIR}/interface.h + ${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.h + ${CMAKE_CURRENT_SOURCE_DIR}/punting.h + ${CMAKE_CURRENT_SOURCE_DIR}/utils.h +) + +list(APPEND SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/address.c + ${CMAKE_CURRENT_SOURCE_DIR}/addressList.c + ${CMAKE_CURRENT_SOURCE_DIR}/interface.c + ${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.c + ${CMAKE_CURRENT_SOURCE_DIR}/punting.c + ${CMAKE_CURRENT_SOURCE_DIR}/utils.c +) + +set(TO_INSTALL_HEADER_FILES + ${TO_INSTALL_HEADER_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/commands.h + PARENT_SCOPE +) + +set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) \ No newline at end of file diff --git a/hicn-light/src/hicn/utils/address.c b/hicn-light/src/hicn/utils/address.c new file mode 100644 index 000000000..fe222a43c --- /dev/null +++ b/hicn-light/src/hicn/utils/address.c @@ -0,0 +1,450 @@ +/* + * 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. + */ + +#ifndef _WIN32 +#include +#include +#endif +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +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 *addressFromInaddr4Port(in_addr_t *addr4, in_port_t *port) { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + + // We assume address and port are already written in memory in network byte + // order + addr.sin_family = AF_INET; + addr.sin_port = *port; + addr.sin_addr.s_addr = *addr4; + + Address *result = addressCreateFromInet(&addr); + return result; +} + +Address *addressFromInaddr6Port(struct in6_addr *addr6, in_port_t *port) { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + + // We assume address and port are already written in memory in network byte + // order + addr.sin6_port = *port; + addr.sin6_addr = *addr6; + addr.sin6_scope_id = 0; + // Other 2 fields: scope_id and flowinfo, do not know what to put inside. + + Address *result = addressCreateFromInet6(&addr); + 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; +} diff --git a/hicn-light/src/hicn/utils/address.h b/hicn-light/src/hicn/utils/address.h new file mode 100644 index 000000000..6ca98347a --- /dev/null +++ b/hicn-light/src/hicn/utils/address.h @@ -0,0 +1,524 @@ +/* + * 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. + */ + +/** + * @brief Represents an endpoint address. + * + * Represents an endpoint address. May be INET, INET6, or a multi-byte LINK, + * or an Interface Index. + * + * INET and INET6 must contain the .sa_addr member, and other members as needed + * by the use of the address. + * + * The Interface Index address is essentially a pointer to a device. + * + * + * Example: + * @code + * <#example#> + * @endcode + */ +#ifndef address_h +#define address_h + +#ifndef _WIN32 +#include +#include +#endif +#include + +#include +#include +#include + +/** + * Return a string representation of the given `address_type` + * + * @param [in] type A valid address_type value. + * + * @return NULL An error occurred + * @return non-NULL A pointer to a static string representation of the + * `address_type`. + * + * Example: + * @code + * { + * const char *typeAsString = addressTypeToString(commandAddrType_INET); + * } + * @endcode + * + * @see addressStringToType + */ +const char *addressTypeToString(address_type type); + +/** + * Return a `address_type` from the given nul-terminated C string. + * + * @param [in] typeAsString A nul-terminated, C string representation of a + * `address_type`. + * + * @return A address_type + * + * Example: + * @code + * { + * address_type type = addressTypeToString("INET"); + * } + * @endcode + * + * @see addressTypeToString + */ +address_type addressStringToType(const char *typeAsString); + +struct address; +typedef struct address Address; + +/** + * Create a new `Address` instance from an IPv4 IP address, the port is + * optional. + * + * The sockaddr_in should be filled in network byte order. The newly created + * instance must eventually be destroyed by calling {@link addressDestroy}(). + * + * @param [in] addr_in The `sockaddr_in` representing the IPv4 IP address with + * which to initialize the new `Address` instance. + * @return A new instance of `Address` that must eventually be destroyed by + * calling {@link addressDestroy}(). + * + * Example: + * @code + * { + * Address *dest = addressCreateFromInet( + * &(struct sockaddr_in) { + * .sa_addr = + * inet_addr("foo.bar.com"), .sa_port = htons(9695) } ); addressDestroy(&dest); + * } + * @endcode + * @see addressDestroy + */ +Address *addressCreateFromInet(struct sockaddr_in *addr_in); + +/** + * Create a new `Address` instance from an IPv6 IP address, the port is + * optional. + * + * + * The sockaddr_in should be filled in network byte order. The newly created + * instance must eventually be destroyed by calling {@link addressDestroy}(). + * + * @param [in] addr_in6 A `sockaddr_in6` from which to initialize a new instance + * of Address + * @return A new instance of `Address` that must eventually be destroyed by + * calling {@link addressDestroy}() + * + * Example: + * @code + * { + * struct sockaddr_in6 addr_in6; + * memset(&addr_in6, 0, sizeof(struct sockaddr_in6)); + * + * inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr)); + * addr_in6.sin6_family = AF_INET6; + * addr_in6.sin6_port = 0x0A0B; + * addr_in6.sin6_flowinfo = 0x01020304; + * + * Address *address = addressCreateFromInet6(&addr_in6); + * + * addressDestroy(&address); + * } + * @endcode + * @see addressDestroy + */ +Address *addressCreateFromInet6(struct sockaddr_in6 *addr_in6); + +/** + * Convert an internet address family (IPv4) to the address format used by the + * Fwd. + * + * @param [in] addr4 IPV4 address in *Network byte order* + * @param [in] port Port number in *Network byte order* + * + * @return A new instance of `Address` that must eventually be destroyed by + * calling {@link addressDestroy}() + */ +Address *addressFromInaddr4Port(in_addr_t *addr4, in_port_t *port); + +/** + * Convert an internet address family (IPv6) to the address format used by the + * Fwd + * + * @param [in] addr6 IPV4 address in *Network byte order* + * @param [in] port Port number in *Network byte order* + * + * @return A new instance of `Address` that must eventually be destroyed by + * calling {@link addressDestroy}() + */ +Address *addressFromInaddr6Port(struct in6_addr *addr6, in_port_t *port); + +/** + * Create a new `Address` instance, initialized from a Link address. + * + * User must know the link address format (i.e. token ring vs ethernet) and have + * the address in a byte array. The array is encoded in left-to-right order. The + * newly created instance must eventually be destroyed by calling {@link + * addressDestroy}(). + * + * @param [in] linkaddr A byte array containing the link address + * @param [in] length The length of the link address byte array + * @return A new instance of `Address` that must eventually be destroyed by + * calling {@link addressDestroy}() + * + * Example: + * @code + * { + * uint8_t mac[] = { 0x14, 0x10, 0x9f, 0xd7, 0x0b, 0x89 }; + * Address *address = addressCreateFromLink(mac, sizeof(mac)); + * + * addressDestroy(&address); + * } + * @endcode + * @see addressDestroy + */ +Address *addressCreateFromLink(const uint8_t *linkaddr, size_t length); + +/** + * Create a new `Address` instance from a network interface index. + * + * The interfaceIndex should be in host byte order. The newly created instance + * must eventually be destroyed by calling {@link addressDestroy}(). + * + * @param [in] interfaceIndex The index of the interface to encode + * @return A new instance of `Address` that must eventually be destroyed by + * calling {@link addressDestroy}() + * + * Example: + * @code + * { + * Address *address = addressCreateFromInterface(2); + * + * addressDestroy(&address); + * } + * @endcode + * @see addressDestroy + */ +Address *addressCreateFromInterface(uint32_t interfaceIndex); + +/** + * Create a new Address instance from a PF_UNIX address domain. + * + * The newly created instance must eventually be destroyed by calling {@link + * addressDestroy}(). + * + * @param [in] addr_un The `struct sockaddr_un` specifying the local PF_UNIX + * socket address + * @return A new instance of `Address` that must eventually be destroyed by + * calling {@link addressDestroy}() + * + * Example: + * @code + * { + * struct sockaddr_un addr_unix; + * memset(&addr_unix, 0, sizeof(struct sockaddr_un)); + * char path[] = "/Hello/Cruel/World"; + * strcpy(addr_un.sun_path, path); + * addr_un.sun_family = AF_UNIX; + * + * Address *address = addressCreateFromUnix(&addr_un); + * + * addressDestroy(&address); + * } + * @endcode + * @see addressDestroy + */ +Address *addressCreateFromUnix(struct sockaddr_un *addr_un); + +/** + * Create a deep copy of an instance of a `Address`. A completely new, + * indedependent instance is created. + * + * The newly created instance must eventually be destroyed by calling {@link + * addressDestroy}(). + * + * @param [in] original A pointer to a `Address` instance to be copied. + * @return A new instance of a Address, deep copied from the `original` + * instance. + * + * Example: + * @code + * { + * Address *address = addressCreateFromInterface(2); + * + * Address *copy = addressCopy(address); + * + * addressDestroy(&address); + * addressDestroy(©); + * } + * @endcode + * @see addressDestroy + */ +Address *addressCopy(const Address *original); + +/** + * Deallocate an instance of a Address. + * + * The Address instance is deallocated, and any referenced data is also + * deallocated. The referenced pointer is set to NULL upon return. + * + * @param [in] addressPtr A pointer to a pointer to an instance of Address. + * + * Example: + * @code + * { + * Address *address = addressCreateFromInterface(2); + * + * addressDestroy(&address); + * } + * @endcode + */ +void addressDestroy(Address **addressPtr); + +/** + * Determine if two Address instances are equal. + * + * + * The following equivalence relations on non-null `Address` instances are + * maintained: + * + * * It is reflexive: for any non-null reference value x, `addressEquals(x, x)` + * must return true. + * + * * It is symmetric: for any non-null reference values x and y, + * `addressEquals(x, y)` must return true if and only if + * `addressEquals(y, x)` returns true. + * + * * It is transitive: for any non-null reference values x, y, and z, if + * `addressEquals(x, y)` returns true and + * `addressEquals(y, z)` returns true, + * then `addressEquals(x, z)` must return true. + * + * * It is consistent: for any non-null reference values x and y, multiple + * invocations of `addressEquals(x, y)` consistently return true or + * consistently return false. + * + * * For any non-null reference value x, `addressEquals(x, NULL)` must + * return false. + * + * If one address specifies more information than other, + * e.g. a is INET with a port and b is not, they are not equal. + * + * `a` and `b` may be NULL, and NULL == NULL. + * + * @param a A pointer to a Address instance + * @param b A pointer to a Address instance + * @return true if the two instances are equal + * @return false if the two instances are not equal + * + * Example: + * @code + * { + * Address *address = addressCreateFromInterface(2); + * Address *copy = addressCopy(address); + * + * if (addressEquals(address, copy)) { + * // true + * } else { + * // false + * } + * + * addressDestroy(&address); + * addressDestroy(©); + * } + * @endcode + */ +bool addressEquals(const Address *a, const Address *b); + +/** + * Return the {@link address_type} from a specified Address. + * + * @param [in] A pointer to a Address instance + * + * @return the {@link address_type} of the specified Address instance + * + * Example: + * @code + * { + * Address *address = addressCreateFromInterface(2); + * + * address_type type = addressGetType(address); + * + * addressDestroy(&address); + * } + * @endcode + * + * @see address_type + */ +address_type addressGetType(const Address *address); + +/** + * Fills in the output parameter with an INET address. + * + * @param addr_in must be non-NULL + * @return true if INET address and output filled in, false otherwise. + * + */ +bool addressGetInet(const Address *address, struct sockaddr_in *addr_in); + +/** + * Retrieve the INET6 address associated with a `Address` instance. + * + * If the specified Address instance is of type {@link commandAddrType_INET6}, + * then populate the supplied `struct sockaddr_in6` from the Address and return + * true. If the Address is not of type `commandAddrType_INET6`, this function + * returns false. + * + * @param [in] address A pointer to a `Address` instance of type {@link + * commandAddrType_INET6}. + * @param [in] addr_in6 A pointer to a `struct sockaddr_in6`. Must be non-NULL. + * @return true If the Address instance is of type `commandAddrType_INET6` and + * `addr_in6` was filled in + * @return false If the Address instance was not of type `commandAddrType_INET6` + * or `addr_in6` could not be filled in. + * + * @see addressGetType + */ +bool addressGetInet6(const Address *address, struct sockaddr_in6 *addr_in6); + +/** + * Retrieve the interface index associated with a `Address` instance. + * + * If the specified `Address` instance is of type {@link commandAddrType_IFACE}, + * then populate the supplied `uint32_t` from the Address and return true. If + * the `Address` is not of type `commandAddrType_INET6`, this function returns + * false. + * + * @param [in] address A pointer to a `Address` instance of type {@link + * commandAddrType_IFACE}. + * @param [in] interfaceIndex A pointer to a `uint32_t` to fill in. Must be + * non-NULL. + * @return true If the Address instance is of type `commandAddrType_IFACE` and + * `interfaceIndex` was filled in. + * @return false If the Address instance was not of type `commandAddrType_IFACE` + * or `interfaceIndex` could not be filled in. + * + * @see addressGetType + */ +bool addressGetInterfaceIndex(const Address *address, uint32_t *interfaceIndex); + +/** + * Retrieve the link address associated with a `Address` instance. + * + * If the specified `Address` instance is of type {@link commandAddrType_LINK}, + * then return a pointer to the {@link PARCBuffer} containing the link address. + * If the `Address` is not of type {@link commandAddrType_LINK}, then return + * NULL. The returned PARCBuffer pointer points to memory managed by the Address + * instance, and does not need to be destroyed or released on its own. + * + * @param [in] address A pointer to a `Address` instance of type {@link + * commandAddrType_LINK}. + * @return A pointer to the {@link PARCBuffer} containing the link address. + * + * Example: + * @code + * { + * uint8_t mac[] = { 0x14, 0x10, 0x9f, 0xd7, 0x0b, 0x89 }; + * Address *address = addressCreateFromLink(mac, sizeof(mac)); + * + * PARCBuffer *macBuffer = addressGetLinkAddress(address); + * + * addressDestroy(&address); + * } + * @endcode + * @see addressGetType + */ +PARCBuffer *addressGetLinkAddress(const Address *address); + +/** + * Append the string representation of a `Address` to a specified + * `PARCBufferComposer`. + * + * @param [in] address A pointer to a `Address` instance. + * @param [in] composer A pointer to a `PARCBufferComposer` instance to which to + * append the string. + * + * @return The `PARCBufferComposer` instance that was passed in. + * + * Example: + * @code + * { + * Address *address = addressCreateFromInterface(1); + * PARCBufferComposer *composer = addressBuildString(address, + * parcBufferComposer_Create()); parcBufferComposer_Release(&composer); + * addressDestroy(&address); + * } + * @endcode + * + * @see PARCBufferComposer + */ +PARCBufferComposer *addressBuildString(const Address *address, + PARCBufferComposer *composer); + +/** + * Produce a nil-terminated string representation of the specified instance. + * + * The result must be freed by the caller via {@link parcMemory_Deallocate}. + * + * @param [in] interest A pointer to the instance. + * + * @return NULL Cannot allocate memory. + * @return non-NULL A pointer to an allocated, nul-terminated C string that must + * be deallocated via {@link parcMemory_Deallocate}(). + * + * Example: + * @code + * { + * Address *address = addressCreateFromInterface(1); + * + * char *string = addressToString(address); + * + * if (string != NULL) { + * printf("Address looks like: %s\n", string); + * parcMemory_Deallocate(string); + * } else { + * printf("Cannot allocate memory\n"); + * } + * + * addressDestroy(&address); + * } + * @endcode + * @see parcMemory_Deallocate + * @see addressBuildString + */ +char *addressToString(const Address *address); + +/** + * Return a non-cryptographic hash code consistent with Equals + * + * If commandAddrA == commandAddrB, then addressHashCode(commandAddrA) == + * addressHashCode(commandAddrB) + * + * @param [in] address A pointer to a Address instance. + * @return A 32-bit hashcode for the specified Address instance. + * + * Example: + * @code + * Address *address = addressCreateFromInterface(1); + * + * uint32_t hashCode = addressHashCode(address); + * + * addressDestroy(&address); + * @endcode + */ +PARCHashCode addressHashCode(const Address *address); +#endif // address_h diff --git a/hicn-light/src/hicn/utils/addressList.c b/hicn-light/src/hicn/utils/addressList.c new file mode 100644 index 000000000..434ceb7ca --- /dev/null +++ b/hicn-light/src/hicn/utils/addressList.c @@ -0,0 +1,133 @@ +/* + * 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 +#include + +#include + +#include + +#include +#include +#include + +struct address_list { + PARCArrayList *listOfAddress; +}; + +static void _addressListFreeAddress(void **addressVoidPtr) { + Address **addressPtr = (Address **)addressVoidPtr; + addressDestroy(addressPtr); +} + +AddressList *addressListCreate() { + AddressList *list = parcMemory_AllocateAndClear(sizeof(AddressList)); + parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL", + sizeof(AddressList)); + list->listOfAddress = parcArrayList_Create(_addressListFreeAddress); + parcAssertNotNull(list->listOfAddress, "Got null from parcArrayList_Create"); + + return list; +} + +void addressListDestroy(AddressList **addressListPtr) { + parcAssertNotNull(addressListPtr, + "Parameter must be non-null double pointer"); + parcAssertNotNull(*addressListPtr, + "Parameter must dereference to non-null pointer"); + AddressList *list = *addressListPtr; + + parcArrayList_Destroy(&list->listOfAddress); + parcMemory_Deallocate((void **)&list); + *addressListPtr = NULL; +} + +AddressList *addressListAppend(AddressList *list, Address *address) { + parcAssertNotNull(list, "Parameter list must be non-null"); + parcAssertNotNull(address, "Parameter address must be non-null"); + + parcArrayList_Add(list->listOfAddress, (PARCObject *)address); + return list; +} + +AddressList *addressListCopy(const AddressList *original) { + parcAssertNotNull(original, "Parameter must be non-null"); + + AddressList *copy = addressListCreate(); + for (int i = 0; i < parcArrayList_Size(original->listOfAddress); i++) { + Address *address = (Address *)parcArrayList_Get(original->listOfAddress, i); + parcArrayList_Add(copy->listOfAddress, (PARCObject *)addressCopy(address)); + } + + return copy; +} + +bool addressListEquals(const AddressList *a, const AddressList *b) { + parcAssertNotNull(a, "Parameter a must be non-null"); + parcAssertNotNull(b, "Parameter b must be non-null"); + + if (a == b) { + return true; + } + + if (parcArrayList_Size(a->listOfAddress) != + parcArrayList_Size(b->listOfAddress)) { + return false; + } + + for (size_t i = 0; i < parcArrayList_Size(a->listOfAddress); i++) { + const Address *addr_a = (Address *)parcArrayList_Get(a->listOfAddress, i); + const Address *addr_b = (Address *)parcArrayList_Get(b->listOfAddress, i); + if (!addressEquals(addr_a, addr_b)) { + return false; + } + } + return true; +} + +size_t addressListLength(const AddressList *list) { + parcAssertNotNull(list, "Parameter must be non-null"); + return parcArrayList_Size(list->listOfAddress); +} + +const Address *addressListGetItem(const AddressList *list, size_t item) { + parcAssertNotNull(list, "Parameter must be non-null"); + parcAssertTrue(item < addressListLength(list), + "Asked for item %zu beyond end of list %zu", item, + addressListLength(list)); + + return (Address *)parcArrayList_Get(list->listOfAddress, item); +} + +char *addressListToString(const AddressList *list) { + PARCBufferComposer *composer = parcBufferComposer_Create(); + + for (size_t i = 0; i < addressListLength(list); i++) { + char *addressString = addressToString(addressListGetItem(list, i)); + parcBufferComposer_PutString(composer, addressString); + if (i < (addressListLength(list) - 1)) { + parcBufferComposer_PutString(composer, " "); + } + parcMemory_Deallocate((void **)&addressString); + } + + PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer); + char *result = parcBuffer_ToString(buffer); + parcBuffer_Release(&buffer); + parcBufferComposer_Release(&composer); + + return result; +} diff --git a/hicn-light/src/hicn/utils/addressList.h b/hicn-light/src/hicn/utils/addressList.h new file mode 100644 index 000000000..823b0c8cb --- /dev/null +++ b/hicn-light/src/hicn/utils/addressList.h @@ -0,0 +1,196 @@ +/* + * 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. + */ + +/** + * @brief A list of Address instances. + * + * An AddressList is a list of addresses. + * It wraps a PARCLinkedList for type saftey with Address. + * + */ +#ifndef address_list_h +#define address_list_h + +#include + +struct address_list; +/** + * @typedef AddressList + * @abstract A list of Address instance pointers. + */ +typedef struct address_list AddressList; + +/** + * Create an instance of {@link AddressList} + * + * @return NULL An error occurred + * @return non-NULL A pointer to a valid AddressList instance. + * + * Example: + * @code + * { + * AddressList *list = addressListCreate(); + * + * } + * @endcode + * + * @see addressListDestroy + */ +AddressList *addressListCreate(void); + +/** + * Dellocate and destroy a AddressList instance. + * + * @param [in] addressListPtr A pointer to a pointer to a valid {@link + * AddressList}. + * + * + * Example: + * @code + * { + * AddressList *list = addressListCreate(void); + * addressListDestroy(&list); + * } + * @endcode + * + * @see addressListCreate + */ +void addressListDestroy(AddressList **addressListPtr); + +/** + * Appends the address, taking ownership of the memory + * + * @param list A pointer to a AddressList. + * @param address must be non-null + * @return The input list + * + * Example: + * @code + * <#example#> + * @endcode + */ +AddressList *addressListAppend(AddressList *list, Address *address); + +/** + * Creates a reference counted copy + * + * @param list A pointer to a valid {@link AddressList}. + * + * @return An allocated list, you must destroy it. + * + * Example: + * @code + * <#example#> + * @endcode + */ +AddressList *addressListCopy(const AddressList *list); + +/** + * Determine if two AddressList instances are equal. + * + * Two AddressList instances are equal if, and only if, they have the same + * length, with the same elements in the same order. + * + * + * The following equivalence relations on non-null `AddressList` instances are + * maintained: + * + * * It is reflexive: for any non-null reference value x, + * `AddressList_Equals(x, x)` must return true. + * + * * It is symmetric: for any non-null reference values x and y, + * `AddressList_Equals(x, y)` must return true if and only if + * `addressListEquals(y, x)` returns true. + * + * * It is transitive: for any non-null reference values x, y, and z, if + * `addressListEquals(x, y)` returns true and + * `addressListEquals(y, z)` returns true, + * then `addressListEquals(x, z)` must return true. + * + * * It is consistent: for any non-null reference values x and y, multiple + * invocations of `addressListEquals(x, y)` consistently return true or + * consistently return false. + * + * * For any non-null reference value x, `addressListEquals(x, NULL)` must + * return false. + * + * @param a A pointer to a `AddressList` instance. + * @param b A pointer to a `AddressList` instance. + * @return true if the two `AddressList` instances are equal. + * + * Example: + * @code + * { + * AddressList *a = addressListCreate(); + * AddressList *b = addressListCreate(); + * + * if (addressListEquals(a, b)) { + * // true + * } else { + * // false + * } + * } + * @endcode + */ +bool addressListEquals(const AddressList *a, const AddressList *b); + +/** + * Get the number of items in the list + * + * @param list A pointer to a {@link AddressList}. + * @return The number of items in the list. + * + * Example: + * @code + * <#example#> + * @endcode + */ +size_t addressListLength(const AddressList *list); + +/** + * Returns a const reference to an item. + * Use addressCopy if needed. + * + * Do not free or modify the returned value. + * Use addressCopy if you need a mutable instance. + * + * @param list A pointer to a AddressList. + * @param item A value less than the number of items in the given {@link + * AddressList}. + * @return Asserts if item off end of list. + * + * Example: + * @code + * <#example#> + * @endcode + */ +const Address *addressListGetItem(const AddressList *list, size_t item); + +/** + * Get a nul-terminated, C-string representation of the given {@link + * AddressList}. + * + * @param list A pointer to a valid {@link AddressList} instance. + * + * @return An allocate string representation of the {@link AddressList} that + * must be freed via `parcMemory_Deallocate()`. + * + * Example: + * @code + * <#example#> + * @endcode + */ +char *addressListToString(const AddressList *list); +#endif // address_list_h diff --git a/hicn-light/src/hicn/utils/commands.h b/hicn-light/src/hicn/utils/commands.h new file mode 100644 index 000000000..9527e5064 --- /dev/null +++ b/hicn-light/src/hicn/utils/commands.h @@ -0,0 +1,332 @@ +/* + * 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. + */ + +/* + * @file commands.h + * @brief All hicn-light commands: 14 in total. + * + * Header and payload in binary format. + */ + +#ifndef commands_h +#define commands_h + +#ifndef _WIN32 +#include +#include +#endif + +#include +#include + +typedef struct in6_addr ipv6_addr_t; +typedef uint32_t ipv4_addr_t; + +union commandAddr { + ipv4_addr_t ipv4; + ipv6_addr_t ipv6; +}; + +typedef enum { + REQUEST_LIGHT = 0xc0, // this is a command + RESPONSE_LIGHT, + ACK_LIGHT, + NACK_LIGHT, + LAST_MSG_TYPE_VALUE +} message_type; + +typedef enum { + ADD_LISTENER = 0, + ADD_CONNECTION, + LIST_CONNECTIONS, + ADD_ROUTE, + LIST_ROUTES, + REMOVE_CONNECTION, + REMOVE_ROUTE, + CACHE_STORE, + CACHE_SERVE, + CACHE_CLEAR, + SET_STRATEGY, + SET_WLDR, + ADD_PUNTING, + LIST_LISTENERS, + MAPME_ENABLE, + MAPME_DISCOVERY, + MAPME_TIMESCALE, + MAPME_RETX, + LAST_COMMAND_VALUE +} command_id; + +typedef enum { + ADDR_INET = 1, + ADDR_INET6, + ADDR_LINK, + ADDR_IFACE, + ADDR_UNIX /* PF_UNIX */ +} address_type; + +typedef enum { + UDP_CONN, + TCP_CONN, + GRE_CONN, // not implemented + HICN_CONN +} connection_type; + +typedef enum { ACTIVATE_ON, ACTIVATE_OFF } activate_type; + +//========== HEADER ========== + +typedef struct { + uint8_t messageType; + uint8_t commandID; + uint16_t length; // tells the number of structures in the payload + uint32_t seqNum; +} header_control_message; +// for the moment has to be at least 8 bytes + +// SIZE=8 + +//========== [00] ADD LISTENER ========== + +typedef enum { ETHER_MODE, IP_MODE, HICN_MODE } listener_mode; + +typedef struct { + char symbolic[16]; + // char interfaceName[16]; + union commandAddr address; + uint16_t port; + // uint16_t etherType; + uint8_t addressType; + uint8_t listenerMode; + uint8_t connectionType; +} add_listener_command; + +// SIZE=40 + +//========== [01] ADD CONNECTION ========== + +typedef struct { + char symbolic[16]; + union commandAddr remoteIp; + union commandAddr localIp; + uint16_t remotePort; + uint16_t localPort; + uint8_t ipType; + uint8_t connectionType; +} add_connection_command; + +// SIZE=56 + +//========== [02] LIST CONNECTIONS ========== + +typedef enum { + CONN_GRE, + CONN_TCP, + CONN_UDP, + CONN_MULTICAST, + CONN_L2, + CONN_HICN +} list_connections_type; + +typedef enum { + IFACE_UP = 0, + IFACE_DOWN = 1, + IFACE_UNKNOWN = 2 // not used actually +} connection_state; + +typedef struct { + add_connection_command connectionData; + uint32_t connid; + uint8_t state; +} list_connections_command; + +// SIZE=64 + +//========== [03] ADD ROUTE ========== + +typedef struct { + char symbolicOrConnid[16]; + union commandAddr address; + uint16_t cost; + uint8_t addressType; + uint8_t len; +} add_route_command; + +// SIZE=36 + +//========== [04] LIST ROUTE ========== + +typedef struct { + union commandAddr address; + uint32_t connid; + uint16_t cost; + uint8_t addressType; + uint8_t len; +} list_routes_command; + +// SIZE=24 + +//========== [05] REMOVE CONNECTION ========== + +typedef struct { + char symbolicOrConnid[16]; +} remove_connection_command; + +// SIZE=16 + +//========== [06] REMOVE ROUTE ========== + +typedef struct { + char symbolicOrConnid[16]; + union commandAddr address; + uint8_t addressType; + uint8_t len; +} remove_route_command; + +// SIZE=36 + +//========== [07] CACHE STORE ========== + +typedef struct { + uint8_t activate; +} cache_store_command; + +// SIZE=1 + +//========== [08] CACHE SERVE ========== + +typedef struct { + uint8_t activate; +} cache_serve_command; + +// SIZE=1 + +//========== [09] SET STRATEGY ========== + +typedef enum { + SET_STRATEGY_LOADBALANCER, + SET_STRATEGY_RANDOM, + SET_STRATEGY_RANDOM_PER_DASH_SEGMENT, + SET_STRATEGY_LOADBALANCER_WITH_DELAY, + SET_STRATEGY_LOADBALANCER_BY_RATE, + SET_STRATEGY_LOADBALANCER_BEST_ROUTE, + LAST_STRATEGY_VALUE +} strategy_type; + +typedef struct { + union commandAddr address; + uint8_t strategyType; + uint8_t addressType; + uint8_t len; +} set_strategy_command; + +// SIZE=20 + +//========== [11] SET WLDR ========== + +typedef struct { + char symbolicOrConnid[16]; + uint8_t activate; +} set_wldr_command; + +// SIZE=17 + +//========== [12] ADD PUNTING ========== + +typedef struct { + char symbolicOrConnid[16]; + union commandAddr address; + uint8_t addressType; + uint8_t len; +} add_punting_command; + +// SIZE=36 + +//========== [13] LIST LISTENER ========== + +typedef struct { + union commandAddr address; + uint32_t connid; + uint16_t port; + uint8_t addressType; + uint8_t encapType; +} list_listeners_command; + +// SIZE=24 + +//========== [14] MAPME ========== + +// (enable/discovery/timescale/retx) + +typedef struct { + uint8_t activate; +} mapme_activator_command; + +// SIZE=1 + +typedef struct { + uint32_t timePeriod; +} mapme_timing_command; + +// SIZE=1 + +//===== size of commands ====== +// REMINDER: when a new_command is added, the following switch has to be +// updated. +static inline int payloadLengthDaemon(command_id id) { + switch (id) { + case ADD_LISTENER: + return sizeof(add_listener_command); + case ADD_CONNECTION: + return sizeof(add_connection_command); + case LIST_CONNECTIONS: + return 0; // list connections: payload always 0 + case ADD_ROUTE: + return sizeof(add_route_command); + case LIST_ROUTES: + return 0; // list routes: payload always 0 + case REMOVE_CONNECTION: + return sizeof(remove_connection_command); + case REMOVE_ROUTE: + return sizeof(remove_route_command); + case CACHE_STORE: + return sizeof(cache_store_command); + case CACHE_SERVE: + return sizeof(cache_serve_command); + case CACHE_CLEAR: + return 0; // cache clear + case SET_STRATEGY: + return sizeof(set_strategy_command); + case SET_WLDR: + return sizeof(set_wldr_command); + case ADD_PUNTING: + return sizeof(add_punting_command); + case LIST_LISTENERS: + return 0; // list listeners: payload always 0 + case MAPME_ENABLE: + return sizeof(mapme_activator_command); + case MAPME_DISCOVERY: + return sizeof(mapme_activator_command); + case MAPME_TIMESCALE: + return sizeof(mapme_timing_command); + case MAPME_RETX: + return sizeof(mapme_timing_command); + case LAST_COMMAND_VALUE: + return 0; + default: + return 0; + } +} +#endif diff --git a/hicn-light/src/hicn/utils/interface.c b/hicn-light/src/hicn/utils/interface.c new file mode 100644 index 000000000..dce9ed8f3 --- /dev/null +++ b/hicn-light/src/hicn/utils/interface.c @@ -0,0 +1,168 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +struct interface { + char *name; + unsigned interfaceIndex; + bool loopback; + bool supportMulticast; + unsigned mtu; + + AddressList *addressList; +}; + +char *interfaceToString(const Interface *interface) { + PARCBufferComposer *composer = parcBufferComposer_Create(); + + parcBufferComposer_Format( + composer, "%3u %10s %1s%1s %8u ", interface->interfaceIndex, + interface->name, interface->loopback ? "l" : " ", + interface->supportMulticast ? "m" : " ", interface->mtu); + + for (size_t i = 0; i < addressListLength(interface->addressList); i++) { + addressBuildString(addressListGetItem(interface->addressList, i), composer); + if (i < (addressListLength(interface->addressList) - 1)) { + parcBufferComposer_PutStrings(composer, "\n", NULL); + } + } + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *result = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + return result; +} + +Interface *interfaceCreate(const char *name, unsigned interfaceIndex, + bool loopback, bool supportMulticast, unsigned mtu) { + Interface *iface = parcMemory_AllocateAndClear(sizeof(Interface)); + + parcAssertNotNull(iface, "parcMemory_AllocateAndClear(%zu) returned NULL", + sizeof(Interface)); + iface->name = parcMemory_StringDuplicate(name, 64); + iface->interfaceIndex = interfaceIndex; + iface->loopback = loopback; + iface->supportMulticast = supportMulticast; + iface->mtu = mtu; + iface->addressList = addressListCreate(); + + return iface; +} + +void interfaceDestroy(Interface **interfacePtr) { + parcAssertNotNull(interfacePtr, "Parameter must be non-null double pointer"); + parcAssertNotNull(*interfacePtr, + "Parameter must dereference to non-null pointer"); + + Interface *iface = *interfacePtr; + parcMemory_Deallocate((void **)&iface->name); + addressListDestroy(&iface->addressList); + parcMemory_Deallocate((void **)&iface); + interfacePtr = NULL; +} + +void interfaceAddAddress(Interface *iface, Address *address) { + parcAssertNotNull(iface, "Parameter iface must be non-null"); + + size_t length = addressListLength(iface->addressList); + for (size_t i = 0; i < length; i++) { + const Address *a = addressListGetItem(iface->addressList, i); + if (addressEquals(a, address)) { + return; + } + } + + addressListAppend(iface->addressList, address); +} + +const AddressList *interfaceGetAddresses(const Interface *iface) { + parcAssertNotNull(iface, "Parameter iface must be non-null"); + return iface->addressList; +} + +unsigned interfaceGetInterfaceIndex(const Interface *iface) { + parcAssertNotNull(iface, "Parameter iface must be non-null"); + return iface->interfaceIndex; +} + +bool interfaceNameEquals(const Interface *iface, const char *name) { + parcAssertNotNull(iface, "Parameter iface must be non-null"); + + if (strcasecmp(iface->name, name) == 0) { + return true; + } + return false; +} + +bool interfaceEquals(const Interface *a, const Interface *b) { + if (a == NULL && b == NULL) { + return true; + } + + if (a == NULL || b == NULL) { + return false; + } + + if (a->interfaceIndex == b->interfaceIndex) { + if (a->loopback == b->loopback) { + if (a->supportMulticast == b->supportMulticast) { + if (a->mtu == b->mtu) { + if (strcasecmp(a->name, b->name) == 0) { + if (addressListEquals(a->addressList, b->addressList)) { + return true; + } + } + } + } + } + } + return false; +} + +// static const char light_Iface[] = "Interface"; +// static const char light_IfName[] = "Name"; +// static const char light_IFIDX[] = "Index"; +// static const char light_IsLoopback[] = "Loopback"; +// static const char light_Multicast[] = "Multicast"; +// static const char light_MTU[] = "MTU"; + +// static const char light_True[] = "true"; +// static const char light_False[] = "false"; +// static const char light_Addrs[] = "Addrs"; + +const char *interfaceGetName(const Interface *iface) { + parcAssertNotNull(iface, "Parameter iface must be non-null"); + return iface->name; +} + +unsigned interfaceGetMTU(const Interface *iface) { + parcAssertNotNull(iface, "Parameter iface must be non-null"); + return iface->mtu; +} diff --git a/hicn-light/src/hicn/utils/interface.h b/hicn-light/src/hicn/utils/interface.h new file mode 100644 index 000000000..fd91edb1d --- /dev/null +++ b/hicn-light/src/hicn/utils/interface.h @@ -0,0 +1,208 @@ +/* + * 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. + */ + +/** + * @brief <#Brief Description#> + * + * <#Detailed Description#> + * + */ +#ifndef interface_h +#define interface_h + +#include +#include + +struct interface; +typedef struct interface Interface; + +/** + * Creates a representation of an interface + * + * The name is copied. Creates a representation of a system interface. + * + * @param <#param1#> + * @return An allocated object, you must call interfaceDestroy() + * + * Example: + * @code + * <#example#> + * @endcode + */ +Interface *interfaceCreate(const char *name, unsigned interfaceIndex, + bool loopback, bool supportMulticast, unsigned mtu); + +void interfaceDestroy(Interface **interfacePtr); + +/** + * Adds an address to an interface + * + * Does not allow duplicates, if already exists is not added again + * + * @param <#param1#> + * @return <#return#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +void interfaceAddAddress(Interface *iface, Address *address); + +/** + * Retrieves a list of interface addresses + * + * <#Discussion#> + * + * @param <#param1#> + * @return Will not be NULL, but may be empty + * + * Example: + * @code + * <#example#> + * @endcode + */ +const AddressList *interfaceGetAddresses(const Interface *iface); + +/** + * The interface index + * + * <#Discussion#> + * + * @param <#param1#> + * @return <#return#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +unsigned interfaceGetInterfaceIndex(const Interface *iface); + +/** + * Returns the interface name, e.g. "eth0" + * + * <#Paragraphs Of Explanation#> + * + * @param [in] iface An allocated Interface + * + * @return non-null The interface Name as a C-string + * @return null An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +const char *interfaceGetName(const Interface *iface); + +/** + * Returns the Maximum Transmission Unit (MTU) of the interface + * + * <#Paragraphs Of Explanation#> + * + * @param [in] iface An allocated Interface + * + * @return number The MTU as reported by the kernel + * + * Example: + * @code + * { + * <#example#> + * } + * @endcode + */ +unsigned interfaceGetMTU(const Interface *iface); + +/** + * Determine if two InterfaceName instances are equal. + * + * + * The following equivalence relations on non-null `InterfaceName` instances are + * maintained: + * + * * It is reflexive: for any non-null reference value x, + * `InterfaceName_Equals(x, x)` must return true. + * + * * It is symmetric: for any non-null reference values x and y, + * `InterfaceName_Equals(x, y)` must return true if and only if + * `InterfaceName_Equals(y, x)` returns true. + * + * * It is transitive: for any non-null reference values x, y, and z, if + * `InterfaceName_Equals(x, y)` returns true and + * `InterfaceName_Equals(y, z)` returns true, + * then `InterfaceName_Equals(x, z)` must return true. + * + * * It is consistent: for any non-null reference values x and y, multiple + * invocations of `InterfaceName_Equals(x, y)` consistently return true or + * consistently return false. + * + * * For any non-null reference value x, `InterfaceName_Equals(x, NULL)` must + * return false. + * + * @param a A pointer to a `InterfaceName` instance. + * @param b A pointer to a `InterfaceName` instance. + * @return true if the two `InterfaceName` instances are equal. + * + * Example: + * @code + * { + * InterfaceName *a = InterfaceName_Create(); + * InterfaceName *b = InterfaceName_Create(); + * + * if (InterfaceName_Equals(a, b)) { + * // true + * } else { + * // false + * } + * } + * @endcode + */ +bool interfaceNameEquals(const Interface *iface, const char *name); + +/** + * Two Interfaces are idential + * + * All properties must be the same. The order of addresses matters, and + * they must have been added to the address list in the same order. + * + * The interface name match is case in-sensitive. + * + * @param <#param1#> + * @return <#return#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool interfaceEquals(const Interface *a, const Interface *b); + +/** + * <#OneLineDescription#> + * + * <#Discussion#> + * + * @param interface A Interface structure pointer. + * @return An allocate string representation of the Interface that must be freed + * via parcMemory_Deallocate(). + * + * Example: + * @code + * <#example#> + * @endcode + */ +char *interfaceToString(const Interface *interface); +#endif // interface_h diff --git a/hicn-light/src/hicn/utils/interfaceSet.c b/hicn-light/src/hicn/utils/interfaceSet.c new file mode 100644 index 000000000..35c97812b --- /dev/null +++ b/hicn-light/src/hicn/utils/interfaceSet.c @@ -0,0 +1,149 @@ +/* + * 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 +#include + +#include + +#include +#include + +#include + +struct interfaceSet { + PARCArrayList *listOfInterfaces; +}; + +static void _destroyInterface(void **ifaceVoidPtr) { + interfaceDestroy((Interface **)ifaceVoidPtr); +} + +InterfaceSet *interfaceSetCreate(void) { + InterfaceSet *set = parcMemory_AllocateAndClear(sizeof(InterfaceSet)); + parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL", + sizeof(InterfaceSet)); + set->listOfInterfaces = parcArrayList_Create(_destroyInterface); + return set; +} + +void interfaceSetDestroy(InterfaceSet **setPtr) { + parcAssertNotNull(setPtr, "Parameter must be non-null double pointer"); + parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer"); + + InterfaceSet *set = *setPtr; + parcArrayList_Destroy(&set->listOfInterfaces); + parcMemory_Deallocate((void **)&set); + *setPtr = NULL; +} + +bool interfaceSetAdd(InterfaceSet *set, Interface *iface) { + parcAssertNotNull(set, "Parameter set must be non-null"); + parcAssertNotNull(iface, "Parameter iface must be non-null"); + + unsigned ifaceIndex = interfaceGetInterfaceIndex(iface); + size_t length = parcArrayList_Size(set->listOfInterfaces); + for (size_t i = 0; i < length; i++) { + Interface *listEntry = + (Interface *)parcArrayList_Get(set->listOfInterfaces, i); + unsigned entryInterfaceIndex = interfaceGetInterfaceIndex(listEntry); + if (entryInterfaceIndex == ifaceIndex) { + return false; + } + } + + parcArrayList_Add(set->listOfInterfaces, (PARCObject *)iface); + return true; +} + +size_t interfaceSetLength(const InterfaceSet *set) { + parcAssertNotNull(set, "Parameter set must be non-null"); + return parcArrayList_Size(set->listOfInterfaces); +} + +Interface *interfaceSetGetByOrdinalIndex(InterfaceSet *set, + size_t ordinalIndex) { + parcAssertNotNull(set, "Parameter set must be non-null"); + return (Interface *)parcArrayList_Get(set->listOfInterfaces, ordinalIndex); +} + +Interface *interfaceSetGetByInterfaceIndex(const InterfaceSet *set, + unsigned interfaceIndex) { + size_t length = parcArrayList_Size(set->listOfInterfaces); + for (size_t i = 0; i < length; i++) { + Interface *listEntry = + (Interface *)parcArrayList_Get(set->listOfInterfaces, i); + unsigned entryInterfaceIndex = interfaceGetInterfaceIndex(listEntry); + if (entryInterfaceIndex == interfaceIndex) { + return listEntry; + } + } + return NULL; +} + +/** + * Uses the system name (e.g. "en0") + * + * <#Discussion#> + * + * @param <#param1#> + * @return NULL if not found + * + * Example: + * @code + * <#example#> + * @endcode + */ +Interface *interfaceSetGetByName(InterfaceSet *set, const char *name) { + size_t length = parcArrayList_Size(set->listOfInterfaces); + for (size_t i = 0; i < length; i++) { + Interface *listEntry = + (Interface *)parcArrayList_Get(set->listOfInterfaces, i); + if (interfaceNameEquals(listEntry, name)) { + return listEntry; + } + } + return NULL; +} + +bool interfaceSetEquals(const InterfaceSet *a, const InterfaceSet *b) { + if (a == NULL && b == NULL) { + return true; + } + + if (a == NULL || b == NULL) { + return false; + } + + size_t length_a = parcArrayList_Size(a->listOfInterfaces); + size_t length_b = parcArrayList_Size(b->listOfInterfaces); + + if (length_a == length_b) { + for (size_t i = 0; i < length_a; i++) { + Interface *iface_a = + (Interface *)parcArrayList_Get(a->listOfInterfaces, i); + + // the set is unique by interface id, so if it exists in set b, it + // exists there by interface id + Interface *iface_b = interfaceSetGetByInterfaceIndex( + b, interfaceGetInterfaceIndex(iface_a)); + if (!interfaceEquals(iface_b, iface_b)) { + return false; + } + } + return true; + } + return false; +} diff --git a/hicn-light/src/hicn/utils/interfaceSet.h b/hicn-light/src/hicn/utils/interfaceSet.h new file mode 100644 index 000000000..e43f985fe --- /dev/null +++ b/hicn-light/src/hicn/utils/interfaceSet.h @@ -0,0 +1,198 @@ +/* + * 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. + */ + +/** + * @brief <#Brief Description#> + * + * <#Detailed Description#> + * + */ +#ifndef InterfaceSet_h +#define InterfaceSet_h + +#include + +struct interfaceSet; +/** + * + * @see interfaceSetCreate + */ +typedef struct interfaceSet InterfaceSet; + +/** + * <#One Line Description#> + * + * <#Paragraphs Of Explanation#> + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + * + * @see <#references#> + */ +InterfaceSet *interfaceSetCreate(void); + +/** + * <#One Line Description#> + * + * <#Paragraphs Of Explanation#> + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + * + * @see <#references#> + */ +void interfaceSetDestroy(InterfaceSet **setPtr); + +/** + * Adds interface to set, does not allow duplicates + * + * Takes ownership of the iface memory if added + * + * Duplicates are two entries with the same interface index + * + * @param <#param1#> + * @return true if added, false if not (likely a duplicate) + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool interfaceSetAdd(InterfaceSet *set, Interface *iface); + +/** + * The number of interfaces in the set + * + * <#Discussion#> + * + * @param <#param1#> + * @return <#return#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +size_t interfaceSetLength(const InterfaceSet *set); + +/** + * Uses the ordinal index of the interface in the Set + * + * Ranges from 0 .. interfaceSetLength()-1. + * + * @param <#param1#> + * @return NULL if not found + * + * Example: + * @code + * <#example#> + * @endcode + */ +Interface *interfaceSetGetByOrdinalIndex(InterfaceSet *set, + size_t ordinalIndex); + +/** + * Retreives by the assigned interface index + * + * <#Discussion#> + * + * @param <#param1#> + * @return NULL if not found + * + * Example: + * @code + * <#example#> + * @endcode + */ +Interface *interfaceSetGetByInterfaceIndex(const InterfaceSet *set, + unsigned interfaceIndex); + +/** + * Uses the system name (e.g. "en0") + * + * <#Discussion#> + * + * @param <#param1#> + * @return NULL if not found + * + * Example: + * @code + * <#example#> + * @endcode + */ +Interface *interfaceSetGetByName(InterfaceSet *set, const char *name); + +/** + * Determine if two InterfaceSet instances are equal. + * + * Two InterfaceSet instances are equal if, and only if, the sets contain the + * same elements + * - order independent. + * Each element is compared via interfaceEquals() + * + * The following equivalence relations on non-null `InterfaceSet` instances are + * maintained: + * + * * It is reflexive: for any non-null reference value x, + * `InterfaceSet_Equals(x, x)` must return true. + * + * * It is symmetric: for any non-null reference values x and y, + * `InterfaceSet_Equals(x, y)` must return true if and only if + * `interfaceSetEquals(y, x)` returns true. + * + * * It is transitive: for any non-null reference values x, y, and z, if + * `interfaceSetEquals(x, y)` returns true and + * `interfaceSetEquals(y, z)` returns true, + * then `interfaceSetEquals(x, z)` must return true. + * + * * It is consistent: for any non-null reference values x and y, multiple + * invocations of `interfaceSetEquals(x, y)` consistently return true or + * consistently return false. + * + * * For any non-null reference value x, `interfaceSetEquals(x, NULL)` must + * return false. + * + * @param a A pointer to a `InterfaceSet` instance. + * @param b A pointer to a `InterfaceSet` instance. + * @return true if the two `InterfaceSet` instances are equal. + * + * Example: + * @code + * { + * InterfaceSet *a = interfaceSetCreate(); + * InterfaceSet *b = interfaceSetCreate(); + * + * if (interfaceSetEquals(a, b)) { + * // true + * } else { + * // false + * } + * } + * @endcode + */ +bool interfaceSetEquals(const InterfaceSet *a, const InterfaceSet *b); +#endif // InterfaceSet_h diff --git a/hicn-light/src/hicn/utils/punting.c b/hicn-light/src/hicn/utils/punting.c new file mode 100644 index 000000000..06466172c --- /dev/null +++ b/hicn-light/src/hicn/utils/punting.c @@ -0,0 +1,98 @@ +/* + * 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 +#include + +#include + +#include +#include + +struct punting { + char *symbolic; + Address *prefix; + uint32_t len; +}; + +Punting *puntingCreate(const char *listenerName, Address *prefix, + uint32_t len) { + parcAssertNotNull(listenerName, "Parameter listenerName must be non-null"); + parcAssertNotNull(prefix, "Parameter prefix must be non-null"); + + Punting *punting = parcMemory_AllocateAndClear(sizeof(Punting)); + if (punting) { + punting->symbolic = + parcMemory_StringDuplicate(listenerName, strlen(listenerName)); + punting->prefix = addressCopy(prefix); + punting->len = len; + } + + return punting; +} + +void puntingRelease(Punting **puntingPtr) { + parcAssertNotNull(puntingPtr, + "Parameter puntingPtr must be non-null double pointer"); + parcAssertNotNull(*puntingPtr, + "Parameter puntingPtr dereference to non-null pointer"); + + Punting *punting = *puntingPtr; + + if (punting->symbolic) { + parcMemory_Deallocate((void **)&punting->symbolic); + } + + if (punting->prefix) { + addressDestroy(&punting->prefix); + } + + parcMemory_Deallocate((void **)&punting); + *puntingPtr = NULL; +} + +bool puntingEquals(const Punting *a, const Punting *b) { + if ((a == NULL && b == NULL) || a == b) { + // both null or identically equal + return true; + } + + if (a == NULL || b == NULL) { + // only one is null + return false; + } + + if ((strcmp(a->symbolic, b->symbolic) == 0) && + (addressEquals(a->prefix, b->prefix)) && (a->len == b->len)) { + return true; + } + + return false; +} + +const char *puntingGetSymbolicName(const Punting *punting) { + parcAssertNotNull(punting, "Parameter listener must be non-null"); + return punting->symbolic; +} + +Address *puntingGetAddress(const Punting *punting) { + parcAssertNotNull(punting, "Parameter listener must be non-null"); + return punting->prefix; +} + +uint32_t puntingPrefixLen(const Punting *punting) { + parcAssertNotNull(punting, "Parameter listener must be non-null"); + return punting->len; +} diff --git a/hicn-light/src/hicn/utils/punting.h b/hicn-light/src/hicn/utils/punting.h new file mode 100644 index 000000000..9be1baed4 --- /dev/null +++ b/hicn-light/src/hicn/utils/punting.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef punting_h +#define punting_h + +struct punting; +typedef struct punting Punting; + +#include + +/** + * Creates a Punting object + * + * The symbolic name represents this listener and may be used by other commands. + * It must be unique, otherwise the command will fail when sent to the + * forwarder. + * + * @param [in] symbolic name of the listener + * @param [in] prefix address to add to the punting rule + * @param [in] len prefix length + * + * @return non-null An Allocated object + * @return null An error + * + */ +Punting *puntingCreate(const char *symbolic, Address *prefix, uint32_t len); + +/** + * Releases a reference count to the object + * + * <#Paragraphs Of Explanation#> + * + * @param [in,out] etherConnPtr A pointer to an etherConn object, will be + * null'd. + * + */ +void puntingRelease(Punting **puntingPtr); + +/** + * Determine if two light Punting are equal. + * + */ + +bool puntingEquals(const Punting *a, const Punting *b); + +/** + * Returns the symbolic name + * + */ +const char *puntingGetSymbolicName(const Punting *punting); + +/** + * Returns the address (INET or INET6 ip address) + * + */ +Address *puntingGetAddress(const Punting *punting); + +uint32_t puntingPrefixLen(const Punting *punting); +#endif // punting_h diff --git a/hicn-light/src/hicn/utils/utils.c b/hicn-light/src/hicn/utils/utils.c new file mode 100644 index 000000000..61ff9a904 --- /dev/null +++ b/hicn-light/src/hicn/utils/utils.c @@ -0,0 +1,236 @@ +// Utility function for commands + +#ifndef _WIN32 +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// This is the unique sequence number used by all messages and its thread locks +static pthread_mutex_t nextSequenceNumberMutex = PTHREAD_MUTEX_INITIALIZER; +static uint32_t nextSequenceNumber = 1; + +uint32_t utils_GetNextSequenceNumber(void) { + uint32_t seqnum; + + int result = pthread_mutex_lock(&nextSequenceNumberMutex); + parcAssertTrue(result == 0, "Got error from pthread_mutex_lock: %d", result); + + seqnum = nextSequenceNumber++; + + result = pthread_mutex_unlock(&nextSequenceNumberMutex); + parcAssertTrue(result == 0, "Got error from pthread_mutex_unlock: %d", + result); + + return seqnum; +} + +/** + * Return true if string is purely an integer + */ +bool utils_IsNumber(const char *string) { + size_t len = strlen(string); + for (size_t i = 0; i < len; i++) { + if (!isdigit(string[i])) { + return false; + } + } + return true; +} + +/** + * A symbolic name must be at least 1 character and must begin with an alpha. + * The remainder must be an alphanum. + */ +bool utils_ValidateSymbolicName(const char *symbolic) { + bool success = false; + size_t len = strlen(symbolic); + if (len > 0) { + if (isalpha(symbolic[0])) { + success = true; + for (size_t i = 1; i < len; i++) { + if (!isalnum(symbolic[i])) { + success = false; + break; + } + } + } + } + return success; +} + +struct iovec *utils_CreateAck(header_control_message *header, void *payload, + size_t payloadLen) { + struct iovec *response = + parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); + + header->messageType = ACK_LIGHT; + + response[0].iov_base = header; + response[0].iov_len = sizeof(header_control_message); + response[1].iov_base = payload; + response[1].iov_len = payloadLen; + + return response; +} + +struct iovec *utils_CreateNack(header_control_message *header, void *payload, + size_t payloadLen) { + struct iovec *response = + parcMemory_AllocateAndClear(sizeof(struct iovec) * 2); + + header->messageType = NACK_LIGHT; + + response[0].iov_base = header; + response[0].iov_len = sizeof(header_control_message); + response[1].iov_base = payload; + response[1].iov_len = payloadLen; + + return response; +} + +char *utils_BuildStringFromInet(in_addr_t *addr4, in_port_t *port) { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = *port; + addr.sin_addr.s_addr = *addr4; + + PARCBufferComposer *composer = parcBufferComposer_Create(); + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer( + parcNetwork_SockInet4Address_BuildString(&addr, composer)); + char *result = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + return result; +} + +char *utils_BuildStringFromInet6(struct in6_addr *addr6, in_port_t *port) { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = *port; + addr.sin6_addr = *addr6; + + PARCBufferComposer *composer = parcBufferComposer_Create(); + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer( + parcNetwork_SockInet6Address_BuildString(&addr, composer)); + char *result = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + return result; +} + +char *utils_CommandAddressToString(address_type addressType, + union commandAddr *address, + in_port_t *port) { + char *result; + + switch (addressType) { + case ADDR_INET: { + result = utils_BuildStringFromInet(&address->ipv4, port); + break; + } + + case ADDR_INET6: { + result = utils_BuildStringFromInet6(&address->ipv6, port); + break; + } + + default: { + char *addrStr = (char *)parcMemory_Allocate(sizeof(char) * 32); + sprintf(addrStr, "Error: UNKNOWN address type = %d", addressType); + result = addrStr; + break; + } + } + return result; +} + +struct iovec *utils_SendRequest(ControlState *state, command_id command, + void *payload, size_t payloadLen) { + bool success = false; + + // get sequence number for the header + uint32_t currentSeqNum = utils_GetNextSequenceNumber(); + + // Allocate and fill the header + header_control_message *headerControlMessage = + parcMemory_AllocateAndClear(sizeof(header_control_message)); + headerControlMessage->messageType = REQUEST_LIGHT; + headerControlMessage->commandID = command; + headerControlMessage->seqNum = currentSeqNum; + if (payloadLen > 0) { + headerControlMessage->length = 1; + } + + struct iovec msg[2]; + msg[0].iov_base = headerControlMessage; + msg[0].iov_len = sizeof(header_control_message); + msg[1].iov_base = payload; + msg[1].iov_len = payloadLen; + + struct iovec *response = controlState_WriteRead(state, msg); + + header_control_message *receivedHeader = + (header_control_message *)response[0].iov_base; + if (receivedHeader->seqNum != currentSeqNum) { + printf("Seq number is NOT correct: expected %d got %d \n", currentSeqNum, + receivedHeader->seqNum); + // failure + } else { + if (receivedHeader->messageType == RESPONSE_LIGHT) { + return response; // command needs both payload and header + } else { + if (receivedHeader->messageType == ACK_LIGHT) { + success = true; + } else if (receivedHeader->messageType == NACK_LIGHT) { + success = true; + } else { + printf("Error: unrecognized message type"); // failure + } + } + } + + // deallocate when payload & header of the response are not needed + if (receivedHeader->length > 0) { + parcMemory_Deallocate(&response[1].iov_base); // free received payload + } + parcMemory_Deallocate(&response[0].iov_base); // free receivedHeader + + // return response + if (success) { + return response; + } else { + parcMemory_Deallocate(&response); // free iovec pointer + return NULL; // will generate a failure + } +} + +const char *utils_PrefixLenToString(address_type addressType, + union commandAddr *address, + uint8_t *prefixLen) { + char len[4]; // max size + 1 + sprintf(len, "%u", (unsigned)*prefixLen); + in_port_t port = htons(1234); // this is a random port number that is ignored + + char *prefix = utils_CommandAddressToString(addressType, address, &port); + char *prefixStr = malloc(strlen(prefix) + strlen(len) + 2); + strcpy(prefixStr, prefix); + strcat(prefixStr, "/"); + strcat(prefixStr, len); + + free(prefix); + + return prefixStr; +} diff --git a/hicn-light/src/hicn/utils/utils.h b/hicn-light/src/hicn/utils/utils.h new file mode 100644 index 000000000..ce8cb4e17 --- /dev/null +++ b/hicn-light/src/hicn/utils/utils.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#ifndef utils_h +#define utils_h + +#include +#include +#include + +/** + * Return true if string is purely an integer + */ +bool utils_IsNumber(const char *string); + +/** + * A symbolic name must be at least 1 character and must begin with an alpha. + * The remainder must be an alphanum. + */ +bool utils_ValidateSymbolicName(const char *symbolic); + +/** + *Create an Ack message instance as a response of a control successfully + *completed. + */ +struct iovec *utils_CreateAck(header_control_message *header, void *payload, + size_t payloadLen); + +/** + *Create a Nack message instance as a response of a control unsuccessfully + *completed. + */ +struct iovec *utils_CreateNack(header_control_message *header, void *payload, + size_t payloadLen); + +/** + *Convert IPv4/IPv6 address from binary to text string. `uint8_t *ipAddress` has + *to be a `in_addr_t * or `a struct in6_addr *. + */ +char *utils_CommandAddressToString(address_type addressType, + union commandAddr *address, in_port_t *port); + +/** + *Given a command payload, it generates the header and send the request to the + *deamon. + */ +struct iovec *utils_SendRequest(ControlState *state, command_id command, + void *payload, size_t payloadLen); + +/** + *Convert a IPv4/IPv6 address plus Netmask len from binary to text string in the + *form [add]:[port]/[len]. + */ +const char *utils_PrefixLenToString(address_type addressType, + union commandAddr *address, + uint8_t *prefixLen); + +#endif \ No newline at end of file -- cgit 1.2.3-korg