diff options
Diffstat (limited to 'hicn-light/src/hicn/io')
29 files changed, 1579 insertions, 5425 deletions
diff --git a/hicn-light/src/hicn/io/CMakeLists.txt b/hicn-light/src/hicn/io/CMakeLists.txt index eb69485a5..d7e6977d6 100644 --- a/hicn-light/src/hicn/io/CMakeLists.txt +++ b/hicn-light/src/hicn/io/CMakeLists.txt @@ -14,40 +14,21 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR) list(APPEND HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/addressPair.h - ${CMAKE_CURRENT_SOURCE_DIR}/ioOperations.h - ${CMAKE_CURRENT_SOURCE_DIR}/listener.h - ${CMAKE_CURRENT_SOURCE_DIR}/listenerSet.h - ${CMAKE_CURRENT_SOURCE_DIR}/tcpListener.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicnListener.h - ${CMAKE_CURRENT_SOURCE_DIR}/udpTunnel.h - ${CMAKE_CURRENT_SOURCE_DIR}/tcpTunnel.h - ${CMAKE_CURRENT_SOURCE_DIR}/udpConnection.h - ${CMAKE_CURRENT_SOURCE_DIR}/udpListener.h - ${CMAKE_CURRENT_SOURCE_DIR}/streamConnection.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicnTunnel.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicnConnection.h ) list(APPEND SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/addressPair.c - ${CMAKE_CURRENT_SOURCE_DIR}/ioOperations.c - ${CMAKE_CURRENT_SOURCE_DIR}/listenerSet.c - ${CMAKE_CURRENT_SOURCE_DIR}/streamConnection.c - ${CMAKE_CURRENT_SOURCE_DIR}/tcpListener.c - ${CMAKE_CURRENT_SOURCE_DIR}/tcpTunnel.c - ${CMAKE_CURRENT_SOURCE_DIR}/udpConnection.c - ${CMAKE_CURRENT_SOURCE_DIR}/udpListener.c - ${CMAKE_CURRENT_SOURCE_DIR}/udpTunnel.c + ${CMAKE_CURRENT_SOURCE_DIR}/hicn.c + ${CMAKE_CURRENT_SOURCE_DIR}/tcp.c + ${CMAKE_CURRENT_SOURCE_DIR}/udp.c ) -if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - list(APPEND SOURCE_FILES - io/hicnTunnel.c - io/hicnConnection.c - io/hicnListener.c - ) -endif() +#if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") +# list(APPEND SOURCE_FILES +# io/hicnTunnel.c +# io/hicnConnection.c +# io/hicnListener.c +# ) +#endif() set(TO_INSTALL_HEADER_FILES ${TO_INSTALL_HEADER_FILES} @@ -56,4 +37,4 @@ set(TO_INSTALL_HEADER_FILES ) set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE) -set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file +set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE) diff --git a/hicn-light/src/hicn/io/addressPair.c b/hicn-light/src/hicn/io/addressPair.c deleted file mode 100644 index f9451f900..000000000 --- a/hicn-light/src/hicn/io/addressPair.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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 <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Object.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/io/addressPair.h> - -struct address_pair { - Address *local; - Address *remote; -}; - -static void _addressPair_Destroy(AddressPair **addressPairPtr) { - AddressPair *pair = *addressPairPtr; - - addressDestroy(&pair->local); - addressDestroy(&pair->remote); -} - -parcObject_ExtendPARCObject(AddressPair, _addressPair_Destroy, NULL, - addressPair_ToString, addressPair_Equals, NULL, - addressPair_HashCode, NULL); - -parcObject_ImplementAcquire(addressPair, AddressPair); - -parcObject_ImplementRelease(addressPair, AddressPair); - -AddressPair *addressPair_Create(const Address *local, const Address *remote) { - parcAssertNotNull(local, "Parameter local must be non-null"); - parcAssertNotNull(remote, "Parameter remote must be non-null"); - - AddressPair *pair = parcObject_CreateInstance(AddressPair); - parcAssertNotNull(pair, "Got null from parcObject_Create()"); - - pair->local = addressCopy(local); - pair->remote = addressCopy(remote); - - return pair; -} - -bool addressPair_Equals(const AddressPair *a, const AddressPair *b) { - if (a == b) { - return true; - } - if (a == NULL || b == NULL) { - return false; - } - - if (addressEquals(a->local, b->local)) { - if (addressEquals(a->remote, b->remote)) { - return true; - } - } - - return false; -} - -bool addressPair_EqualsAddresses(const AddressPair *a, const Address *local, - const Address *remote) { - if (a == NULL || local == NULL || remote == NULL) { - return false; - } - - if (addressEquals(a->local, local)) { - if (addressEquals(a->remote, remote)) { - return true; - } - } - - return false; -} - -char *addressPair_ToString(const AddressPair *pair) { - parcAssertNotNull(pair, "Parameter pair must be non-null"); - - char *local = addressToString(pair->local); - char *remote = addressToString(pair->remote); - - char *output; - int failure = asprintf(&output, "{ .local=%s, .remote=%s }", local, remote); - parcAssertTrue(failure > -1, "Error on asprintf"); - - parcMemory_Deallocate((void **)&local); - parcMemory_Deallocate((void **)&remote); - - return output; -} - -const Address *addressPair_GetLocal(const AddressPair *pair) { - parcAssertNotNull(pair, "Parameter pair must be non-null"); - return pair->local; -} - -const Address *addressPair_GetRemote(const AddressPair *pair) { - parcAssertNotNull(pair, "Parameter pair must be non-null"); - return pair->remote; -} - -/** - * @function addressPair_HashCode - * @abstract Hash useful for tables. Consistent with Equals. - * @discussion - * Returns a non-cryptographic hash that is consistent with equals. That is, - * if a == b, then hash(a) == hash(b). - * - */ -PARCHashCode addressPair_HashCode(const AddressPair *pair) { - PARCHashCode hashpair[2]; - hashpair[0] = addressHashCode(pair->local); - hashpair[1] = addressHashCode(pair->remote); - return parcHashCode_Hash((const uint8_t *)hashpair, sizeof(hashpair)); -} diff --git a/hicn-light/src/hicn/io/addressPair.h b/hicn-light/src/hicn/io/addressPair.h deleted file mode 100644 index f1b72e0dc..000000000 --- a/hicn-light/src/hicn/io/addressPair.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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. - */ - -/** - * Used to identify a connection between a specific local address and - * a specific remote address. - */ - -#ifndef address_Pair_h -#define address_Pair_h - -#include <hicn/utils/address.h> - -struct address_pair; -typedef struct address_pair AddressPair; - -/** - * @function addressPair_Create - * @abstract Creates and address pair. There is no restriction on the address - * types. - * @discussion - * Creates an ordered pair of addresses, where the first is considered the - * "local" address and the second is the "remote" address. Those designations - * are purely a convention used to name them, and does not imply any specifici - * types of operations. - * - * The two addresses may be of any address types (e.g. IPv4, IPv6, Local, - * Ethernet). However, some functions that use an AddressPair may require that - * the local and remote addresses be the same type. - * - */ -AddressPair *addressPair_Create(const Address *local, const Address *remote); - -/** - * Returns a reference counted copy of the address pair - * - * Increments the reference count and returns the same address pair - * - * @param [in] addressPair An allocated address pair - * - * @retval non-null A reference counted copy - * @retval null An error - */ -AddressPair *addressPair_Acquire(const AddressPair *addressPair); - -/** - * Releases a reference count to the object - * - * Decrements the reference count and destroys the object when it reaches 0. - */ -void addressPair_Release(AddressPair **pairPtr); - -/** - * Determine if two AddressPair instances are equal. - * - * Two AddressPair instances are equal if, and only if, the local and remote - * addresses are identical. Equality is determined by addressEquals(a->local, - * b->local) and Adress_Equals(a->remote, b->remote). - * - * The following equivalence relations on non-null `AddressPair` instances are - * maintained: - * - * * It is reflexive: for any non-null reference value x, - * `AddressPair_Equals(x, x)` must return true. - * - * * It is symmetric: for any non-null reference values x and y, - * `addressPair_Equals(x, y)` must return true if and only if - * `addressPair_Equals(y, x)` returns true. - * - * * It is transitive: for any non-null reference values x, y, and z, if - * `addressPair_Equals(x, y)` returns true and - * `addressPair_Equals(y, z)` returns true, - * then `addressPair_Equals(x, z)` must return true. - * - * * It is consistent: for any non-null reference values x and y, multiple - * invocations of `addressPair_Equals(x, y)` consistently return true or - * consistently return false. - * - * * For any non-null reference value x, `addressPair_Equals(x, NULL)` must - * return false. - * - * @param a A pointer to a `AddressPair` instance. - * @param b A pointer to a `AddressPair` instance. - * @return true if the two `AddressPair` instances are equal. - */ -bool addressPair_Equals(const AddressPair *a, const AddressPair *b); - -/** - * @function addressPair_EqualsAddresses - * @abstract As AddressEquals, but "b" is broken out - * @discussion - * Equality is determined by addressEquals(a->local, local) and - * Adress_Equals(a->remote, remote). - */ -bool addressPair_EqualsAddresses(const AddressPair *a, const Address *local, - const Address *remote); - -const Address *addressPair_GetLocal(const AddressPair *pair); - -const Address *addressPair_GetRemote(const AddressPair *pair); - -/** - * @function addressPair_HashCode - * @abstract Hash useful for tables. Consistent with Equals. - * @discussion - * Returns a non-cryptographic hash that is consistent with equals. That is, - * if a == b, then hash(a) == hash(b). - */ -PARCHashCode addressPair_HashCode(const AddressPair *pair); - -/** - * @function addressPair_ToString - * @abstract Human readable string representation. Caller must use free(3). - */ -char *addressPair_ToString(const AddressPair *pair); -#endif // address_Pair_h diff --git a/hicn-light/src/hicn/io/hicn.c b/hicn-light/src/hicn/io/hicn.c new file mode 100644 index 000000000..a239dc781 --- /dev/null +++ b/hicn-light/src/hicn/io/hicn.c @@ -0,0 +1,522 @@ +/* + * 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 hicn.c + * @brief Implementation of hicn face + */ + +#include <errno.h> +#include <fcntl.h> +#include <hicn/hicn-light/config.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <hicn/core/listener.h> +#include <hicn/core/listener_vft.h> +#include <hicn/core/connection.h> +#include <hicn/core/connection_vft.h> +#include <hicn/core/connection_table.h> +#include <hicn/core/forwarder.h> +#include <hicn/core/mapme.h> +#include <hicn/core/messagePacketType.h> +#include <hicn/socket/api.h> +#include <hicn/util/log.h> + +#define IPv6 6 +#define IPv4 4 +#define MTU_SIZE 1500 // bytes +#define MAX_HICN_RETRY 5 +#define DEFAULT_PORT 1234 + +// XXX #if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && defined(PUNTING) + +// XXX the socket helper should be moved here as we can have a single hicn +// listener + +#if 0 +static +const +address_pair_t * +_createRecvAddressPairFromPacket(const uint8_t *msgBuffer) { + address_t * packetSrcAddr = NULL; /* This one is in the packet */ + address_t * localAddr = NULL; /* This one is to be determined */ + + if (messageHandler_GetIPPacketType(msgBuffer) == IPv6_TYPE) { + struct sockaddr_in6 addr_in6; + addr_in6.sin6_family = AF_INET6; + addr_in6.sin6_port = htons(DEFAULT_PORT); + addr_in6.sin6_flowinfo = 0; + addr_in6.sin6_scope_id = 0; + memcpy(&addr_in6.sin6_addr, + (struct in6_addr *)messageHandler_GetSource(msgBuffer), 16); + packetSrcAddr = addressCreateFromInet6(&addr_in6); + + /* We now determine the local address used to reach the packet src address */ +#ifndef _WIN32 + int sock = socket (AF_INET6, SOCK_DGRAM, 0); +#else + int sock = (int)socket (AF_INET6, SOCK_DGRAM, 0); +#endif /* _WIN32 */ + if (sock < 0) + goto ERR; + + struct sockaddr_in6 remote, local; + memset(&remote, 0, sizeof(remote)); + remote.sin6_family = AF_INET6; + remote.sin6_addr = addr_in6.sin6_addr; + remote.sin6_port = htons(DEFAULT_PORT); + + socklen_t locallen = sizeof(local); + if (connect(sock, (const struct sockaddr*)&remote, sizeof(remote)) == -1) + goto ERR; + if (getsockname(sock, (struct sockaddr*) &local, &locallen) == -1) + goto ERR; + + local.sin6_port = htons(DEFAULT_PORT); + localAddr = addressCreateFromInet6(&local); + + close(sock); + + } else if (messageHandler_GetIPPacketType(msgBuffer) == IPv4_TYPE) { + struct sockaddr_in addr_in; + addr_in.sin_family = AF_INET; + addr_in.sin_port = htons(DEFAULT_PORT); + memcpy(&addr_in.sin_addr, + (struct in_addr *)messageHandler_GetSource(msgBuffer), 4); + packetSrcAddr = addressCreateFromInet(&addr_in); + + /* We now determine the local address used to reach the packet src address */ + +#ifndef _WIN32 + int sock = socket (AF_INET, SOCK_DGRAM, 0); +#else + int sock = (int)socket (AF_INET, SOCK_DGRAM, 0); +#endif /* _WIN32 */ + if (sock < 0) { + perror("Socket error"); + goto ERR; + } + + struct sockaddr_in remote, local; + memset(&remote, 0, sizeof(remote)); + remote.sin_family = AF_INET; + remote.sin_addr = addr_in.sin_addr; + remote.sin_port = htons(DEFAULT_PORT); + + socklen_t locallen = sizeof(local); + if (connect(sock, (const struct sockaddr*)&remote, sizeof(remote)) == -1) + goto ERR; + if (getsockname(sock, (struct sockaddr*) &local, &locallen) == -1) + goto ERR; + + local.sin_port = htons(DEFAULT_PORT); + localAddr = addressCreateFromInet(&local); + + close(sock); + } + /* As this is a receive pair, we swap src and dst */ + return addressPair_Create(localAddr, packetSrcAddr); + +ERR: + perror("Socket error"); + return NULL; +} + +static +bool _isEmptyAddressIPv6(address_t * address) { + struct sockaddr_in6 *addr6 = + parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6)); + parcAssertNotNull(addr6, "parcMemory_AllocateAndClear(%zu) returned NULL", + sizeof(addr6)); + + addressGetInet6(address, addr6); + + bool res = true; + for (int i = 0; i < 16; ++i) { + if (addr6->sin6_addr.s6_addr[i] != 0) { + res = false; + } + } + + parcMemory_Deallocate((void **)&addr6); + + return res; +} + +} + +static +const Connection * +_lookupConnection(ListenerOps * listener, const address_pair_t *pair) +{ + HicnListener * hicn = (HicnListener*)listener->context; + const connection_table_t * table = forwarder_GetConnectionTable(hicn->forwarder); + const address_t * packetSourceAddress = address_pair_local(pair); + + if (hicn->connection_id != -1) + return connection_table_get_by_id(table, hicn->connection_id); + + if (!packetSourceAddress) + return NULL; + + // in this first check we try to retrieve the standard connection + // generated by the hicn-light + const address_pair_t new_pair = { + .local = hicn->localAddress, + .remote = *packetSourceAddress, + }; + return *connection_table_lookup(table, &new_pair); +} + + +// XXX TODO : rely on libhicn +int +_createAddressFromPacket(const uint8_t *packet, address_t * address) +{ + if (messageHandler_GetIPPacketType(packet) == IPv6_TYPE) { + struct sockaddr_in6 * sin6 = address6(address); + *sin6 = (struct sockaddr_in6) { + .sin6_family = AF_INET6, + .sin6_port = htons(DEFAULT_PORT), + .sin6_flowinfo = 0, + .sin6_scope_id = 0, + }; + memcpy(&sin6->sin6_addr, + (struct in6_addr *)messageHandler_GetSource(packet), 16); + return 0; + } else if (messageHandler_GetIPPacketType(packet) == IPv4_TYPE) { + struct sockaddr_in * sin = address4(address); + *sin = (struct sockaddr_in) { + .sin_family = AF_INET, + .sin_port = htons(DEFAULT_PORT), + }; + memcpy(&sin->sin_addr, + (struct in_addr *)messageHandler_GetSource(packet), 4); + return 0; + } else { + return -1; + } +} + +#endif + +/****************************************************************************** + * Listener + ******************************************************************************/ + +typedef struct { + //address_t localAddress; // this is the local address or 0::0 in case of the + // main listener this is the address used inside + // forwarder to identify the listener. Notice that this + // address is the same as the fisical interfaces on + // which we create the TUN. it is NOT the TUN address + // which is given by libhicn after the bind operation + // However the user alway uses this address since is + // the only one available at configuration time + + // XXX why do we need the id of the associated connection ? + int connection_id; // this is used only if the listener is used to receive + // data packets we assume that 1 connection is associated + // to one listener in this case so we set the + // connection_id we the connection is create. if this id + // is not set and a data packet is received, the packet is + // dropped + + hicn_socket_t * hicn_socket; + hicn_socket_helper_t * hicn_socket_helper; + +} listener_hicn_data_t; + +static +void +listener_hicn_read_callback(listener_t * listener, int fd, void * data) +{ + assert(listener); + assert(!data); /* No user data */ + uint8_t packet[MTU_SIZE]; + + int family = address_family(&listener->address); + if ((family != AF_INET) && (family != AF_INET6)) { + /* + * We need to discard the frame. Read 1 byte. This will clear it off + * the stack. + */ + int nread = read(fd, packet, 1); + + if (nread > 0) { + DEBUG("Discarded frame from fd %d", fd); + } else if (nread < 0) { + ERROR("Error trying to discard frame from fd %d: (%d) %s", fd, errno, + strerror(errno)); + } + return; + } + +#if 0 + if (!(what & PARCEventType_Read)) + return; +#endif + + ssize_t n = read(fd, packet, MTU_SIZE); + if (n < 0) { + ERROR("read failed %d: (%d) %s", fd, errno, strerror(errno)); + return; + } + +#if 0 + address_t packet_addr; + if (_createAddressFromPacket(packet, &packet_addr) < 0) + return; + + address_pair_t pair_find = { + .local = packet_addr, + .remote = /* dummy */ hicn->localAddress, + }; + const Connection *conn = _lookupConnection(listener, &pair_find); + if (!conn) { + address_pair_t pair = { + .local = hicn->localAddress, + .remote = packet_addr, + }; + connid = _createNewConnection(listener, fd, &pair); + } else { + connid = connection_GetConnectionId(conn); + } +#endif + + listener_read_callback(listener->forwarder, listener, fd, &listener->address, packet, n); +} + +bool +listener_hicn_bind(listener_t * listener, const address_t * address) +{ + assert(listener); + assert(address); + + listener_hicn_data_t * data = listener->data; + assert(data); + + char *address_str = malloc(/* max */ INET6_ADDRSTRLEN); + inet_ntop(address_family(address), address, address_str, /* max */ INET6_ADDRSTRLEN); + int rc = hicn_bind(data->hicn_socket_helper, listener->fd, address_str); + if (rc < 0) { + ERROR("hicn_bind failed %d %s", rc, hicn_socket_strerror(rc)); + free(address_str); + return false; + } + + free(address_str); + return true; +} + +static +int +listener_hicn_initialize(listener_t * listener) +{ + assert(listener); + + listener_hicn_data_t * data = listener->data; + assert(data); + + /* This is the id of the connection associated to this listener (unique in + * the case of hICN */ + data->connection_id = -1; + + data->hicn_socket_helper = hicn_create(); + if (!data->hicn_socket) + goto ERR_HELPER; + + if (address_empty(&listener->address)) { + listener->fd = hicn_socket(data->hicn_socket_helper, listener->name, NULL); + } else { + char *local_addr = malloc(/* max */ INET6_ADDRSTRLEN); + inet_ntop(address_family(&listener->address), &listener->address, + local_addr, /* max */ INET6_ADDRSTRLEN); + listener->fd = hicn_socket(data->hicn_socket_helper, listener->name, local_addr); + free(local_addr); + } + + if (listener->fd < 0) { + ERROR("HicnListener %s: error creating hICN listener", listener->name); + goto ERR_FD; + } + + // Set non-blocking flag + int flags = fcntl(listener->fd, F_GETFL, NULL); + if (flags != -1) { + ERROR("fcntl failed to obtain file descriptor flags (%d)", errno); + goto ERR_FLAGS; + } + + if (fcntl(listener->fd, F_SETFL, flags | O_NONBLOCK) < 0) { + ERROR("fcntl failed to set file descriptor flags (%d)", errno); + goto ERR_FLAGS; + } + + return 0; + +ERR_FLAGS: + close(listener->fd); +ERR_FD: + hicn_free(data->hicn_socket_helper); +ERR_HELPER: + return -1; +} + +static +void +listener_hicn_finalize(listener_t * listener) +{ + assert(listener); + assert(listener_get_type(listener) == FACE_TYPE_HICN); + + listener_hicn_data_t * data = listener->data; + assert(data); + + // TODO destroy hicn_socket + // TODO free(data) (like in other classes) + + hicn_free(data->hicn_socket_helper); + // XXX + //hicn_socket_free(data->hicn_socket); + + return; +} + +static +int +listener_hicn_punt(const listener_t * listener, const char * prefix_s) +{ + assert(listener); + assert(listener_get_type(listener) == FACE_TYPE_HICN); + assert(prefix_s); + + listener_hicn_data_t * data = listener->data; + assert(data); + + int rc; + for (int retry = 0; retry < MAX_HICN_RETRY; retry++) { + if ((rc = hicn_listen(data->hicn_socket_helper, listener->fd, prefix_s)) >= 0) + return 0; + sleep(1); + } + ERROR("hicn_listen failed %d %s", rc, hicn_socket_strerror(rc)); + return -1; +} + +static +int +listener_hicn_get_socket(const listener_t * listener, const address_t * local, + const address_t * remote, const char * interface_name) +{ + assert(listener); + assert(listener_get_type(listener) == FACE_TYPE_HICN); + assert(pair); + + /* ... */ + + return -1; + +} + +DECLARE_LISTENER(hicn); + +/****************************************************************************** + * Connection + ******************************************************************************/ + +typedef struct { + /* ... */ +} connection_hicn_data_t; + +static +int +connection_hicn_initialize(connection_t * connection) +{ + + assert(connection); + assert(connection_get_type(connection) == FACE_TYPE_HICN); + + /* ... */ + + return 0; +} + +static +void +connection_hicn_finalize(connection_t * connection) +{ + /* ... */ + + return; +} + +static +int +connection_hicn_send(const connection_t * connection, msgbuf_t * msgbuf, + bool queue) +{ + assert(connection); + /* msgbuf can be NULL */ + +// connection_hicn_data_t * data = connection->data; +// assert(data); + + /* ... */ + + return true; +} + +//static +//int +//connection_hicn_sendv(const connection_t * connection, struct iovec * iov, +// size_t size) +//{ +// +// assert(connetion); +// assert(iov); +// +//// connection_hicn_data_t * data = connection->data; +//// assert(data); +// +// /* ... */ +// +// return 0; +//} +// +static +int +connection_hicn_send_packet(const connection_t * connection, const uint8_t * packet, size_t size) +{ + assert(ops); + assert(packet); + + /* ... */ + + return 0; +} + +static +void +connection_hicn_read_callback(connection_t * connection, int fd, void * data) +{ + ERROR("Unexpected read callback for hicn connection"); + return; +} + +DECLARE_CONNECTION(hicn); diff --git a/hicn-light/src/hicn/io/hicnConnection.c b/hicn-light/src/hicn/io/hicnConnection.c deleted file mode 100644 index 646cea990..000000000 --- a/hicn-light/src/hicn/io/hicnConnection.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * 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. - */ - -/** - * Embodies the reader/writer for a Hicn connection - * - * NB The Send() function may overflow the output buffer - * - */ - -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <string.h> -#include <sys/uio.h> -#include <unistd.h> - -#include <hicn/core/message.h> -#include <hicn/io/hicnConnection.h> - -#include <hicn/core/messageHandler.h> - -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/core/connection.h> -#include <hicn/core/forwarder.h> - -typedef struct hicn_state { - Forwarder *forwarder; - char * interfaceName; - Logger *logger; - - // the hicn listener socket we receive packets on - int hicnListenerSocket; - - AddressPair *addressPair; - - // We need to access this all the time, so grab it out - // of the addressPair; - struct sockaddr *peerAddress; - socklen_t peerAddressLength; - - struct sockaddr *localAddress; - socklen_t localAddressLength; - - bool isLocal; - bool isUp; - unsigned id; - - unsigned delay; - - /* This information would better be stored in the connection data structure - * but it is currently not reachable from within the implementation. */ - connection_state_t state; - connection_state_t admin_state; -#ifdef WITH_POLICY - uint32_t priority; -#endif /* WITH_POLICY */ -} _HicnState; - -// Prototypes -static bool _send(IoOperations *ops, const Address *nexthop, Message *message); -static bool _sendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size); -static const Address *_getRemoteAddress(const IoOperations *ops); -static const AddressPair *_getAddressPair(const IoOperations *ops); -static unsigned _getConnectionId(const IoOperations *ops); -static bool _isUp(const IoOperations *ops); -static bool _isLocal(const IoOperations *ops); -static void _destroy(IoOperations **opsPtr); -static list_connections_type _getConnectionType(const IoOperations *ops); -static void _sendProbe(IoOperations *ops, uint8_t *message); -static connection_state_t _getState(const IoOperations *ops); -static void _setState(IoOperations *ops, connection_state_t state); -static connection_state_t _getAdminState(const IoOperations *ops); -static void _setAdminState(IoOperations *ops, connection_state_t admin_state); -#ifdef WITH_POLICY -static uint32_t _getPriority(const IoOperations *ops); -static void _setPriority(IoOperations *ops, uint32_t priority); -#endif /* WITH_POLICY */ -static const char * _getInterfaceName(const IoOperations *ops); - -/* - * This assigns a unique pointer to the void * which we use - * as a GUID for this class. - */ -static const void *_ioOperationsGuid = __FILE__; - -/* - * Return our GUID - */ -static const void *_streamConnection_Class(const IoOperations *ops) { - return _ioOperationsGuid; -} - -static IoOperations _template = { - .closure = NULL, - .send = &_send, - .sendIOVBuffer = &_sendIOVBuffer, - .getRemoteAddress = &_getRemoteAddress, - .getAddressPair = &_getAddressPair, - .getConnectionId = &_getConnectionId, - .isUp = &_isUp, - .isLocal = &_isLocal, - .destroy = &_destroy, - .class = &_streamConnection_Class, - .getConnectionType = &_getConnectionType, - .sendProbe = &_sendProbe, - .getState = &_getState, - .setState = &_setState, - .getAdminState = &_getAdminState, - .setAdminState = &_setAdminState, -#ifdef WITH_POLICY - .getPriority = &_getPriority, - .setPriority = &_setPriority, -#endif /* WITH_POLICY */ - .getInterfaceName = &_getInterfaceName, -}; - -// ================================================================= - -static void _setConnectionState(_HicnState *Hicn, bool isUp); -static bool _saveSockaddr(_HicnState *hicnConnState, const AddressPair *pair); - -IoOperations *hicnConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd, - const AddressPair *pair, bool isLocal) { - IoOperations *io_ops = NULL; - - _HicnState *hicnConnState = parcMemory_AllocateAndClear(sizeof(_HicnState)); - parcAssertNotNull(hicnConnState, - "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_HicnState)); - - hicnConnState->forwarder = forwarder; - hicnConnState->interfaceName = strdup(interfaceName); - hicnConnState->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - - bool saved = _saveSockaddr(hicnConnState, pair); - if (saved) { - hicnConnState->hicnListenerSocket = fd; - hicnConnState->id = forwarder_GetNextConnectionId(forwarder); - hicnConnState->addressPair = addressPair_Acquire(pair); - hicnConnState->isLocal = isLocal; - - // allocate a connection - io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations)); - parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(IoOperations)); - memcpy(io_ops, &_template, sizeof(IoOperations)); - io_ops->closure = hicnConnState; - - _setConnectionState(hicnConnState, true); - -#ifdef WITH_POLICY - hicnConnState->priority = 0; -#endif /* WITH_POLICY */ - - if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - char *str = addressPair_ToString(hicnConnState->addressPair); - logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Info, - __func__, - "HicnConnection %p created for address %s (isLocal %d)", - (void *)hicnConnState, str, hicnConnState->isLocal); - free(str); - } - - messenger_Send( - forwarder_GetMessenger(forwarder), - missive_Create(MissiveType_ConnectionCreate, hicnConnState->id)); - messenger_Send(forwarder_GetMessenger(forwarder), - missive_Create(MissiveType_ConnectionUp, hicnConnState->id)); - } else { - // _saveSockaddr will already log an error, no need for extra log message - // here - logger_Release(&hicnConnState->logger); - free(hicnConnState->interfaceName); - parcMemory_Deallocate((void **)&hicnConnState); - } - - return io_ops; -} - -// ================================================================= -// I/O Operations implementation - -static void _destroy(IoOperations **opsPtr) { - parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer"); - parcAssertNotNull(*opsPtr, - "Parameter opsPtr must dereference to non-null pointer"); - - IoOperations *ops = *opsPtr; - parcAssertNotNull(ioOperations_GetClosure(ops), - "ops->context must not be null"); - - _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops); - addressPair_Release(&hicnConnState->addressPair); - parcMemory_Deallocate((void **)&(hicnConnState->peerAddress)); - parcMemory_Deallocate((void **)&(hicnConnState->localAddress)); - - messenger_Send( - forwarder_GetMessenger(hicnConnState->forwarder), - missive_Create(MissiveType_ConnectionDestroyed, hicnConnState->id)); - - if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Info, - __func__, "HicnConnection %p destroyed", (void *)hicnConnState); - } - - // do not close hicListenerSocket, the listener will close - // that when its done - // should I say something to libhicn? - - logger_Release(&hicnConnState->logger); - free(hicnConnState->interfaceName); - parcMemory_Deallocate((void **)&hicnConnState); - parcMemory_Deallocate((void **)&ops); - - *opsPtr = NULL; -} - -static bool _isUp(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->isUp; -} - -static bool _isLocal(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->isLocal; -} - -static const Address *_getRemoteAddress(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return addressPair_GetRemote(hicnConnState->addressPair); -} - -static const AddressPair *_getAddressPair(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->addressPair; -} - -static unsigned _getConnectionId(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->id; -} - -/** - * @function hicnConnection_Send - * @abstract Non-destructive send of the message. - * @discussion - * sends a message to the peer. - * - * @param dummy is ignored. . - */ -static bool _send(IoOperations *ops, const Address *dummy, Message *message) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops); - - // NAT for HICN - if (message_GetType(message) == MessagePacketType_ContentObject) { - // this is a data packet. We need to put the remote address in the - // destination field - - if (messageHandler_GetIPPacketType(message_FixedHeader(message)) == - IPv6_TYPE) { - messageHandler_SetDestination_IPv6( - (uint8_t *)message_FixedHeader(message), - &((struct sockaddr_in6 *)hicnConnState->peerAddress)->sin6_addr); - } else { - messageHandler_SetDestination_IPv4( - (uint8_t *)message_FixedHeader(message), - &(((struct sockaddr_in *)hicnConnState->peerAddress) - ->sin_addr.s_addr)); - } - } else if (message_GetType(message) == MessagePacketType_Interest) { - // this si an interest packet. We need to put the local address in the - // source field - if (messageHandler_GetIPPacketType(message_FixedHeader(message)) == - IPv6_TYPE) { - messageHandler_SetSource_IPv6( - (uint8_t *)message_FixedHeader(message), - &((struct sockaddr_in6 *)hicnConnState->localAddress)->sin6_addr); - } else { - messageHandler_SetSource_IPv4( - (uint8_t *)message_FixedHeader(message), - &(((struct sockaddr_in *)hicnConnState->localAddress) - ->sin_addr.s_addr)); - } - } else if (message_GetType(message) == MessagePacketType_WldrNotification) { - // here we don't need to do anything for now - } else { - // unkown packet - if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Debug, - __func__, "connid %u can't parse the message", - hicnConnState->id); - } - return false; - } - - ssize_t writeLength = - write(hicnConnState->hicnListenerSocket, message_FixedHeader(message), - message_Length(message)); - - if (writeLength < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - return false; - } else { - // this print is for debugging - printf("Incorrect write length %zd, expected %zd: (%d) %s\n", writeLength, - message_Length(message), errno, strerror(errno)); - return false; - } - } - - return true; -} - -static bool _sendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - - _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops); - - - ssize_t n = writev(hicnConnState->hicnListenerSocket, message, size); - if (n < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - size_t length = 0; - for (int i = 0; i < size; i++) - length += message[i].iov_len; - logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Error, - __func__, "Incorrect write length %zd, expected %zd: (%d) %s\n", - n, length, errno, strerror(errno)); - } - } - return false; - } - return true; -} - -static list_connections_type _getConnectionType(const IoOperations *ops) { - return CONN_HICN; -} - -static void _sendProbe(IoOperations *ops, uint8_t *message) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - - _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops); - - if(messageHandler_IsInterest(message)){// - // this is an interest packet. We need to put the local address in the - // source field - if (messageHandler_GetIPPacketType(message) == IPv6_TYPE) { - messageHandler_SetSource_IPv6(message, - &((struct sockaddr_in6 *)hicnConnState->localAddress)->sin6_addr); - } else { - messageHandler_SetSource_IPv4(message, - &(((struct sockaddr_in *)hicnConnState->localAddress) - ->sin_addr.s_addr)); - } - }//if is a data packet the packet is already set (see - //messageHandler_CreateProbeReply) - - ssize_t writeLength = write(hicnConnState->hicnListenerSocket, message, - messageHandler_GetTotalPacketLength(message)); - - if (writeLength < 0) { - return; - } -} - -// ================================================================= -// Internal API - -static bool _saveSockaddr(_HicnState *hicnConnState, const AddressPair *pair) { - bool success = false; - const Address *remoteAddress = addressPair_GetRemote(pair); - const Address *localAddress = addressPair_GetLocal(pair); - switch (addressGetType(remoteAddress)) { // local must be of the same type - - case ADDR_INET: { - size_t bytes = sizeof(struct sockaddr_in); - hicnConnState->peerAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(hicnConnState->peerAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet(remoteAddress, - (struct sockaddr_in *)hicnConnState->peerAddress); - hicnConnState->peerAddressLength = (socklen_t)bytes; - - hicnConnState->localAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(hicnConnState->localAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet(localAddress, - (struct sockaddr_in *)hicnConnState->localAddress); - hicnConnState->localAddressLength = (socklen_t)bytes; - success = true; - break; - } - - case ADDR_INET6: { - size_t bytes = sizeof(struct sockaddr_in6); - hicnConnState->peerAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(hicnConnState->peerAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet6(remoteAddress, - (struct sockaddr_in6 *)hicnConnState->peerAddress); - hicnConnState->peerAddressLength = (socklen_t)bytes; - - hicnConnState->localAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(hicnConnState->localAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet6(localAddress, - (struct sockaddr_in6 *)hicnConnState->localAddress); - hicnConnState->localAddressLength = (socklen_t)bytes; - success = true; - break; - } - - default: - if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - char *str = addressToString(remoteAddress); - logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Error, - __func__, "Remote address is not INET or INET6: %s", str); - parcMemory_Deallocate((void **)&str); - } - break; - } - return success; -} - -static void _setConnectionState(_HicnState *hicnConnState, bool isUp) { - parcAssertNotNull(hicnConnState, "Parameter HICN must be non-null"); - - Messenger *messenger = forwarder_GetMessenger(hicnConnState->forwarder); - - bool oldStateIsUp = hicnConnState->isUp; - hicnConnState->isUp = isUp; - - if (oldStateIsUp && !isUp) { - // bring connection DOWN - Missive *missive = - missive_Create(MissiveType_ConnectionDown, hicnConnState->id); - messenger_Send(messenger, missive); - return; - } - - if (!oldStateIsUp && isUp) { - // bring connection UP - Missive *missive = - missive_Create(MissiveType_ConnectionUp, hicnConnState->id); - messenger_Send(messenger, missive); - return; - } -} - -static connection_state_t _getState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->state; -} - -static void _setState(IoOperations *ops, connection_state_t state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _HicnState *hicnConnState = - (_HicnState *)ioOperations_GetClosure(ops); - hicnConnState->state = state; -} - -static connection_state_t _getAdminState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->admin_state; -} - -static void _setAdminState(IoOperations *ops, connection_state_t admin_state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _HicnState *hicnConnState = - (_HicnState *)ioOperations_GetClosure(ops); - hicnConnState->admin_state = admin_state; -} - -#ifdef WITH_POLICY -static uint32_t _getPriority(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _HicnState *hicnConnState = - (const _HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->priority; -} - -static void _setPriority(IoOperations *ops, uint32_t priority) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _HicnState *hicnConnState = - (_HicnState *)ioOperations_GetClosure(ops); - hicnConnState->priority = priority; -} -#endif /* WITH_POLICY -*/ -static const char * _getInterfaceName(const IoOperations *ops) -{ - parcAssertNotNull(ops, "Parameter must be non-null"); - _HicnState *hicnConnState = - (_HicnState *)ioOperations_GetClosure(ops); - return hicnConnState->interfaceName; -} diff --git a/hicn-light/src/hicn/io/hicnConnection.h b/hicn-light/src/hicn/io/hicnConnection.h deleted file mode 100644 index fec18e1bd..000000000 --- a/hicn-light/src/hicn/io/hicnConnection.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 hicnConnection.h - * @brief Represents a Hicn connection for the connection table - * - * <#Detailed Description#> - * - */ - -#ifndef hicnConnection_h -#define hicnConnection_h - -#include <hicn/core/forwarder.h> -#include <hicn/io/addressPair.h> -#include <hicn/io/ioOperations.h> -#include <hicn/utils/address.h> - -/** - * Creates a Hicn connection that can send to the remote address - * - * The address pair must both be same type (i.e. INET or INET6). - * - * @param [in] an allocated hicn-light Forwarder (saves reference) - * @param [in] fd The socket to use - * @param [in] pair An allocated address pair for the connection (saves - * reference) - * @param [in] isLocal determines if the remote address is on the current system - * - * @retval non-null An allocated Io operations - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -IoOperations *hicnConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd, - const AddressPair *pair, bool isLocal); -#endif // hicnConnection_h diff --git a/hicn-light/src/hicn/io/hicnListener.c b/hicn-light/src/hicn/io/hicnListener.c deleted file mode 100644 index bc49f4cee..000000000 --- a/hicn-light/src/hicn/io/hicnListener.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * 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 <errno.h> -#include <fcntl.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <unistd.h> - -#include <hicn/io/hicnConnection.h> -#include <hicn/io/hicnListener.h> - -#include <hicn/core/connection.h> -#include <hicn/core/connectionTable.h> -#include <hicn/core/forwarder.h> -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/core/mapme.h> -#include <hicn/core/messagePacketType.h> -#include <hicn/io/listener.h> -#include <hicn/socket/api.h> - -#define IPv6 6 -#define IPv4 4 -#define MTU_SIZE 1500 // bytes -#define MAX_HICN_RETRY 5 - -struct hicn_listener { - - char *listenerName; - - Forwarder *forwarder; - Logger *logger; - - PARCEvent *hicn_event; - int hicn_fd; // this is the file descriptor got from hicn library - - Address - *localAddress; // this is the local address or 0::0 in case of the - // main listener this is the address used inside - // forwarder to identify the listener. Notice that this - // address is the same as the fisical interfaces on - // which we create the TUN. it is NOT the TUN address - // which is given by libhicn after the bind operation - // However the user alway uses this address since is - // the only one available at configuration time - - unsigned inetFamily; - - int connection_id; // this is used only if the listener is used to receive - // data packets we assume that 1 connection is associated - // to one listener in this case so we set the - // connection_id we the connection is create. if this id - // is not set and a data packet is received, the packet is - // dropped - - unsigned conn_id; -}; - -static void _destroy(ListenerOps **listenerOpsPtr); -static const char *_getListenerName(const ListenerOps *ops); -static const char *_getInterfaceName(const ListenerOps *ops); -static unsigned _getInterfaceIndex(const ListenerOps *ops); -static const Address *_getListenAddress(const ListenerOps *ops); -static EncapType _getEncapType(const ListenerOps *ops); -static int _getSocket(const ListenerOps *ops); -static unsigned _createNewConnection(ListenerOps *listener, int fd, const AddressPair *pair); -static const Connection * _lookupConnection(ListenerOps * listener, const AddressPair *pair); -static Message *_readMessage(ListenerOps * listener, int fd, uint8_t *msgBuffer); -static void _hicnListener_readcb(int fd, PARCEventType what, void *listener_void); -static Address *_createAddressFromPacket(uint8_t *msgBuffer); -static void _handleWldrNotification(ListenerOps *listener, uint8_t *msgBuffer); -static void _readFrameToDiscard(HicnListener *hicn, int fd); - -static ListenerOps _hicnTemplate = { - .context = NULL, - .destroy = &_destroy, - .getInterfaceIndex = &_getInterfaceIndex, - .getListenAddress = &_getListenAddress, - .getEncapType = &_getEncapType, - .getSocket = &_getSocket, - .getInterfaceName = &_getInterfaceName, - .getListenerName = &_getListenerName, - .createConnection = &_createNewConnection, - .lookupConnection = &_lookupConnection, -}; - -static bool _isEmptyAddressIPv6(Address *address) { - struct sockaddr_in6 *addr6 = - parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6)); - parcAssertNotNull(addr6, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(addr6)); - - addressGetInet6(address, addr6); - - bool res = true; - for (int i = 0; i < 16; ++i) { - if (addr6->sin6_addr.s6_addr[i] != 0) { - res = false; - } - } - - parcMemory_Deallocate((void **)&addr6); - - return res; -} - -static Message *_readMessage(ListenerOps * listener, int fd, uint8_t *msgBuffer) { - HicnListener * hicn = (HicnListener*)listener->context; - Message *message = NULL; - - ssize_t readLength = read(fd, msgBuffer, MTU_SIZE); - - if (readLength < 0) { - printf("read failed %d: (%d) %s\n", fd, errno, strerror(errno)); - return message; - } - - size_t packetLength = messageHandler_GetTotalPacketLength(msgBuffer); - - if (readLength != packetLength) { - parcMemory_Deallocate((void **)&msgBuffer); - return message; - } - - if (messageHandler_IsTCP(msgBuffer)) { - MessagePacketType pktType; - unsigned connid = 0; - if (messageHandler_IsData(msgBuffer)) { - pktType = MessagePacketType_ContentObject; - if (hicn->connection_id == -1) { - parcMemory_Deallocate((void **)&msgBuffer); - return message; - } else { - connid = hicn->connection_id; - } - } else if (messageHandler_IsInterest(msgBuffer)) { - // notice that the connections for the interest (the one that we create at - // run time) uses as a local address 0::0, so the main tun - pktType = MessagePacketType_Interest; - Address *packetAddr = _createAddressFromPacket(msgBuffer); - - AddressPair *pair_find = addressPair_Create(packetAddr, /* dummy */ hicn->localAddress); - const Connection *conn = _lookupConnection(listener, pair_find); - addressPair_Release(&pair_find); - if (conn == NULL) { - AddressPair *pair = addressPair_Create(hicn->localAddress, packetAddr); - connid = _createNewConnection(listener, fd, pair); - addressPair_Release(&pair); - } else { - connid = connection_GetConnectionId(conn); - } - addressDestroy(&packetAddr); - } else { - printf("Got a packet that is not a data nor an interest, drop it!\n"); - parcMemory_Deallocate((void **)&msgBuffer); - return message; - } - - message = message_CreateFromByteArray(connid, msgBuffer, pktType, - forwarder_GetTicks(hicn->forwarder), - forwarder_GetLogger(hicn->forwarder)); - if (message == NULL) { - parcMemory_Deallocate((void **)&msgBuffer); - } - } else if (messageHandler_IsWldrNotification(msgBuffer)) { - _handleWldrNotification(listener, msgBuffer); - } else { - messageHandler_handleHooks(hicn->forwarder, msgBuffer, listener, fd, NULL); - parcMemory_Deallocate((void **)&msgBuffer); - } - - return message; -} - -static void _receivePacket(ListenerOps * listener, int fd) { - HicnListener * hicn = (HicnListener*)listener->context; - Message *msg = NULL; - uint8_t *msgBuffer = parcMemory_AllocateAndClear(MTU_SIZE); - msg = _readMessage(listener, fd, msgBuffer); - - if (msg) { - forwarder_Receive(hicn->forwarder, msg); - } -} - -static void _hicnListener_readcb(int fd, PARCEventType what, void *listener_void) { - ListenerOps * listener = (ListenerOps *)listener_void; - HicnListener *hicn = (HicnListener *)listener->context; - - if (hicn->inetFamily == IPv4 || hicn->inetFamily == IPv6) { - if (what & PARCEventType_Read) { - _receivePacket(listener, fd); - } - } else { - _readFrameToDiscard(hicn, fd); - } -} - -static bool _isEmptyAddressIPv4(Address *address) { - bool res = false; - - if (strcmp("inet4://0.0.0.0:1234", addressToString(address)) == 0) res = true; - return res; -} - -ListenerOps *hicnListener_CreateInet(Forwarder *forwarder, char *symbolic, - Address *address) { - HicnListener *hicn = parcMemory_AllocateAndClear(sizeof(HicnListener)); - parcAssertNotNull(hicn, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(HicnListener)); - - hicn->forwarder = forwarder; - hicn->listenerName = parcMemory_StringDuplicate(symbolic, strlen(symbolic)); - - hicn->conn_id = forwarder_GetNextConnectionId(forwarder); - hicn->inetFamily = IPv4; - - hicn->connection_id = -1; - - hicn_socket_helper_t *hicnSocketHelper = - forwarder_GetHicnSocketHelper(forwarder); - - if (_isEmptyAddressIPv4(address)) { - hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, NULL); - } else { - struct sockaddr_in *tmpAddr = - parcMemory_AllocateAndClear(sizeof(struct sockaddr_in)); - parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(tmpAddr)); - addressGetInet(address, tmpAddr); - char *local_addr = parcMemory_AllocateAndClear(INET_ADDRSTRLEN); - inet_ntop(AF_INET, &(tmpAddr->sin_addr), local_addr, INET_ADDRSTRLEN); - parcMemory_Deallocate((void **)&tmpAddr); - - hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, local_addr); - - parcMemory_Deallocate((void **)&local_addr); - } - - if (hicn->hicn_fd < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log( - hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "HicnListener %s: error while creating an hicn listener in lib_hicn", - symbolic); - } - logger_Release(&hicn->logger); - addressDestroy(&hicn->localAddress); - parcMemory_Deallocate((void **)&hicn->listenerName); - parcMemory_Deallocate((void **)&hicn); - return NULL; - } - - // Set non-blocking flag - int flags = fcntl(hicn->hicn_fd, F_GETFL, NULL); - parcAssertTrue(flags != -1, - "fcntl failed to obtain file descriptor flags (%d)", errno); - int failure = fcntl(hicn->hicn_fd, F_SETFL, flags | O_NONBLOCK); - parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)", - errno); - - ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - - memcpy(ops, &_hicnTemplate, sizeof(ListenerOps)); - ops->context = hicn; - - hicn->hicn_event = dispatcher_CreateNetworkEvent( - forwarder_GetDispatcher(forwarder), true, _hicnListener_readcb, - (void *)ops, hicn->hicn_fd); - dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder), - hicn->hicn_event); - - - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "HicnListener %s created", symbolic); - } - - return ops; - return NULL; -} - -ListenerOps *hicnListener_CreateInet6(Forwarder *forwarder, char *symbolic, - Address *address) { - HicnListener *hicn = parcMemory_AllocateAndClear(sizeof(HicnListener)); - parcAssertNotNull(hicn, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(HicnListener)); - - hicn->forwarder = forwarder; - hicn->listenerName = parcMemory_StringDuplicate(symbolic, strlen(symbolic)); - hicn->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - - hicn->conn_id = forwarder_GetNextConnectionId(forwarder); - hicn->localAddress = addressCopy(address); - - hicn->inetFamily = IPv6; - - hicn->connection_id = -1; - - // the call to libhicn is the same both for the main and the normal listeners - // in both cases we need to set only the identifier. In the case of normal - // listener (listener for data packet) we let the library select the right ip - // address we just need to set the right type of packet - - hicn_socket_helper_t *hicnSocketHelper = - forwarder_GetHicnSocketHelper(forwarder); - - if (_isEmptyAddressIPv6(address)) { - // create main listener - hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, NULL); - } else { - // create listener for the connetion - struct sockaddr_in6 *tmpAddr = - parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6)); - - parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(tmpAddr)); - addressGetInet6(address, tmpAddr); - - char *local_addr = parcMemory_AllocateAndClear(INET6_ADDRSTRLEN); - inet_ntop(AF_INET6, &(tmpAddr->sin6_addr), local_addr, INET6_ADDRSTRLEN); - - parcMemory_Deallocate((void **)&tmpAddr); - - hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, local_addr); - - parcMemory_Deallocate((void **)&local_addr); - } - - if (hicn->hicn_fd < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log( - hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "HicnListener %s: error while creating an hicn listener in lib_hicn", - symbolic); - } - logger_Release(&hicn->logger); - addressDestroy(&hicn->localAddress); - parcMemory_Deallocate((void **)&hicn->listenerName); - parcMemory_Deallocate((void **)&hicn); - return NULL; - } - - // Set non-blocking flag - int flags = fcntl(hicn->hicn_fd, F_GETFL, NULL); - parcAssertTrue(flags != -1, - "fcntl failed to obtain file descriptor flags (%d)", errno); - int failure = fcntl(hicn->hicn_fd, F_SETFL, flags | O_NONBLOCK); - parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)", - errno); - - ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - - memcpy(ops, &_hicnTemplate, sizeof(ListenerOps)); - ops->context = hicn; - - hicn->hicn_event = dispatcher_CreateNetworkEvent( - forwarder_GetDispatcher(forwarder), true, _hicnListener_readcb, - (void *)ops, hicn->hicn_fd); - dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder), - hicn->hicn_event); - - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "HicnListener %s created", symbolic); - } - - return ops; -} - -bool _hicnListener_BindInet6(ListenerOps *ops, const Address *remoteAddress) { - HicnListener *hicn = (HicnListener *)ops->context; - hicn_socket_helper_t *hicnSocketHelper = - forwarder_GetHicnSocketHelper(hicn->forwarder); - - struct sockaddr_in6 *tmpAddr = - parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6)); - parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(tmpAddr)); - addressGetInet6(remoteAddress, tmpAddr); - char *remote_addr = parcMemory_AllocateAndClear(INET6_ADDRSTRLEN); - inet_ntop(AF_INET6, &(tmpAddr->sin6_addr), remote_addr, INET6_ADDRSTRLEN); - parcMemory_Deallocate((void **)&tmpAddr); - - int res = hicn_bind(hicnSocketHelper, hicn->hicn_fd, remote_addr); - - bool result = false; - if (res < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "hicn_bind failed %d %s", res, hicn_socket_strerror(res)); - } - } else { - result = true; - } - - parcMemory_Deallocate((void **)&remote_addr); - - return result; -} - -bool _hicnListener_BindInet(ListenerOps *ops, const Address *remoteAddress) { - HicnListener *hicn = (HicnListener *)ops->context; - hicn_socket_helper_t *hicnSocketHelper = - forwarder_GetHicnSocketHelper(hicn->forwarder); - - struct sockaddr_in *tmpAddr = - parcMemory_AllocateAndClear(sizeof(struct sockaddr_in)); - parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(tmpAddr)); - addressGetInet(remoteAddress, tmpAddr); - char *remote_addr = parcMemory_AllocateAndClear(INET_ADDRSTRLEN); - inet_ntop(AF_INET, &(tmpAddr->sin_addr), remote_addr, INET_ADDRSTRLEN); - parcMemory_Deallocate((void **)&tmpAddr); - - int res = hicn_bind(hicnSocketHelper, hicn->hicn_fd, remote_addr); - bool result = false; - - if (res < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "hicn_bind failed %d %s", res, hicn_socket_strerror(res)); - } - } else { - result = true; - } - - parcMemory_Deallocate((void **)&remote_addr); - - return result; -} - -bool hicnListener_Bind(ListenerOps *ops, const Address *remoteAddress) { - if (addressGetType(remoteAddress) == ADDR_INET) { - return _hicnListener_BindInet(ops, remoteAddress); - } else if (addressGetType(remoteAddress) == ADDR_INET6) { - return _hicnListener_BindInet6(ops, remoteAddress); - } else { - printf("Bind failed: Invalid address\n"); - return false; - } -} - -bool hicnListener_Punting(ListenerOps *ops, const char *prefix) { - HicnListener *hicn = (HicnListener *)ops->context; - hicn_socket_helper_t *hicnSocketHelper = - forwarder_GetHicnSocketHelper(hicn->forwarder); - - int res = hicn_listen(hicnSocketHelper, hicn->hicn_fd, prefix); - int retry = 0; - - while (res < 0 && retry < MAX_HICN_RETRY) { - sleep(1); - res = hicn_listen(hicnSocketHelper, hicn->hicn_fd, prefix); - retry++; - } - - if (res < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "hicn_listen failed %d %s", res, hicn_socket_strerror(res)); - } - return false; - } - - return true; -} - -bool hicnListener_SetConnectionId(ListenerOps *ops, unsigned connId) { - HicnListener *hicn = (HicnListener *)ops->context; - if (hicn) { - hicn->connection_id = connId; - return true; - } - return false; -} - -static void _hicnListener_Destroy(HicnListener **listenerPtr) { - parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*listenerPtr, - "Parameter must derefernce to non-null pointer"); - - HicnListener *hicn = *listenerPtr; - - dispatcher_DestroyNetworkEvent(forwarder_GetDispatcher(hicn->forwarder), - &hicn->hicn_event); - logger_Release(&hicn->logger); - addressDestroy(&hicn->localAddress); - parcMemory_Deallocate((void **)&hicn); - *listenerPtr = NULL; -} - -static void _destroy(ListenerOps **listenerOpsPtr) { - ListenerOps *ops = *listenerOpsPtr; - HicnListener *hicn = (HicnListener *)ops->context; - _hicnListener_Destroy(&hicn); - parcMemory_Deallocate((void **)&ops); - *listenerOpsPtr = NULL; -} - -static const char *_getListenerName(const ListenerOps *ops) { - HicnListener *hicn = (HicnListener *)ops->context; - return hicn->listenerName; -} - -static const char *_getInterfaceName(const ListenerOps *ops) { - const char *interfaceName = ""; - return interfaceName; -} - -static unsigned _getInterfaceIndex(const ListenerOps *ops) { - HicnListener *hicn = (HicnListener *)ops->context; - return hicn->conn_id; -} - -static const Address *_getListenAddress(const ListenerOps *ops) { - HicnListener *hicn = (HicnListener *)ops->context; - return hicn->localAddress; -} - -static EncapType _getEncapType(const ListenerOps *ops) { return ENCAP_HICN; } - -static int _getSocket(const ListenerOps *ops) { - HicnListener *hicn = (HicnListener *)ops->context; - return hicn->hicn_fd; -} - -// =============================== - -static void _readFrameToDiscard(HicnListener *hicn, int fd) { - // we need to discard the frame. Read 1 byte. This will clear it off the - // stack. - uint8_t buffer; - int nread = read(fd, &buffer, 1); - - if (nread > 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "Discarded frame from fd %d", fd); - } - } else if (nread < 0) { - if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Error trying to discard frame from fd %d: (%d) %s", fd, errno, - strerror(errno)); - } - } -} - -static unsigned _createNewConnection(ListenerOps * listener, int fd, - const AddressPair *pair) { - HicnListener * hicn = (HicnListener *)listener->context; - bool isLocal = false; - - // udpConnection_Create takes ownership of the pair - IoOperations *ops = hicnConnection_Create(hicn->forwarder, listener->getInterfaceName(listener), fd, pair, isLocal); - Connection *conn = connection_Create(ops); - - connectionTable_Add(forwarder_GetConnectionTable(hicn->forwarder), conn); - unsigned connid = ioOperations_GetConnectionId(ops); - - return connid; -} - -static const Connection * _lookupConnection(ListenerOps * listener, - const AddressPair *pair) { - HicnListener * hicn = (HicnListener*)listener->context; - const Address * packetSourceAddress = addressPair_GetLocal(pair); - - const Connection *conn = NULL; - if (hicn->connection_id != -1) { - conn = connectionTable_FindById( - forwarder_GetConnectionTable(hicn->forwarder), hicn->connection_id); - } else { - if (packetSourceAddress != NULL) { - // in this first check we try to retrieve the standard connection - // generated by the hicn-light - AddressPair *pair = - addressPair_Create(hicn->localAddress, packetSourceAddress); - conn = connectionTable_FindByAddressPair( - forwarder_GetConnectionTable(hicn->forwarder), pair); - addressPair_Release(&pair); - } - } - - return conn; -} - -static Address *_createAddressFromPacket(uint8_t *msgBuffer) { - Address *packetAddr = NULL; - if (messageHandler_GetIPPacketType(msgBuffer) == IPv6_TYPE) { - struct sockaddr_in6 addr_in6; - addr_in6.sin6_family = AF_INET6; - addr_in6.sin6_port = htons(1234); - addr_in6.sin6_flowinfo = 0; - addr_in6.sin6_scope_id = 0; - memcpy(&addr_in6.sin6_addr, - (struct in6_addr *)messageHandler_GetSource(msgBuffer), 16); - packetAddr = addressCreateFromInet6(&addr_in6); - } else if (messageHandler_GetIPPacketType(msgBuffer) == IPv4_TYPE) { - struct sockaddr_in addr_in; - addr_in.sin_family = AF_INET; - addr_in.sin_port = htons(1234); - memcpy(&addr_in.sin_addr, - (struct in_addr *)messageHandler_GetSource(msgBuffer), 4); - packetAddr = addressCreateFromInet(&addr_in); - } - return packetAddr; -} - -static void _handleWldrNotification(ListenerOps *listener, uint8_t *msgBuffer) { - HicnListener * hicn = (HicnListener *)listener->context; - - Address *packetAddr = _createAddressFromPacket(msgBuffer); - - if (packetAddr == NULL) { - parcMemory_Deallocate((void **)&msgBuffer); - return; - } - - AddressPair * pair = addressPair_Create(packetAddr, /* dummy */ hicn->localAddress); - - const Connection *conn = _lookupConnection(listener, pair); - - addressPair_Release(&pair); - addressDestroy(&packetAddr); - - if (conn == NULL) { - parcMemory_Deallocate((void **)&msgBuffer); - return; - } - - Message *message = message_CreateFromByteArray( - connection_GetConnectionId(conn), msgBuffer, - MessagePacketType_WldrNotification, forwarder_GetTicks(hicn->forwarder), - forwarder_GetLogger(hicn->forwarder)); - - connection_HandleWldrNotification((Connection *)conn, message); - - message_Release(&message); -} diff --git a/hicn-light/src/hicn/io/hicnListener.h b/hicn-light/src/hicn/io/hicnListener.h deleted file mode 100644 index faf6ad6b8..000000000 --- a/hicn-light/src/hicn/io/hicnListener.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 hicnListener.h - * @brief Listens for in coming Hicn connections - * - * - */ - -#ifndef hicnListener_h -#define hicnListener_h - -#include <hicn/core/forwarder.h> -#include <hicn/core/messageHandler.h> -#include <hicn/io/listener.h> -#include <stdlib.h> - -struct hicn_listener; -typedef struct hicn_listener HicnListener; - -ListenerOps *hicnListener_CreateInet(Forwarder *forwarder, char *symbolic, - Address *address); -ListenerOps *hicnListener_CreateInet6(Forwarder *forwarder, char *symbolic, - Address *address); -bool hicnListener_Punting(ListenerOps *ops, const char *prefix); -bool hicnListener_Bind(ListenerOps *ops, const Address *remoteAddress); -bool hicnListener_SetConnectionId(ListenerOps *ops, unsigned connId); -// const Address *hicnListener_GetTunAddress(const ListenerOps *ops); -#endif // hicnListener_h diff --git a/hicn-light/src/hicn/io/hicnTunnel.c b/hicn-light/src/hicn/io/hicnTunnel.c deleted file mode 100644 index fd5acc680..000000000 --- a/hicn-light/src/hicn/io/hicnTunnel.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <parc/assert/parc_Assert.h> -#include <hicn/io/hicnConnection.h> -#include <hicn/io/hicnListener.h> -#include <hicn/io/hicnTunnel.h> - -IoOperations *hicnTunnel_CreateOnListener(Forwarder *forwarder, - ListenerOps *localListener, - const Address *remoteAddress) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - parcAssertNotNull(localListener, "Parameter localListener must be non-null"); - parcAssertNotNull(remoteAddress, "Parameter remoteAddress must be non-null"); - - Logger *logger = forwarder_GetLogger(forwarder); - - IoOperations *ops = NULL; - if (localListener->getEncapType(localListener) == ENCAP_HICN) { - const Address *localAddress = - localListener->getListenAddress(localListener); - address_type localType = addressGetType(localAddress); - address_type remoteType = addressGetType(remoteAddress); - - if (localType == remoteType) { - bool res = hicnListener_Bind(localListener, remoteAddress); - if (res == false) { - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Unable to bind local listener to remote node"); - } - return ops; - } - - // localAddress = hicnListener_GetTunAddress(localListener); //This is the - // true local address - - AddressPair *pair = addressPair_Create(localAddress, remoteAddress); - bool isLocal = false; - int fd = localListener->getSocket(localListener); - ops = hicnConnection_Create(forwarder, localListener->getInterfaceName(localListener), fd, pair, isLocal); - - addressPair_Release(&pair); - } else { - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Local listener of type %s and remote type %s, cannot " - "establish tunnel", - addressTypeToString(localType), - addressTypeToString(remoteType)); - } - } - } else { - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Local listener %p is not type UDP, cannot establish tunnel", - (void *)localListener); - } - } - - return ops; -} - -IoOperations *hicnTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress) { - ListenerSet *set = forwarder_GetListenerSet(forwarder); - ListenerOps *listener = listenerSet_Find(set, ENCAP_HICN, localAddress); - IoOperations *ops = NULL; - if (listener) { - ops = hicnTunnel_CreateOnListener(forwarder, listener, remoteAddress); - } else { - if (logger_IsLoggable(forwarder_GetLogger(forwarder), LoggerFacility_IO, - PARCLogLevel_Error)) { - char *str = addressToString(localAddress); - logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_IO, - PARCLogLevel_Error, __func__, - "Could not find listener to match address %s", str); - parcMemory_Deallocate((void **)&str); - } - } - - if (ops) { - hicnListener_SetConnectionId(listener, ops->getConnectionId(ops)); - } - - return ops; -} diff --git a/hicn-light/src/hicn/io/hicnTunnel.h b/hicn-light/src/hicn/io/hicnTunnel.h deleted file mode 100644 index 1fe0b413c..000000000 --- a/hicn-light/src/hicn/io/hicnTunnel.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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 hicnTunnel.h - * @brief Establish a tunnel to a remote system - * - * Creates a "hicn tunnel" to a remote system. There must already be a local - * HICN listener for the local side of the connection. - * - */ - -#ifndef hicnTunnel_h -#define hicnTunnel_h - -#include <hicn/core/forwarder.h> -#include <hicn/io/ioOperations.h> -#include <hicn/io/listener.h> -#include <hicn/utils/address.h> - -/** - * Establishes a connection to a remote system over HICN - * - * The remoteAddress must be of the same type (i.e. v4 or v6) as the - * localAddress. There must be an existing HICN listener on the local address. - * If either of these are not true, will return NULL. - * - * The connection will go in the table immediately, and will be in the "up" - * state. - * - * @param [in] an allocated hicn-light Forwarder - * @param [in] localAddress The local IP address and port to use for the - * connection - * @param [in] remote Address the remote IP address for the connection, must - * include a destination port. - * - * @retval non-null An allocated Io Operations structure for the connection - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -IoOperations *hicnTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress); - -IoOperations *hicnTunnel_CreateOnListener(Forwarder *forwarder, - ListenerOps *localListener, - const Address *remoteAddress); - -#endif // hicnTunnel_h diff --git a/hicn-light/src/hicn/io/ioOperations.c b/hicn-light/src/hicn/io/ioOperations.c deleted file mode 100644 index 0087b320a..000000000 --- a/hicn-light/src/hicn/io/ioOperations.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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 <parc/assert/parc_Assert.h> -#include <hicn/hicn-light/config.h> -#include <hicn/io/ioOperations.h> -#include <stdio.h> - -void *ioOperations_GetClosure(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - return ops->closure; -} - -bool ioOperations_Send(IoOperations *ops, const Address *nexthop, - Message *message) { - return ops->send(ops, nexthop, message); -} - -bool ioOperations_SendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size) { - return ops->sendIOVBuffer(ops, message, size); -} - -const Address *ioOperations_GetRemoteAddress(const IoOperations *ops) { - return ops->getRemoteAddress(ops); -} - -const AddressPair *ioOperations_GetAddressPair(const IoOperations *ops) { - return ops->getAddressPair(ops); -} - - - -bool ioOperations_IsUp(const IoOperations *ops) { return ops->isUp(ops); } - -bool ioOperations_IsLocal(const IoOperations *ops) { return ops->isLocal(ops); } - -unsigned ioOperations_GetConnectionId(const IoOperations *ops) { - return ops->getConnectionId(ops); -} - -void ioOperations_Release(IoOperations **opsPtr) { - IoOperations *ops = *opsPtr; - ops->destroy(opsPtr); -} - -const void *ioOperations_Class(const IoOperations *ops) { - return ops->class(ops); -} - -list_connections_type ioOperations_GetConnectionType(const IoOperations *ops) { - return ops->getConnectionType(ops); -} - -void ioOperations_SendProbe(IoOperations *ops, uint8_t *message) { - ops->sendProbe(ops, message); -} - - -connection_state_t ioOperations_GetState(const IoOperations *ops) { - return ops->getState(ops); -} - -void ioOperations_SetState(IoOperations *ops, connection_state_t state) { - ops->setState(ops, state); -} - -connection_state_t ioOperations_GetAdminState(const IoOperations *ops) { - return ops->getAdminState(ops); -} - -void ioOperations_SetAdminState(IoOperations *ops, connection_state_t admin_state) { - ops->setAdminState(ops, admin_state); -} - -#ifdef WITH_POLICY -uint32_t ioOperations_GetPriority(const IoOperations *ops) { - return ops->getPriority(ops); -} - -void ioOperations_SetPriority(IoOperations *ops, uint32_t priority) { - ops->setPriority(ops, priority); -} -#endif /* WITH_POLICY */ - -const char * ioOperations_GetInterfaceName(const IoOperations *ops) { - return ops->getInterfaceName(ops); -} diff --git a/hicn-light/src/hicn/io/ioOperations.h b/hicn-light/src/hicn/io/ioOperations.h deleted file mode 100644 index 5d9befac3..000000000 --- a/hicn-light/src/hicn/io/ioOperations.h +++ /dev/null @@ -1,449 +0,0 @@ -/* - * 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. - */ - -/** - * Defines the interface all connections use to communicate with the forwarder. - */ - -/** - * I/O is built around a callback structure. The connection table contains an - * operations structure built around function pointers. These allow the - * connection table to be agnostic about underlying connections. - */ - -#ifndef io_h -#define io_h - -#include <hicn/core/connectionState.h> -#include <hicn/core/message.h> -#include <hicn/core/ticks.h> -#include <hicn/io/addressPair.h> -#include <hicn/utils/address.h> - -// packet types for probing -#define PACKET_TYPE_PROBE_REQUEST 5 -#define PACKET_TYPE_PROBE_REPLY 6 - -struct io_ops; -typedef struct io_ops IoOperations; - -/** - * @typedef IoOperations - * @abstract The IO Operations structure abstracts an connection's properties - * and send() method - * @constant context Implementation specific opaque data, passed back on each - * call - * @constant send function pointer to send a message, does not destroy the - * message - * @constant getRemoteAddress function pointer to return the "to" address - * associated with the connection. Some connections might not have a specific - * peer, such as multicast, where its the group address. - * @constant isUp test if the connection is up, ready to send a message. - * @constant isLocal test if the connection is local to the host. - * @constant getConnectionId returns the hicn-light id for the connection. - * @constant destroy releases a refernce count on the connection and possibly - * destroys the connection. - * @constant class A unique identifier for each class that instantiates - * IoOperations. - * @constant getConnectionType Returns the type of connection (TCP, UDP, L2, - * etc.) of the underlying connection. - * @constant getState Returns the current state of the connection (redundant - * with isUp for added for completeness of the API). - * @constant setState Allows to mark the current state of a connection. - * @constant getAdminState Returns the administrative state of a connection (as - * requested by the user, which might occasionally differ from the current - * state). - * @constant setAdminState Allows to set the administrative state of a - * connection. - * @constant getInterfaceName Returns the interface name associated to a - * connection. - * @discussion <#Discussion#> - */ -struct io_ops { - void *closure; - bool (*send)(IoOperations *ops, const Address *nexthop, Message *message); - bool (*sendIOVBuffer)(IoOperations *ops, struct iovec *message, size_t - size); - const Address *(*getRemoteAddress)(const IoOperations *ops); - const AddressPair *(*getAddressPair)(const IoOperations *ops); - bool (*isUp)(const IoOperations *ops); - bool (*isLocal)(const IoOperations *ops); - unsigned (*getConnectionId)(const IoOperations *ops); - void (*destroy)(IoOperations **opsPtr); - const void *(*class)(const IoOperations *ops); - list_connections_type (*getConnectionType)(const IoOperations *ops); - void (*sendProbe)(IoOperations *ops, uint8_t *message); - connection_state_t (*getState)(const IoOperations *ops); - void (*setState)(IoOperations *ops, connection_state_t state); - connection_state_t (*getAdminState)(const IoOperations *ops); - void (*setAdminState)(IoOperations *ops, connection_state_t admin_state); -#ifdef WITH_POLICY - uint32_t (*getPriority)(const IoOperations *ops); - void (*setPriority)(IoOperations *ops, uint32_t priority); -#endif /* WITH_POLICY */ - const char * (*getInterfaceName)(const IoOperations *ops); -}; - -/** - * Returns the closure of the interface - * - * The creator of the closure sets this parameter to store its state. - * - * @param [in] ops A concrete instance of the interface - * - * @return The value set by the concrete instance of the interface. - * - * Example: - * @clode - * { - - * } - * @endcode - */ -void *ioOperations_GetClosure(const IoOperations *ops); - -/** - * Release all memory related to the interface and implementation - * - * This function must release all referenced memory in the concrete - * implementation and memory related to the IoOperations. It should NULL the - * input parameter. - * - * @param [in,out] opsPtr Pointer to interface. Will be NULLed. - * - * Example: - * @code - * - * static void - * _etherConnection_InternalRelease(_EtherState *etherConnState) - * { - * // release internal state of _EtherState - * } - * - * static void - * _etherConnection_Release(IoOperations **opsPtr) - * { - * IoOperations *ops = *opsPtr; - * - * _EtherState *etherConnState = (_EtherState *) - * ioOperations_GetClosure(ops); - * _etherConnection_InternalRelease(etherConnState); - * - * parcMemory_Deallocate((void **) &ops); - * } - * - * IoOperations * - * etherConnection_Create(Forwarder *forwarder, GenericEther *ether, - * AddressPair *pair) - * { - * size_t allocationSize = sizeof(_EtherState) + sizeof(IoOperations); - * IoOperations *ops = parcMemory_AllocateAndClear(allocationSize); - * if (ops) { - * // fill in other interface functions - * ops->destroy = &_etherConnection_Release; - * ops->closure = (uint8_t *) ops + sizeof(IoOperations); - * - * _EtherState *etherConnState = ioOperations_GetClosure(ops); - * // fill in Ethernet state - * } - * return ops; - * } - * @endcode - */ -void ioOperations_Release(IoOperations **opsPtr); - -/** - * Sends the specified Message out this connection - * - * The the implementation of send may queue the message, it must acquire a - * reference to it. - * - * @param [in] ops The connection implementation. - * @param [in] nexthop On multiple access networks, this parameter might be - * used, usually NULL. - * @param [in] message The message to send. If the message will be queued, it - * will be acquired. - * - * @return true The message was sent or queued - * @retrun false An error occured and the message will not be sent or queued - * - * Example: - * @code - * { - * if (ioOperations_IsUp(conn->ops)) { - * return ioOperations_Send(conn->ops, NULL, message); - * } - * } - * @endcode - */ -bool ioOperations_Send(IoOperations *ops, const Address *nexthop, - Message *message); - -bool ioOperations_SendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size); - -/** - * A connection is made up of a local and a remote address. This function - * returns the remote address. - * - * Represents the destination endpoint of the communication. - * - * @param [in] ops The connection implementation. - * - * @return non-null The remote address - * @return null The connection does not have a remote address - * - * Example: - * @code - * { - * Address *local = addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03, - * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t []) - * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair = - * addressPair_Create(local, remote); IoOperations *ops = - * etherConnection_Create(forwarder, ether, pair); - * - * const Address *test = ioOperations_GetRemoteAddress(ops); - * parcAssertTrue(addressEquals(test, remote), "Wrong remote address"); - * ioOperations_Release(&ops); - * addressPair_Release(&pair); - * addressDestroy(&local); - * addressDestroy(&remote); - * } - * @endcode - */ -const Address *ioOperations_GetRemoteAddress(const IoOperations *ops); - -/** - * A connection is made up of a local and a remote address. This function - * returns the address pair. - * - * Represents the destination endpoint of the communication. - * - * @param [in] ops The connection implementation. - * - * @return non-null The address pair - * @return null An error. - * - * Example: - * @code - * { - * Address *local = addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03, - * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t []) - * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair = - * addressPair_Create(local, remote); IoOperations *ops = - * etherConnection_Create(forwarder, ether, pair); - * - * const AddressPair *test = ioOperations_GetAddressPair(ops); - * parcAssertTrue(addressPair(test, pair), "Wrong address pair"); - * ioOperations_Release(&ops); - * addressPair_Release(&pair); - * addressDestroy(&local); - * addressDestroy(&remote); - * } - * @endcode - */ -const AddressPair *ioOperations_GetAddressPair(const IoOperations *ops); - -/** - * Returns true if the underlying connection is in operation - * - * An UP connection is able to send and receive packets. If a subsystem needs to - * take actions when a connection goes UP or DOWN, it should subscribe as a - * Missive listener. - * - * @param [in] ops The connection implementation. - * - * @return true The connection is UP - * @return false The connection is not UP - * - * Example: - * @code - * { - * if (ioOperations_IsUp(conn->ops)) { - * return ioOperations_Send(conn->ops, NULL, message); - * } - * } - * @endcode - */ -bool ioOperations_IsUp(const IoOperations *ops); - -/** - * If the remote address is local to this system, returns true - * - * Will return true if an INET or INET6 connection is on localhost. Will return - * true for AF_UNIX. An Ethernet connection is not local. - * - * @param [in] ops The connection implementation. - * - * @return true The remote address is local to the system - * @return false The remote address is not local - * - * Example: - * @code - * { - * // Is the ingress connection remote? If so check for non-zero and - * decrement if (!ioOperations(ingressConnectionOps) { uint8_t hoplimit = - * message_GetHopLimit(interestMessage); if (hoplimit == 0) { - * // error - * } else { - * hoplimit--; - * } - * // take actions on hoplimit - * } - * } - * @endcode - */ -bool ioOperations_IsLocal(const IoOperations *ops); - -/** - * Returns the connection ID represented by this IoOperations in the - * ConnectionTable. - * - * <#Paragraphs Of Explanation#> - * - * @param [in] ops The connection implementation. - * - * @return number The connection ID in the connection table. - * - * Example: - * @code - * { - * unsigned id = ioOperations_GetConnectionId(ingressIoOps); - * const Connection *conn = - * connectionTable_FindById(forwarder->connectionTable, id); - * } - * @endcode - */ -unsigned ioOperations_GetConnectionId(const IoOperations *ops); - -/** - * A pointer that represents the class of the connection - * - * Each concrete implementation has a class pointer that is unique to the - * implementation (not instance). Each implementation is free to choose how to - * determine the value, so long as it is unique on the system. This is a - * system-local value. - * - * @param [in] ops The connection implementation. - * - * @return non-null A pointer value unique to the implementation (not instance). - * - * Example: - * @code - * bool - * etherConnection_IsInstanceOf(const Connection *conn) - * { - * bool result = false; - * if (conn != NULL) { - * IoOperations *ops = connection_GetIoOperations(conn); - * const void *class = ioOperations_Class(ops); - * result = (class == _etherConnection_Class(ops)); - * } - * return result; - * } - * @endcode - */ -const void *ioOperations_Class(const IoOperations *ops); - -/** - * Returns the transport type of the connection (TCP, UDP, L2, etc.). - * - * TCP and AF_UNIX are both stream connections and will both return - * "Connection_TCP". Ethernet will return "Connection_L2". - * - * @param [in] ops The connection implementation. - * - * @return Connection_TCP A TCP4, TCP6, or AF_UNIX connection - * @return Connection_UDP A UDP4 or UDP6 connection - * @return Connection_L2 An Ethernet connection - * - * Example: - * @code - * { - * ConnectionType type = - * ioOperations_GetConnectionType(connection_GetIoOperations(connection)); - * Connection *Conn = - * Connection_Create(connection_GetConnectionId(connection), localAddress, - * remoteAddress, type); - * } - * @endcode - */ -list_connections_type ioOperations_GetConnectionType(const IoOperations *ops); - -void ioOperations_SendProbe(IoOperations *ops, uint8_t *message); - - -/** - * Returns the current state of the connection - * - * @param [in] ops The connection implementation. - * - * @return Connection state (connection_state_t). - */ -connection_state_t ioOperations_GetState(const IoOperations *ops); - -/** - * Sets the current state of the connection - * - * @param [in] ops The connection implementation. - * @param [in] state New state to set (connection_state_t). - */ -void ioOperations_SetState(IoOperations *ops, connection_state_t state); - -/** - * Returns the administrative state of the connection - * - * @param [in] ops The connection implementation. - * - * @return Connection state (connection_state_t). - */ -connection_state_t ioOperations_GetAdminState(const IoOperations *ops); - -/** - * Sets the administrative state of the connection - * - * @param [in] ops The connection implementation. - * @param [in] state New state to set (connection_state_t). - */ -void ioOperations_SetAdminState(IoOperations *ops, connection_state_t admin_state); - -#ifdef WITH_POLICY -/** - * Returns the priority of the connection - * - * @param [in] ops The connection implementation. - * - * @return Connection state (uint32_t). - */ -uint32_t ioOperations_GetPriority(const IoOperations *ops); - -/** - * Sets the priority of the connection - * - * @param [in] ops The connection implementation. - * @param [in] state New state to set (uint32_t). - */ -void ioOperations_SetPriority(IoOperations *ops, uint32_t priority); -#endif /* WITH_POLICY */ - -/** - * Sets the interface name associated to the connection. - * - * @param [in] ops The connection implementation. - * @return the name associated to the connection (const char *) - */ -const char * ioOperations_GetInterfaceName(const IoOperations *ops); - -#endif // io_h diff --git a/hicn-light/src/hicn/io/listener.h b/hicn-light/src/hicn/io/listener.h deleted file mode 100644 index 1b473be59..000000000 --- a/hicn-light/src/hicn/io/listener.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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 listener.h - * @brief Provides the function abstraction of all Listeners. - * - * A listener accepts in coming packets. A Stream listener will accept the - * connection then pass it off to the {@link StreamConnection} class. A - * datagram listener will have to have its own way to multiplex packets. - * - */ - -#ifndef listener_h -#define listener_h - -#include <hicn/utils/address.h> -#include <hicn/io/addressPair.h> -#include <hicn/core/connection.h> - -struct listener_ops; -typedef struct listener_ops ListenerOps; - -typedef enum { - ENCAP_TCP, /**< TCP encapsulation type */ - ENCAP_UDP, /**< UDP encapsulation type */ - ENCAP_ETHER, /**< Ethernet encapsulation type */ - ENCAP_LOCAL, /**< A connection to a local protocol stack */ - ENCAP_HICN -} EncapType; - -struct listener_ops { - /** - * A user-defined parameter - */ - void *context; - - /** - * Called to destroy the Listener. - * - * @param [in] listenerOpsPtr Double pointer to this structure - */ - void (*destroy)(ListenerOps **listenerOpsPtr); - - /** - * Returns the listener name of the listener. - * - * @param [in] ops Pointer to this structure - * - * @return the listener name of the listener - */ - const char *(*getListenerName)(const ListenerOps *ops); - - /** - * Returns the interface index of the listener. - * - * @param [in] ops Pointer to this structure - * - * @return the interface index of the listener - */ - unsigned (*getInterfaceIndex)(const ListenerOps *ops); - - /** - * Returns the address pair that defines the listener (local, remote) - * - * @param [in] ops Pointer to this structure - * - * @return the (local, remote) pair of addresses - */ - const Address *(*getListenAddress)(const ListenerOps *ops); - - /** - * Returns the encapsulation type of the listener (e.g. TCP, UDP, HICN) - * - * @param [in] ops Pointer to this structure - * - * @return the listener encapsulation type - */ - EncapType (*getEncapType)(const ListenerOps *ops); - - /** - * Returns the interface name of the listener. - * - * @param [in] ops Pointer to this structure - * - * @return the interface name of the listener - */ - const char *(*getInterfaceName)(const ListenerOps *ops); - - /** - * Returns the underlying socket associated with the listener - * - * Not all listeners are capable of returning a useful socket. In those - * cases, this function pointer is NULL. - * - * TCP does not support this operation (function is NULL). UDP returns its - * local socket. - * - * The caller should never close this socket, the listener will do that when - * its destroy method is called. - * - * @param [in] ops Pointer to this structure - * - * @retval integer The socket descriptor - * - * Example: - * @code - * <#example#> - * @endcode - */ - int (*getSocket)(const ListenerOps *ops); - - unsigned (*createConnection)(ListenerOps *listener, int fd, const AddressPair *pair); - const Connection * (*lookupConnection)(ListenerOps * listener, const AddressPair *pair); -}; -#endif // listener_h diff --git a/hicn-light/src/hicn/io/listenerSet.c b/hicn-light/src/hicn/io/listenerSet.c deleted file mode 100644 index d69632287..000000000 --- a/hicn-light/src/hicn/io/listenerSet.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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 <hicn/hicn-light/config.h> -#include <stdio.h> - -#include <parc/algol/parc_ArrayList.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/io/listenerSet.h> - -struct listener_set { - PARCArrayList *listOfListeners; -}; - -static void listenerSet_DestroyListenerOps(void **opsPtr) { - ListenerOps *ops = *((ListenerOps **)opsPtr); - ops->destroy(&ops); -} - -ListenerSet *listenerSet_Create() { - ListenerSet *set = parcMemory_AllocateAndClear(sizeof(ListenerSet)); - parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerSet)); - set->listOfListeners = parcArrayList_Create(listenerSet_DestroyListenerOps); - - return set; -} - -void listenerSet_Destroy(ListenerSet **setPtr) { - parcAssertNotNull(setPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer"); - - ListenerSet *set = *setPtr; - parcArrayList_Destroy(&set->listOfListeners); - parcMemory_Deallocate((void **)&set); - *setPtr = NULL; -} - -/** - * @function listenerSet_Add - * @abstract Adds the listener to the set - * @discussion - * Unique set based on pair (EncapType, localAddress) - * - * @param <#param1#> - * @return <#return#> - */ -bool listenerSet_Add(ListenerSet *set, ListenerOps *ops) { - parcAssertNotNull(set, "Parameter set must be non-null"); - parcAssertNotNull(ops, "Parameter ops must be non-null"); - - int opsEncap = ops->getEncapType(ops); - const Address *opsAddress = ops->getListenAddress(ops); - - // make sure its not in the set - size_t length = parcArrayList_Size(set->listOfListeners); - for (size_t i = 0; i < length; i++) { - ListenerOps *entry = parcArrayList_Get(set->listOfListeners, i); - - int entryEncap = entry->getEncapType(entry); - const Address *entryAddress = entry->getListenAddress(entry); - - if (opsEncap == entryEncap && addressEquals(opsAddress, entryAddress)) { - // duplicate - return false; - } - } - - parcArrayList_Add(set->listOfListeners, ops); - return true; -} - -size_t listenerSet_Length(const ListenerSet *set) { - parcAssertNotNull(set, "Parameter set must be non-null"); - return parcArrayList_Size(set->listOfListeners); -} - -/** - * Returns the listener at the given index - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] index The index position (0 <= index < listenerSet_Count) - * - * @retval non-null The listener at index - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -ListenerOps *listenerSet_Get(const ListenerSet *set, size_t index) { - parcAssertNotNull(set, "Parameter set must be non-null"); - return parcArrayList_Get(set->listOfListeners, index); -} - -ListenerOps *listenerSet_Find(const ListenerSet *set, EncapType encapType, - const Address *localAddress) { - parcAssertNotNull(set, "Parameter set must be non-null"); - parcAssertNotNull(localAddress, "Parameter localAddress must be non-null"); - - ListenerOps *match = NULL; - - for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners) && !match; - i++) { - ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i); - parcAssertNotNull(ops, "Got null listener ops at index %zu", i); - - if (ops->getEncapType(ops) == encapType) { - if (addressEquals(localAddress, ops->getListenAddress(ops))) { - match = ops; - } - } - } - - return match; -} - -ListenerOps *listenerSet_FindById(const ListenerSet *set, unsigned id) { - parcAssertNotNull(set, "Parameter set must be non-null"); - - ListenerOps *match = NULL; - - for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners) && !match; - i++) { - ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i); - parcAssertNotNull(ops, "Got null listener ops at index %zu", i); - if (ops->getInterfaceIndex(ops) == id) { - match = ops; - } - } - - return match; -} - -int listenerSet_FindIdByListenerName(const ListenerSet *set, const char *listenerName ) { - parcAssertNotNull(set, "Parameter set must be non-null"); - parcAssertNotNull(listenerName, "Parameter listenerName must be non-null"); - - ListenerOps *match = NULL; - int index = -1; - for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners) && !match; - i++) { - ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i); - parcAssertNotNull(ops, "Got null listener ops at index %zu", i); - if (ops->getListenerName(ops) && strcmp(ops->getListenerName(ops), listenerName) == 0) { - index = ops->getInterfaceIndex(ops); - break; - } - } - - return index; -} - -void listenerSet_RemoveById(const ListenerSet *set, unsigned id) { - parcAssertNotNull(set, "Parameter set must be non-null"); - - for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners); - i++) { - ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i); - parcAssertNotNull(ops, "Got null listener ops at index %zu", i); - if (ops->getInterfaceIndex(ops) == id) { - parcArrayList_RemoveAndDestroyAtIndex(set->listOfListeners, i); - break; - } - } -} diff --git a/hicn-light/src/hicn/io/listenerSet.h b/hicn-light/src/hicn/io/listenerSet.h deleted file mode 100644 index 5779d2af4..000000000 --- a/hicn-light/src/hicn/io/listenerSet.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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 listenerSet.h - * @brief A listener set is unique on (EncapType, localAddress) - * - * Keeps track of all the running listeners. The set is unique on the - * encapsulation type and the local address. For example, with TCP - * encapsulation and local address 127.0.0.1 or Ethernet encapsulation and MAC - * address 00:11:22:33:44:55. - * - * NOTE: This does not allow multiple EtherType on the same interface because - * the Address for a LINK address does not include an EtherType. - * - */ - -#ifndef listenerSet_h -#define listenerSet_h - -#include <hicn/io/listener.h> - -struct listener_set; -typedef struct listener_set ListenerSet; - -/** - * <#One Line Description#> - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @retval <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -ListenerSet *listenerSet_Create(void); - -/** - * <#One Line Description#> - * - * <#Paragraphs Of Explanation#> - * - * @param [<#in out in,out#>] <#name#> <#description#> - * - * @retval <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -void listenerSet_Destroy(ListenerSet **setPtr); - -/** - * @function listenerSet_Add - * @abstract Adds the listener to the set - * @discussion - * Unique set based on pair (EncapType, localAddress). - * Takes ownership of the ops memory if added. - * - * @param <#param1#> - * @return true if added, false if not - */ -bool listenerSet_Add(ListenerSet *set, ListenerOps *ops); - -/** - * The number of listeners in the set - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * - * @retval <#value#> <#explanation#> - * - * Example: - * @code - * <#example#> - * @endcode - */ -size_t listenerSet_Length(const ListenerSet *set); -size_t listenerSet_Length(const ListenerSet *set); - -/** - * Returns the listener at the given index - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] index The index position (0 <= index < listenerSet_Lenght) - * - * @retval non-null The listener at index - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -ListenerOps *listenerSet_Get(const ListenerSet *set, size_t index); - -/** - * Looks up a listener by its key (EncapType, LocalAddress) - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] encapType the listener type - * @param [in] localAddress The local bind address (e.g. MAC address or TCP - * socket) - * - * @retval non-null The listener matching the query - * @retval null Does not exist - * - * Example: - * @code - * - * @endcode - */ -ListenerOps *listenerSet_Find(const ListenerSet *set, EncapType encapType, - const Address *localAddress); - -/** - * Looks up a listener by its id - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] id of the listener - * - * @retval non-null The listener matching the query - * @retval null Does not exist - * - * Example: - * @code - * - * @endcode - */ -ListenerOps *listenerSet_FindById(const ListenerSet *set, unsigned id); - -/** - * Looks up a listener by its id - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] name of the listener - * - * @retval greater or equal to 0 The listener matching the query - * @retval -1 Does not exist - * - * Example: - * @code - * - * @endcode - */ -int listenerSet_FindIdByListenerName(const ListenerSet *set, const char *listenerName); - -/** - * Remove up a listener by its id - * - * <#Paragraphs Of Explanation#> - * - * @param [in] set An allocated listener set - * @param [in] id of the listener - * - * Example: - * @code - * - * @endcode - */ -void listenerSet_RemoveById(const ListenerSet *set, unsigned id); -#endif diff --git a/hicn-light/src/hicn/io/streamConnection.c b/hicn-light/src/hicn/io/streamConnection.c deleted file mode 100644 index 00298d1b0..000000000 --- a/hicn-light/src/hicn/io/streamConnection.c +++ /dev/null @@ -1,773 +0,0 @@ -/* - * 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. - */ - -/** - * Common activity for STREAM based listeners. - */ - -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <parc/algol/parc_Hash.h> -#include <hicn/core/connection.h> -#include <hicn/core/forwarder.h> -#include <hicn/core/message.h> -#include <hicn/io/streamConnection.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/core/messageHandler.h> - -#include <hicn/utils/commands.h> - -#include <hicn/hicn.h> -// 128 KB output queue -#define OUTPUT_QUEUE_BYTES (128 * 1024) - -static void _conn_readcb(PARCEventQueue *bufferEventVector, PARCEventType type, - void *ioOpsVoid); - -static void _conn_eventcb(PARCEventQueue *bufferEventVector, - PARCEventQueueEventType events, void *ioOpsVoid); - -typedef struct stream_state { - Forwarder *forwarder; - char * interfaceName; - Logger *logger; - - int fd; - - AddressPair *addressPair; - PARCEventQueue *bufferEventVector; - - bool isLocal; - bool isUp; - bool isClosed; - unsigned id; - - size_t nextMessageLength; - - /* This information would better be stored in the connection data structure - * but it is currently not reachable from within the implementation. */ - connection_state_t state; - connection_state_t admin_state; -#ifdef WITH_POLICY - uint32_t priority; -#endif /* WITH_POLICY */ -} _StreamState; - -// Prototypes -static bool _streamConnection_Send(IoOperations *ops, const Address *nexthop, - Message *message); -static bool _streamConnection_SendIOVBuffer(IoOperations *ops, struct - iovec *msg, size_t size); -static const Address *_streamConnection_GetRemoteAddress( - const IoOperations *ops); -static const AddressPair *_streamConnection_GetAddressPair( - const IoOperations *ops); -static unsigned _streamConnection_GetConnectionId(const IoOperations *ops); -static bool _streamConnection_IsUp(const IoOperations *ops); -static bool _streamConnection_IsLocal(const IoOperations *ops); -static void _streamConnection_DestroyOperations(IoOperations **opsPtr); - -static void _setConnectionState(_StreamState *stream, bool isUp); -static list_connections_type _streamConnection_GetConnectionType( - const IoOperations *ops); -static void _sendProbe(IoOperations *ops, uint8_t *message); -static connection_state_t _streamConnection_getState(const IoOperations *ops); -static void _streamConnection_setState(IoOperations *ops, connection_state_t state); -static connection_state_t _streamConnection_getAdminState(const IoOperations *ops); -static void _streamConnection_setAdminState(IoOperations *ops, connection_state_t admin_state); -#ifdef WITH_POLICY -static uint32_t _streamConnection_getPriority(const IoOperations *ops); -static void _streamConnection_setPriority(IoOperations *ops, uint32_t priority); -#endif /* WITH_POLICY */ -static const char * _streamConnection_getInterfaceName(const IoOperations *ops); - -/* - * This assigns a unique pointer to the void * which we use - * as a GUID for this class. - */ -static const void *_ioOperationsGuid = __FILE__; - -/* - * Return our GUID - */ -static const void *_streamConnection_Class(const IoOperations *ops) { - return _ioOperationsGuid; -} - -static IoOperations _template = { - .closure = NULL, - .send = &_streamConnection_Send, - .sendIOVBuffer = &_streamConnection_SendIOVBuffer, - .getRemoteAddress = &_streamConnection_GetRemoteAddress, - .getAddressPair = &_streamConnection_GetAddressPair, - .getConnectionId = &_streamConnection_GetConnectionId, - .isUp = &_streamConnection_IsUp, - .isLocal = &_streamConnection_IsLocal, - .destroy = &_streamConnection_DestroyOperations, - .class = &_streamConnection_Class, - .getConnectionType = &_streamConnection_GetConnectionType, - .sendProbe = &_sendProbe, - .getState = &_streamConnection_getState, - .setState = &_streamConnection_setState, - .getAdminState = &_streamConnection_getAdminState, - .setAdminState = &_streamConnection_setAdminState, -#ifdef WITH_POLICY - .getPriority = &_streamConnection_getPriority, - .setPriority = &_streamConnection_setPriority, -#endif /* WITH_POLICY */ - .getInterfaceName = &_streamConnection_getInterfaceName, -}; - -IoOperations *streamConnection_AcceptConnection(Forwarder *forwarder, int fd, - AddressPair *pair, - bool isLocal) { - _StreamState *stream = parcMemory_AllocateAndClear(sizeof(_StreamState)); - parcAssertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_StreamState)); - - Dispatcher *dispatcher = forwarder_GetDispatcher(forwarder); - PARCEventScheduler *eventBase = dispatcher_GetEventScheduler(dispatcher); - stream->bufferEventVector = parcEventQueue_Create( - eventBase, fd, - PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks); - - stream->forwarder = forwarder; - stream->interfaceName = NULL; - stream->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - stream->fd = fd; - stream->id = forwarder_GetNextConnectionId(forwarder); - stream->addressPair = pair; - stream->isClosed = false; - -#ifdef WITH_POLICY - stream->priority = 0; -#endif /* WITH_POLICY */ - - // allocate a connection - IoOperations *io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations)); - parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(IoOperations)); - memcpy(io_ops, &_template, sizeof(IoOperations)); - io_ops->closure = stream; - stream->isLocal = isLocal; - - parcEventQueue_SetCallbacks(stream->bufferEventVector, _conn_readcb, NULL, - _conn_eventcb, (void *)io_ops); - parcEventQueue_Enable(stream->bufferEventVector, PARCEventType_Read); - - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionCreate, stream->id)); - - // As we are acceting a connection, we begin in the UP state - _setConnectionState(stream, true); - - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - char *pair_str = addressPair_ToString(pair); - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "StreamConnection %p accept for address pair %s", (void *)stream, - pair_str); - free(pair_str); - } - - return io_ops; -} - -IoOperations *streamConnection_OpenConnection(Forwarder *forwarder, - AddressPair *pair, bool isLocal) { - parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null"); - parcAssertNotNull(pair, "Parameter pair must be non-null"); - - // if there's an error on the bind or connect, will return NULL - PARCEventQueue *bufferEventVector = - dispatcher_StreamBufferConnect(forwarder_GetDispatcher(forwarder), pair); - if (bufferEventVector == NULL) { - // error opening connection - return NULL; - } - - _StreamState *stream = parcMemory_AllocateAndClear(sizeof(_StreamState)); - parcAssertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_StreamState)); - - stream->forwarder = forwarder; - stream->interfaceName = NULL; - stream->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - stream->fd = parcEventQueue_GetFileDescriptor(bufferEventVector); - stream->bufferEventVector = bufferEventVector; - stream->id = forwarder_GetNextConnectionId(forwarder); - stream->addressPair = pair; - stream->isClosed = false; - - // allocate a connection - IoOperations *io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations)); - parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(IoOperations)); - memcpy(io_ops, &_template, sizeof(IoOperations)); - io_ops->closure = stream; - stream->isLocal = isLocal; - - parcEventQueue_SetCallbacks(stream->bufferEventVector, _conn_readcb, NULL, - _conn_eventcb, (void *)io_ops); - parcEventQueue_Enable(stream->bufferEventVector, PARCEventType_Read); - - // we start in DOWN state, until remote side answers - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionCreate, stream->id)); - _setConnectionState(stream, false); - - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, PARCLogLevel_Info)) { - char *pair_str = addressPair_ToString(pair); - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__, - "StreamConnection %p connect for address pair %s", - (void *)stream, pair_str); - free(pair_str); - } - - return io_ops; -} - -static void _streamConnection_DestroyOperations(IoOperations **opsPtr) { - parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer"); - parcAssertNotNull(*opsPtr, - "Parameter opsPtr must dereference to non-null pointer"); - - IoOperations *ops = *opsPtr; - parcAssertNotNull(ioOperations_GetClosure(ops), - "ops->context must not be null"); - - _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops); - - parcEventQueue_Destroy(&stream->bufferEventVector); - - addressPair_Release(&stream->addressPair); - - if (!stream->isClosed) { - stream->isClosed = true; - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionClosed, stream->id)); - } - - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionDestroyed, stream->id)); - - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, PARCLogLevel_Info)) { - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__, - "StreamConnection %p destroyed", (void *)stream); - } - - logger_Release(&stream->logger); - parcMemory_Deallocate((void **)&stream); - parcMemory_Deallocate((void **)&ops); - - *opsPtr = NULL; -} - -static bool _streamConnection_IsUp(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->isUp; -} - -static bool _streamConnection_IsLocal(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->isLocal; -} - -static const Address *_streamConnection_GetRemoteAddress( - const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return addressPair_GetRemote(stream->addressPair); -} - -static const AddressPair *_streamConnection_GetAddressPair( - const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->addressPair; -} - -static unsigned _streamConnection_GetConnectionId(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->id; -} - -bool _streamConnection_SendIOVBuffer(IoOperations *ops, - struct iovec * message, size_t size) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - - _StreamState *conn = (_StreamState *)ioOperations_GetClosure(ops); - - if (!conn->isUp) { - if (logger_IsLoggable(conn->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - logger_Log( - conn->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "connid %u tried to send to down connection (isUp %d isClosed %d)", - conn->id, conn->isUp, conn->isClosed); - } - return false; - } - - PARCEventBuffer *buffer = - parcEventBuffer_GetQueueBufferOutput(conn->bufferEventVector); - size_t buffer_backlog = parcEventBuffer_GetLength(buffer); - parcEventBuffer_Destroy(&buffer); - - if (buffer_backlog >= OUTPUT_QUEUE_BYTES) { - if (logger_IsLoggable(conn->logger, LoggerFacility_IO, - PARCLogLevel_Warning)) { - logger_Log(conn->logger, LoggerFacility_IO, PARCLogLevel_Warning, - __func__, - "connid %u Writing to buffer backlog %zu bytes DROP MESSAGE", - conn->id, buffer_backlog); - } - return false; - } - - if (logger_IsLoggable(conn->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - size_t length = 0; - for (int i = 0; i < size; i++) - length += message[i].iov_len; - - logger_Log( conn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "connid %u Writing %zu bytes to buffer with backlog %zu bytes", - conn->id, length, buffer_backlog); - } - - /* Write directly into the parcEventQueue without passing through message */ - for (int i = 0; i < size; i++) { - if (parcEventQueue_Write(conn->bufferEventVector, message[i].iov_base, - message[i].iov_len) != 0) - return false; - } - - return true; -} - -/** - * @function streamConnection_Send - * @abstract Non-destructive send of the message. - * @discussion - * Send uses message_CopyToStreamBuffer, which is a non-destructive write. - * The send may fail if there's no buffer space in the output queue. - * - * @param dummy is ignored. A stream has only one peer. - * @return <#return#> - */ -static bool _streamConnection_Send(IoOperations *ops, const Address *dummy, - Message *message) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops); - - bool success = false; - if (stream->isUp) { - PARCEventBuffer *buffer = - parcEventBuffer_GetQueueBufferOutput(stream->bufferEventVector); - size_t buffer_backlog = parcEventBuffer_GetLength(buffer); - parcEventBuffer_Destroy(&buffer); - - if (buffer_backlog < OUTPUT_QUEUE_BYTES) { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Debug)) { - logger_Log( - stream->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "connid %u Writing %zu bytes to buffer with backlog %zu bytes", - stream->id, message_Length(message), buffer_backlog); - } - - int failure = message_Write(stream->bufferEventVector, message); - if (failure == 0) { - success = true; - } - } else { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Warning)) { - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Warning, - __func__, - "connid %u Writing to buffer backlog %zu bytes DROP MESSAGE", - stream->id, buffer_backlog); - } - } - } else { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - logger_Log( - stream->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "connid %u tried to send to down connection (isUp %d isClosed %d)", - stream->id, stream->isUp, stream->isClosed); - } - } - - return success; -} - -list_connections_type _streamConnection_GetConnectionType( - const IoOperations *ops) { - return CONN_TCP; -} - -static void _sendProbe(IoOperations *ops, uint8_t *message) { - // we don't need to implemet this here, it is a local connection -} - -// ================================================================= -// the actual I/O functions - -int _isACommand(PARCEventBuffer *input) { - size_t bytesAvailable = parcEventBuffer_GetLength(input); - parcAssertTrue(bytesAvailable >= sizeof(header_control_message), - "Called with too short an input: %zu", bytesAvailable); - - uint8_t *msg = parcEventBuffer_Pullup(input, bytesAvailable); - // read first byte of the header - - // first byte: must be a REQUEST_LIGHT - if (msg[0] != REQUEST_LIGHT) { - return LAST_COMMAND_VALUE; - } - - // second byte: must be a command_id - if (msg[1] < 0 || msg[1] >= LAST_COMMAND_VALUE) { - return LAST_COMMAND_VALUE; - } - - return msg[1]; -} - -PARCEventBuffer *_tryReadControlMessage(_StreamState *stream, - PARCEventBuffer *input, - command_id command, - struct iovec **request) { - size_t bytesAvailable = parcEventBuffer_GetLength(input); - - if (stream->nextMessageLength == 0) { - stream->nextMessageLength = - sizeof(header_control_message) + - payloadLengthDaemon(command); // consider the whole packet. - } - - if (bytesAvailable >= stream->nextMessageLength) { - PARCEventBuffer *message = parcEventBuffer_Create(); - int bytesRead = parcEventBuffer_ReadIntoBuffer(input, message, - stream->nextMessageLength); - parcAssertTrue(bytesRead == stream->nextMessageLength, - "Partial read, expected %zu got %d", - stream->nextMessageLength, bytesRead); - - uint8_t *control = - parcEventBuffer_Pullup(message, stream->nextMessageLength); - if (!(*request = (struct iovec *)parcMemory_AllocateAndClear( - sizeof(struct iovec) * 2))) { - return NULL; - } - (*request)[0].iov_base = control; // header - (*request)[0].iov_len = sizeof(header_control_message); - if (payloadLengthDaemon(command) > 0) { - (*request)[1].iov_base = - control + sizeof(header_control_message); // payload - } else { - (*request)[1].iov_base = NULL; - } - (*request)[1].iov_len = payloadLengthDaemon(command); - // now reset message length for next packet - - stream->nextMessageLength = 0; - - return message; - } - - return NULL; -} - -static bool _isAnHicnPacket(PARCEventBuffer *input) { - size_t bytesAvailable = parcEventBuffer_GetLength(input); - parcAssertTrue(bytesAvailable >= sizeof(header_control_message), - "Called with too short an input: %zu", bytesAvailable); - - uint8_t *fh = parcEventBuffer_Pullup(input, sizeof(header_control_message)); - return messageHandler_IsValidHicnPacket(fh); -} - -static Message *_readMessage(_StreamState *stream, Ticks time, - PARCEventBuffer *input) { - Message *message = message_CreateFromEventBuffer( - input, stream->nextMessageLength, stream->id, time, stream->logger); - - return message; -} - -static void _startNewMessage(_StreamState *stream, PARCEventBuffer *input, - size_t inputBytesAvailable) { - parcAssertTrue(stream->nextMessageLength == 0, - "Invalid state, nextMessageLength not zero: %zu", - stream->nextMessageLength); - parcAssertTrue(inputBytesAvailable >= sizeof(header_control_message), - "read_length not a whole fixed header!: %zd", - inputBytesAvailable); - - // this linearizes the first messageHandler_GetIPv6HeaderLength() bytes of the - // input buffer's iovecs and returns a pointer to it. - uint8_t *fh = parcEventBuffer_Pullup(input, sizeof(header_control_message)); - - // Calculate the total message size based on the fixed header - stream->nextMessageLength = messageHandler_GetTotalPacketLength(fh); -} - -static Message *_tryReadMessage(PARCEventBuffer *input, _StreamState *stream) { - size_t bytesAvailable = parcEventBuffer_GetLength(input); - parcAssertTrue(bytesAvailable >= sizeof(header_control_message), - "Called with too short an input: %zu", bytesAvailable); - - if (stream->nextMessageLength == 0) { - _startNewMessage(stream, input, bytesAvailable); - } - - // This is not an ELSE statement. We can both start a new message then - // check if there's enough bytes to read the whole thing. - - if (bytesAvailable >= stream->nextMessageLength) { - Message *message = - _readMessage(stream, forwarder_GetTicks(stream->forwarder), input); - - // now reset message length for next packet - stream->nextMessageLength = 0; - - return message; - } - - return NULL; -} - -/** - * @function conn_readcb - * @abstract Event callback for reads - * @discussion - * Will read messages off the input. Continues reading as long as we - * can get a header to determine the next message length or as long as we - * can read a complete message. - * - * This function manipulates the read low water mark. (1) read a fixed header - * plus complete message, then set the low water mark to FIXED_HEADER_LEN. (2) - * read a fixed header, but not a complete message, then set low water mark to - * the total mesage length. Using the low water mark like this means the buffer - * event will only trigger on meaningful byte boundaries when we can get actual - * work done. - * - * @param <#param1#> - * @return <#return#> - */ -static void _conn_readcb(PARCEventQueue *event, PARCEventType type, - void *ioOpsVoid) { - command_id command; - IoOperations *ops = (IoOperations *)ioOpsVoid; - _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops); - - PARCEventBuffer *input = parcEventBuffer_GetQueueBufferInput(event); - - // drain the input buffer - - // notice that we always try to read at least 8 bytes - // (sizeof(header_control_message)). This is enough to read the length of all - // kind of packets - while (parcEventBuffer_GetLength(input) >= sizeof(header_control_message) && - parcEventBuffer_GetLength(input) >= stream->nextMessageLength) { - - if ((command = _isACommand(input)) != LAST_COMMAND_VALUE) { - struct iovec *rx; - // Get message from the stream and set the stream->nextMessageLength - PARCEventBuffer *message = - _tryReadControlMessage(stream, input, command, &rx); - // If received correctly the whole message, send to dispatcher - if (message) { - forwarder_ReceiveCommand(stream->forwarder, command, rx, stream->id); - parcMemory_Deallocate((void **)&rx); - parcEventBuffer_Destroy(&message); - } - - } else if (_isAnHicnPacket(input)) { - // this is an Hicn packet (here we should distinguish between IPv4 and - // IPv6 tryReadMessage may set nextMessageLength - Message *message = _tryReadMessage(input, stream); - - if (message) { - forwarder_Receive(stream->forwarder, message); - } - - } else { - parcAssertTrue(false, - "(Local stream connection) malformed packet received"); - } - } - - if (stream->nextMessageLength == 0) { - // we don't have the next header, so set it to the header length - streamBuffer_SetWatermark(event, true, false, - sizeof(header_control_message), 0); - } else { - // set it to the packet length - streamBuffer_SetWatermark(event, true, false, stream->nextMessageLength, 0); - } - parcEventBuffer_Destroy(&input); -} - -static void _setConnectionState(_StreamState *stream, bool isUp) { - parcAssertNotNull(stream, "Parameter stream must be non-null"); - - Messenger *messenger = forwarder_GetMessenger(stream->forwarder); - - bool oldStateIsUp = stream->isUp; - stream->isUp = isUp; - - if (oldStateIsUp && !isUp) { - // bring connection DOWN - Missive *missive = missive_Create(MissiveType_ConnectionDown, stream->id); - messenger_Send(messenger, missive); - return; - } - - if (!oldStateIsUp && isUp) { - // bring connection UP - Missive *missive = missive_Create(MissiveType_ConnectionUp, stream->id); - messenger_Send(messenger, missive); - return; - } -} - -static void _conn_eventcb(PARCEventQueue *event, PARCEventQueueEventType events, - void *ioOpsVoid) { - IoOperations *ops = (IoOperations *)ioOpsVoid; - _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops); - - if (events & PARCEventQueueEventType_Connected) { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__, - "Connection %u is connected", stream->id); - } - - // if the stream was closed, do not transition to an UP state - if (!stream->isClosed) { - _setConnectionState(stream, true); - } - } else if (events & PARCEventQueueEventType_EOF) { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__, - "connid %u closed.", stream->id); - } - - parcEventQueue_Disable(stream->bufferEventVector, PARCEventType_Read); - - _setConnectionState(stream, false); - - if (!stream->isClosed) { - stream->isClosed = true; - // this will cause the connection manager to destroy the connection later - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionClosed, stream->id)); - } - } else if (events & PARCEventQueueEventType_Error) { - if (logger_IsLoggable(stream->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Error, - __func__, "Got an error on the connection %u: %s", stream->id, - strerror(errno)); - } - - parcEventQueue_Disable(stream->bufferEventVector, - PARCEventType_Read | PARCEventType_Write); - - _setConnectionState(stream, false); - - if (!stream->isClosed) { - stream->isClosed = true; - // this will cause the connection manager to destroy the connection later - messenger_Send(forwarder_GetMessenger(stream->forwarder), - missive_Create(MissiveType_ConnectionClosed, stream->id)); - } - } - /* None of the other events can happen here, since we haven't enabled - * timeouts */ -} - -static connection_state_t _streamConnection_getState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->state; -} - -static void _streamConnection_setState(IoOperations *ops, connection_state_t state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _StreamState *stream = - (_StreamState *)ioOperations_GetClosure(ops); - stream->state = state; -} - -static connection_state_t _streamConnection_getAdminState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->admin_state; -} - -static void _streamConnection_setAdminState(IoOperations *ops, connection_state_t admin_state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _StreamState *stream = - (_StreamState *)ioOperations_GetClosure(ops); - stream->admin_state = admin_state; -} - -#ifdef WITH_POLICY -static uint32_t _streamConnection_getPriority(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _StreamState *stream = - (const _StreamState *)ioOperations_GetClosure(ops); - return stream->priority; -} - -static void _streamConnection_setPriority(IoOperations *ops, uint32_t priority) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _StreamState *stream = - (_StreamState *)ioOperations_GetClosure(ops); - stream->priority = priority; -} -#endif /* WITH_POLICY */ - -static const char * _streamConnection_getInterfaceName(const IoOperations *ops) -{ - parcAssertNotNull(ops, "Parameter must be non-null"); - _StreamState *stream = - (_StreamState *)ioOperations_GetClosure(ops); - return stream->interfaceName; -} diff --git a/hicn-light/src/hicn/io/streamConnection.h b/hicn-light/src/hicn/io/streamConnection.h deleted file mode 100644 index f483d0b82..000000000 --- a/hicn-light/src/hicn/io/streamConnection.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - */ - -/** - * Methods common to TCP and PF_LOCAL stream-based listeners - */ - -#ifndef streamConnection_h -#define streamConnection_h - -#include <hicn/core/forwarder.h> -#include <hicn/core/messagePacketType.h> -#include <hicn/io/addressPair.h> -#include <hicn/io/ioOperations.h> -#include <hicn/utils/address.h> - -/** - * @function streamConnection_AcceptConnection - * @abstract Receive a connection from a remote peer - * @discussion - * We are the "server side" of the stream connection, so we need to accept the - * client connection and setup state for her. - * - * @param <#param1#> - * @return <#return#> - */ -IoOperations *streamConnection_AcceptConnection(Forwarder *forwarder, int fd, - AddressPair *pair, - bool isLocal); - -/** - * @function streamConnection_OpenConnection - * @abstract Initiate a connection to a remote peer - * @discussion - * We are the "client side" of the stream connection. We'll create state for - * the peer, but it will be in the "down" state until the connection - * establishes. - * - * For TCP, both address pairs need to be the same address family: both INET - * or both INET6. The remote address must have the complete socket information - * (address, port). The local socket could be wildcarded or may specify down to - * the (address, port) pair. - * - * If the local address is IPADDR_ANY and the port is 0, then it is a normal - * call to "connect" that will use whatever local IP address and whatever local - * port for the connection. If either the address or port is set, the local - * socket will first be bound (via bind(2)), and then call connect(). - * - * AF_UNIX is not yet supported - * - * If there's an error binding to the specified address or connecting to the - * remote address, will return NULL. - * - * @param pair (takes ownership of this) is the complete socket pair of - * (address, port) for each end, if INET or INET6. - * @return NULL on error, otherwise the connections IO operations. - */ -IoOperations *streamConnection_OpenConnection(Forwarder *forwarder, - AddressPair *pair, bool isLocal); - -bool streamState_SendIOVBuffer(IoOperations *ops, struct iovec *response, - size_t size); - -#endif // streamConnection_h diff --git a/hicn-light/src/hicn/io/tcp.c b/hicn-light/src/hicn/io/tcp.c new file mode 100644 index 000000000..03911e556 --- /dev/null +++ b/hicn-light/src/hicn/io/tcp.c @@ -0,0 +1,563 @@ +/* + * 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. + */ + +/** + * Common activity for STREAM based listeners. + */ + +#include <errno.h> +#ifndef _WIN32 +#include <unistd.h> // fcntl +#endif /* _WIN32 */ +#include <fcntl.h> // fcntl +#include <hicn/hicn-light/config.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include <hicn/core/connection.h> +#include <hicn/core/connection_vft.h> +#include <hicn/core/listener.h> +#include <hicn/core/listener_vft.h> +#include <hicn/core/msgbuf.h> +#include <hicn/core/forwarder.h> + +#include <hicn/core/messageHandler.h> + +#include <hicn/utils/commands.h> +#include <hicn/util/log.h> + +#include <hicn/hicn.h> +// 128 KB output queue +#define OUTPUT_QUEUE_BYTES (128 * 1024) + +#define RECV_BUFLEN 8192 +#define MTU 1500 + +// XXX TODO what is exactly an eventqueue +// XXX TODO can't we write directly to the socket ? + +/****************************************************************************** + * Listener + ******************************************************************************/ + +typedef struct { +} listener_tcp_data_t; + +static +int +listener_tcp_initialize(listener_t * listener) +{ + + ERROR("[listener_tcp_initialize] Not implemented"); + + return 0; +} + +static +void +listener_tcp_finalize(listener_t * listener) +{ + + ERROR("[listener_tcp_finalize] Not implemented"); +} + +static +int +listener_tcp_punt(const listener_t * listener, const char * prefix_s) +{ + ERROR("[listener_tcp_punt] Not implemented"); + return -1; +} + +static +int +listener_tcp_get_socket(const listener_t * listener, const address_t * local, + const address_t * remote, const char * interface_name) +{ + + ERROR("[listener_tcp_get_socket] Not implemented"); + return -1; + +} + +static +void +listener_tcp_read_callback(listener_t * listener, int fd, void * data) +{ + ERROR("[listener_tcp_read_callback] Not implemented"); + +} + +DECLARE_LISTENER(tcp); + +/****************************************************************************** + * Connection + ******************************************************************************/ + + +typedef struct { + /* Partial receive buffer */ + u8 buf[RECV_BUFLEN]; + size_t roff; /**< Read offset */ + size_t woff; /**< Write offset */ + + + // XXX this should be initialized with the header length, and tells what we + // expect to receive next... + size_t next_len; + struct bufferevent * bufferevent; +} connection_tcp_data_t; + +// XXX This seems more a listener code ! +// XXX we must have accept to the connection table to spawn new ones !! +// XXX equivalent to initialize +int +connection_tcp_accept(connection_t * connection, forwarder_t *forwarder, int fd, + address_pair_t *pair, bool local, unsigned connection_id) +{ + assert(connection); + assert(forwarder); + + *connection = (connection_t) { + .id = connection_id, + .interface_name = NULL, + .type = FACE_TYPE_TCP, + .pair = *pair, + .fd = fd, + .local = local, + // As we are accepting a connection, we begin in the UP state + .state = FACE_STATE_UP, + .admin_state = FACE_STATE_UP, +#ifdef WITH_POLICY + .priority = 0, +#endif /* WITH_POLICY */ + + .forwarder = forwarder, + .closed = false, + }; + + // XXX this new connection needs to be registered + //char *str = pair_ToString(udp->pair); + INFO("%s connection %p created for address %s (local=%s)", + face_type_str(connection->type), connection, "N/A", + connection_is_local(connection) ? "true" : "false"); + //free(str); + + return 0; +} + +int +make_socket(address_pair_t * pair) +{ +#ifndef _WIN32 + int fd = socket(address_family(&pair->local), SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + goto ERR_SOCKET; + } +#else + SOCKET fd = socket(address_family(&pair->local), SOCK_STREAM, 0); + if (fd == INVALID_SOCKET) { + perror("socket"); + goto ERR_SOCKET; + } +#endif /* _WIN32 */ + + /* Set non-blocking flag */ +#ifndef _WIN32 + int flags = fcntl(fd, F_GETFL, NULL); + if (flags == -1) { + perror("F_GETFL"); + goto ERR; + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { + perror("F_SETFL"); + goto ERR; + } +#else + if (ioctlsocket(fd, FIONBIO, &(u_long){1}) != NO_ERROR) { + perror("ioctlsocket"); + goto ERR; + } +#endif /* _WIN32 */ + + if (bind(fd, address_sa(&pair->local), address_socklen(&pair->local)) == -1) { + perror("bind"); + goto ERR; + } + + if (connect(fd, address_sa(&pair->remote), address_socklen(&pair->remote)) < 0) { + perror("connect"); + goto ERR; + } + + + return 0; + +ERR: +#ifndef _WIN32 + close(fd); +#else + closesocket(fd); +#endif + +ERR_SOCKET: + return -1; + +} + +static +int +connection_tcp_initialize(connection_t * connection) +{ + assert(connection); + assert(connection->type = FACE_TYPE_TCP); + + connection_tcp_data_t * data = connection->data; + assert(data); + + data->roff = 0; + data->woff = 0; + + connection->fd = make_socket(connection_get_pair(connection)); + if (connection->fd < 0) { + ERROR("Error creating TCP socket"); + return -1; + } + + //char *pair_str = address_pair_ToString(pair); + INFO("%s connection %p connect for address pair %s", + face_type_str(connection->type), connection, "N/A"); + //free(pair_str); + + return 0; +} + +// XXX a part needs to be handled in the connection.c +static +void +connection_tcp_finalize(connection_t * connection) +{ + if (!connection->closed) { + connection->closed = true; + // XXX need to delete the connection like previously in the connection + // manager + } + + INFO("%s connection %p destroyed", face_type_str(connection->type), + connection); + // XXX need to release the "connection" +} + +#if 0 +static +bool +connection_tcp_sendv(connnection_t * connection, struct iovec * iov, + size_t size) +{ + assert(connection); + assert(iov); + + if (!connection_is_up(connection)) { + ERROR("Connection #%u tried to send to down connection (up=%d closed=%d)", + connection_get_id(connection), + connection_get_up(connection) ? "true" : "false", + connection_get_closed(connection) ? "true" : "false"); + return false; + } + + PARCEventBuffer *buffer = + parcEventBuffer_GetQueueBufferOutput(connection->events); + size_t buffer_backlog = parcEventBuffer_GetLength(buffer); + parcEventBuffer_Destroy(&buffer); + + if (buffer_backlog >= OUTPUT_QUEUE_BYTES) { + WARN("Connection #%u Writing to buffer backlog %zu bytes DROP MESSAGE", + connection_get_id(connection), buffer_backlog); + return false; + } + +#if 0 + /* DEBUG */ + size_t length = 0; + for (int i = 0; i < size; i++) + length += message[i].iov_len; + DEBUG("Connection #%u writing %zu bytes to buffer with backlog %zu bytes", + connection_get_id(connection), length, buffer_backlog); +#endif + + /* Write directly into the parcEventQueue without passing through message */ + for (int i = 0; i < size; i++) { + if (parcEventQueue_Write(conn->events, iov[i].iov_base, + iov[i].iov_len) != 0) + return false; + } + + return true; +} +#endif + +/** + * @function streamConnection_Send + * @abstract Non-destructive send of the message. + * @discussion + * Send uses message_CopyToStreamBuffer, which is a non-destructive write. + * The send may fail if there's no buffer space in the output queue. + * + * @param dummy is ignored. A stream has only one peer. + * @return <#return#> + */ +// XXX address not used anywhere +// XXX too much repeated code with sendv here +static +int +connection_tcp_send(const connection_t * connection, //const address_t * address, + msgbuf_t * msgbuf, bool queue) +{ + assert(connection); + assert(address); + /* msgbuf can be NULL */ + + /* No need to flush */ + if (!msgbuf) + return true; + + if (!connection_is_up(connection)) { + ERROR("Connection #%u tried to send to down connection (up=%d closed=%d)", + connection_get_id(connection), + connection_is_up(connection) ? "true" : "false", + connection_is_closed(connection) ? "true" : "false"); + return false; + } + + // XXX TODO write to fd +#if 0 + PARCEventBuffer *buffer = + parcEventBuffer_GetQueueBufferOutput(connection->events); + size_t buffer_backlog = parcEventBuffer_GetLength(buffer); + parcEventBuffer_Destroy(&buffer); + + if (buffer_backlog >= OUTPUT_QUEUE_BYTES) { + WARN("Connection #%u Writing to buffer backlog %zu bytes DROP MESSAGE", + connection_get_id(connection), buffer_backlog); + return false; + } + + DEBUG("Connection #%u Writing %zu bytes to buffer with backlog %zu bytes", + connection_get_id(connection), msgbuf_len(message), buffer_backlog); + + return (parcEventQueue_Write(connection->events, msgbuf_packet(message), + msgbuf_len(message)) == 0); +#endif + return true; +} + +static +int +connection_tcp_send_packet(const connection_t * connection, + const uint8_t * packet, size_t size) +{ + /* Not implemented for local connections */ + // XXX shall we set the pointer to NULL and add a check ? + + ERROR("[connection_tcp_send_packet] Not implemented"); + + return -1; +} + +// ================================================================= +// the actual I/O functions + +// not needed anymore ? +#if 0 +// XXX this is called iif there is sufficient data to read, otherwise it raises +// an assertion error. This was a problem before I guess +static +int +connection_tcp_read_message(connection_t * connection, msgbuf_t * msgbuf) +{ + assert(connection); + assert(msgbuf); + + connection_tcp_data_t * data = connection->data; + assert(data); + + size_t n = evbuffer_get_length(data->evbuffer); + // XXX this check was wrong + // parcAssertTrue(n >= sizeof(header_control_message), + "Called with too short an input: %zu", n); + + // XXX WTF + if (stream->next_len == 0) { + // this linearizes the first messageHandler_GetIPv6HeaderLength() bytes of the + // input buffer's iovecs and returns a pointer to it. + uint8_t *fh = parcEventBuffer_Pullup(data->evbuffer, sizeof(header_control_message)); + + // Calculate the total message size based on the fixed header + stream->next_len = messageHandler_GetTotalPacketLength(fh); + } + // This is not an ELSE statement. We can both start a new message then + // check if there's enough bytes to read the whole thing. + + if (n < stream->next_len) + return -1; + + uint8_t packet_type; + if (messageHandler_IsInterest(packet)) { + packet_type = MESSAGE_TYPE_INTEREST; + } else if (messageHandler_IsData(packet)) { + packet_type = MESSAGE_TYPE_DATA; + } else { + ERROR("Dropped packet that is not interest nor data"); + goto ERR; + } + + if (evbuffer_remove(data->evbuffer, data->packet, data->next_len) < 0) + return -1; + + msgbuf_from_packet(msgbuf, data->packet, packet_type, stream->id, + ticks_now()); + + // now reset message length for next packet + data->next_len = 0; + return 0; + +ERR: + evbuffer_drain(data->evbuffer, data->next_len); + return -1; +} +#endif + +/** + * @function conn_readcb + * @abstract Event callback for reads + * @discussion + * Will read messages off the input. Continues reading as long as we + * can get a header to determine the next message length or as long as we + * can read a complete message. + * + * This function manipulates the read low water mark. (1) read a fixed header + * plus complete message, then set the low water mark to FIXED_HEADER_LEN. (2) + * read a fixed header, but not a complete message, then set low water mark to + * the total mesage length. Using the low water mark like this means the buffer + * event will only trigger on meaningful byte boundaries when we can get actual + * work done. + * + * @param <#param1#> + * @return <#return#> + */ +static +void +connection_tcp_read_callback(connection_t * connection, int fd, void * user_data) +{ + assert(!!(what & PARCEventType_Read)); + assert(connection_void); + + connection_tcp_data_t * data = connection->data; + assert(RECV_BUFLEN - data->woff > MTU); + + /* No batching here as code is not expected to receive much throughput */ + for (;;) { + ssize_t n = recv(connection->fd, data->buf + data->woff, + RECV_BUFLEN - data->woff, 0); + if (n == 0) /* EOF */ + return; // XXX close connection + if (n < 0) { + if (errno == EWOULDBLOCK) + break; + perror("recv"); + return; // XXX close connection + } + data->woff += n; + + /* Process */ + uint8_t * packet = data->buf + data->roff; + size_t size = data->woff - data->roff; /* > 0 */ + + ssize_t used = listener_read_callback(connection->forwarder, NULL, fd, + address_pair_get_local(&connection->pair), packet, size); + if (used < 0) + return; // XXX close connection ? + if (used == 0) + break; /* We would have received more if there was still packets to be read */ + data->roff += used; + assert(data->roff <= data->woff); + + if (data->roff == data->woff) { + /* Reset state whenever possible to avoid memcpy's */ + data->roff = 0; + data->woff = 0; + return; + } + } + + /* Make sure there is enough remaining space in the buffer */ + if (RECV_BUFLEN - data->woff < MTU) { + /* + * There should be no overlap provided a sufficiently large BUFLEN, but + * who knows. + */ + memmove(data->buf, data->buf + data->roff, data->woff - data->roff); + data->woff -= data->roff; + data->roff = 0; + } + + return; +} + +#if 0 +static +void +connection_tcp_callback(connection_t * connection, int fd, void * user_data) +{ + if (events & PARCEventQueueEventType_Connected) { + INFO("Connection %u is connected", stream->id); + + // if the stream was closed, do not transition to an UP state + if (!stream->isClosed) { + _setConnectionState(stream, true); + } + } else if (events & PARCEventQueueEventType_EOF) { + INFO("connid %u closed.", stream->id); + + parcEventQueue_Disable(stream->events, PARCEventType_Read); + + _setConnectionState(stream, false); + + if (!stream->isClosed) { + stream->isClosed = true; + // XXX TODO destroy the connection + } + } else if (events & PARCEventQueueEventType_Error) { + ERROR("Got an error on the connection %u: %s", stream->id, + strerror(errno)); + + parcEventQueue_Disable(stream->events, + PARCEventType_Read | PARCEventType_Write); + + _setConnectionState(stream, false); + + if (!stream->isClosed) { + stream->isClosed = true; + // XXX TODO destroy the connection + } + } + /* None of the other events can happen here, since we haven't enabled + * timeouts */ +} +#endif + +DECLARE_CONNECTION(tcp) diff --git a/hicn-light/src/hicn/io/tcpListener.c b/hicn-light/src/hicn/io/tcpListener.c deleted file mode 100644 index e2b80c215..000000000 --- a/hicn-light/src/hicn/io/tcpListener.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * 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 <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <hicn/core/connectionTable.h> -#include <hicn/core/forwarder.h> -#include <hicn/io/listener.h> -#include <hicn/io/streamConnection.h> -#include <hicn/io/tcpListener.h> - -#include <parc/algol/parc_Memory.h> -#include <parc/algol/parc_Network.h> -#include <parc/assert/parc_Assert.h> - -typedef struct tcp_listener { - char *listenerName; - Forwarder *forwarder; - Logger *logger; - - PARCEventSocket *listener; - - Address *localAddress; - - unsigned id; - char *interfaceName; - - // is the localAddress as 127.0.0.0 address? - bool isLocalAddressLocal; -} _TcpListener; - -static void _tcpListener_Destroy(_TcpListener **listenerPtr); - -static void _tcpListener_OpsDestroy(ListenerOps **listenerOpsPtr); - -static const char *_tcpListener_ListenerName(const ListenerOps *ops); - -static unsigned _tcpListener_OpsGetInterfaceIndex(const ListenerOps *ops); - -static const Address *_tcpListener_OpsGetListenAddress(const ListenerOps *ops); - -static const char *_tcpListener_InterfaceName(const ListenerOps *ops); - -static EncapType _tcpListener_OpsGetEncapType(const ListenerOps *ops); - -static ListenerOps _tcpTemplate = { - .context = NULL, - .destroy = &_tcpListener_OpsDestroy, - .getListenerName = &_tcpListener_ListenerName, - .getInterfaceIndex = &_tcpListener_OpsGetInterfaceIndex, - .getListenAddress = &_tcpListener_OpsGetListenAddress, - .getEncapType = &_tcpListener_OpsGetEncapType, - .getInterfaceName = &_tcpListener_InterfaceName, - .getSocket = NULL}; - -// STREAM daemon listener callback -static void _tcpListener_Listen(int, struct sockaddr *, int socklen, - void *tcpVoid); - -ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder, char *listenerName, - struct sockaddr_in6 sin6, char *interfaceName) { - - _TcpListener *tcp = parcMemory_AllocateAndClear(sizeof(_TcpListener)); - parcAssertNotNull(tcp, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_TcpListener)); - - tcp->forwarder = forwarder; - tcp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName)); - tcp->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - tcp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName)); - - tcp->listener = dispatcher_CreateListener( - forwarder_GetDispatcher(forwarder), _tcpListener_Listen, (void *)tcp, -1, - (struct sockaddr *)&sin6, sizeof(sin6)); - - if (tcp->listener == NULL) { - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "dispatcher_CreateListener failed to create listener (%d) %s", - errno, strerror(errno)); - logger_Release(&tcp->logger); - parcMemory_Deallocate((void **)&tcp); - return NULL; - } - - tcp->localAddress = addressCreateFromInet6(&sin6); - tcp->id = forwarder_GetNextConnectionId(forwarder); - tcp->isLocalAddressLocal = - parcNetwork_IsSocketLocal((struct sockaddr *)&sin6); - - ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - - memcpy(ops, &_tcpTemplate, sizeof(ListenerOps)); - ops->context = tcp; - - if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - char *str = addressToString(tcp->localAddress); - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "TcpListener %p created for address %s (isLocal %d)", - (void *)tcp, str, tcp->isLocalAddressLocal); - parcMemory_Deallocate((void **)&str); - } - - return ops; -} - -ListenerOps *tcpListener_CreateInet(Forwarder *forwarder, char *listenerName, - struct sockaddr_in sin, char *interfaceName) { - _TcpListener *tcp = parcMemory_AllocateAndClear(sizeof(_TcpListener)); - parcAssertNotNull(tcp, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_TcpListener)); - - tcp->forwarder = forwarder; - tcp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName)); - tcp->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - tcp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName)); - - tcp->listener = dispatcher_CreateListener( - forwarder_GetDispatcher(forwarder), _tcpListener_Listen, (void *)tcp, -1, - (struct sockaddr *)&sin, sizeof(sin)); - - if (tcp->listener == NULL) { - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "dispatcher_CreateListener failed to create listener (%d) %s", - errno, strerror(errno)); - - logger_Release(&tcp->logger); - parcMemory_Deallocate((void **)&tcp); - return NULL; - } - - tcp->localAddress = addressCreateFromInet(&sin); - tcp->id = forwarder_GetNextConnectionId(forwarder); - tcp->isLocalAddressLocal = parcNetwork_IsSocketLocal((struct sockaddr *)&sin); - - ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - - memcpy(ops, &_tcpTemplate, sizeof(ListenerOps)); - ops->context = tcp; - - if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - char *str = addressToString(tcp->localAddress); - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "TcpListener %p created for address %s (isLocal %d)", - (void *)tcp, str, tcp->isLocalAddressLocal); - parcMemory_Deallocate((void **)&str); - } - - return ops; -} - -static void _tcpListener_Destroy(_TcpListener **listenerPtr) { - parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*listenerPtr, - "Parameter must derefernce to non-null pointer"); - _TcpListener *tcp = *listenerPtr; - - if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - char *str = addressToString(tcp->localAddress); - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "TcpListener %p destroyed", (void *)tcp); - parcMemory_Deallocate((void **)&str); - } - - parcMemory_Deallocate((void **)&tcp->listenerName); - parcMemory_Deallocate((void **)&tcp->interfaceName); - logger_Release(&tcp->logger); - dispatcher_DestroyListener(forwarder_GetDispatcher(tcp->forwarder), - &tcp->listener); - addressDestroy(&tcp->localAddress); - parcMemory_Deallocate((void **)&tcp); - *listenerPtr = NULL; -} - -// ================================================== - -static const char *_tcpListener_ListenerName(const ListenerOps *ops) { - _TcpListener *tcp = (_TcpListener *)ops->context; - return tcp->listenerName; -} - -static const char *_tcpListener_InterfaceName(const ListenerOps *ops) { - _TcpListener *tcp = (_TcpListener *)ops->context; - return tcp->interfaceName; -} - -static void _tcpListener_Listen(int fd, struct sockaddr *sa, int socklen, - void *tcpVoid) { - _TcpListener *tcp = (_TcpListener *)tcpVoid; - - Address *remote; - - switch (sa->sa_family) { - case AF_INET: - remote = addressCreateFromInet((struct sockaddr_in *)sa); - break; - - case AF_INET6: - remote = addressCreateFromInet6((struct sockaddr_in6 *)sa); - break; - - default: - parcTrapIllegalValue(sa, "Expected INET or INET6, got %d", sa->sa_family); - abort(); - } - - AddressPair *pair = addressPair_Create(tcp->localAddress, remote); - - IoOperations *ops = streamConnection_AcceptConnection( - tcp->forwarder, fd, pair, tcp->isLocalAddressLocal); - Connection *conn = connection_Create(ops); - - connectionTable_Add(forwarder_GetConnectionTable(tcp->forwarder), conn); - - if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "TcpListener %p listen started", (void *)tcp); - } - - addressDestroy(&remote); -} - -static void _tcpListener_OpsDestroy(ListenerOps **listenerOpsPtr) { - ListenerOps *ops = *listenerOpsPtr; - _TcpListener *tcp = (_TcpListener *)ops->context; - _tcpListener_Destroy(&tcp); - parcMemory_Deallocate((void **)&ops); - *listenerOpsPtr = NULL; -} - -static unsigned _tcpListener_OpsGetInterfaceIndex(const ListenerOps *ops) { - _TcpListener *tcp = (_TcpListener *)ops->context; - return tcp->id; -} - -static const Address *_tcpListener_OpsGetListenAddress(const ListenerOps *ops) { - _TcpListener *tcp = (_TcpListener *)ops->context; - return tcp->localAddress; -} - -static EncapType _tcpListener_OpsGetEncapType(const ListenerOps *ops) { - return ENCAP_TCP; -} diff --git a/hicn-light/src/hicn/io/tcpListener.h b/hicn-light/src/hicn/io/tcpListener.h deleted file mode 100644 index a841738e5..000000000 --- a/hicn-light/src/hicn/io/tcpListener.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 tcpListener.h - * @brief Listens for in coming TCP connections - * - * This is the "server socket" of hicn-light for TCP connections. The actual - * I/O is handled by {@link StreamConnection}. - * - */ - -#ifndef tcpListener_h -#define tcpListener_h - -#ifndef _WIN32 -#include <netinet/in.h> -#endif - -#include <hicn/core/forwarder.h> -#include <hicn/io/listener.h> -#include <stdlib.h> - -ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder, char *listenerName, - struct sockaddr_in6 sin6, char *interfaceName); -ListenerOps *tcpListener_CreateInet(Forwarder *forwarder, char *listenerName, - struct sockaddr_in sin, char *interfaceName); -#endif // tcpListener_h diff --git a/hicn-light/src/hicn/io/tcpTunnel.c b/hicn-light/src/hicn/io/tcpTunnel.c deleted file mode 100644 index 7a04a4222..000000000 --- a/hicn-light/src/hicn/io/tcpTunnel.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <parc/assert/parc_Assert.h> -#include <hicn/io/streamConnection.h> -#include <hicn/io/tcpListener.h> -#include <hicn/io/tcpTunnel.h> - -IoOperations *tcpTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress) { - IoOperations *ops = NULL; - - address_type localType = addressGetType(localAddress); - address_type remoteType = addressGetType(remoteAddress); - - if (localType == remoteType) { - AddressPair *pair = addressPair_Create(localAddress, remoteAddress); - bool isLocal = false; - - ops = streamConnection_OpenConnection(forwarder, pair, isLocal); - } - - return ops; -} diff --git a/hicn-light/src/hicn/io/tcpTunnel.h b/hicn-light/src/hicn/io/tcpTunnel.h deleted file mode 100644 index d1d2a8524..000000000 --- a/hicn-light/src/hicn/io/tcpTunnel.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 tcpTunnel.h - * @brief Establish a tunnel to a remote system - * - */ - -#ifndef tcpTunnel_h -#define tcpTunnel_h - -#include <hicn/core/forwarder.h> -#include <hicn/io/ioOperations.h> -#include <hicn/io/listener.h> -#include <hicn/utils/address.h> - -/** - */ -// IoOperations *tcpTunnel_CreateOnListener(Forwarder *forwarder, -// ListenerOps *localListener, -// const Address *remoteAddress); - -/** - */ -IoOperations *tcpTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress); - -#endif // tcpTunnel_h diff --git a/hicn-light/src/hicn/io/udp.c b/hicn-light/src/hicn/io/udp.c new file mode 100644 index 000000000..2baae1e5b --- /dev/null +++ b/hicn-light/src/hicn/io/udp.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2017-2020 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 udp.c + * #brief Implementation of the UDP face + * + * Old comment: + * - The Send() function may overflow the output buffer + * + */ + +/* This has to be included early as other modules are including socket.h */ + +#ifndef _WIN32 +#include <arpa/inet.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#ifndef _WIN32 +#include <sys/uio.h> +#include <unistd.h> +#endif +#include <sys/socket.h> + +#ifdef WITH_GSO +#include <netinet/if_ether.h> // ETH_DATA_LEN +#include <linux/ipv6.h> // struct ipv6hdr +#include <netinet/udp.h> // struct udphdr, SOL_UDP +//#include <linux/udp.h> // UDP_GRO +#define UDP_GRO 104 +#endif /* WITH_GSO */ + +#include <hicn/core/address_pair.h> +#include <hicn/core/connection.h> +#include <hicn/core/connection_vft.h> +#include <hicn/core/listener.h> +#include <hicn/core/listener_vft.h> +#include <hicn/base/loop.h> +#include <hicn/core/msgbuf.h> +#include <hicn/core/forwarder.h> +#include <hicn/core/messageHandler.h> +#include <hicn/core/messagePacketType.h> +#include <hicn/hicn-light/config.h> +#include <hicn/util/log.h> + +// Batching based on recvmmsg is also generic +// the difference is the handling of packet as in tcp we need to go through the +// ring buffer first to do the framing, while in UDP this is already done +// +// each module should have a function to process a packet, then call a callback +// in the forwarder again + +#define BATCH_SOCKET_BUFFER 512 * 1024 /* 256k */ + + +/****************************************************************************** + * Listener + ******************************************************************************/ + +typedef struct { + uint16_t port; // in address ? + + batch_buffer_t bb; +} listener_udp_data_t; + +#ifdef __ANDROID__ +extern int bindSocket(int sock, const char * interface_name); +#endif + +#include <arpa/inet.h> +char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen) +{ + switch(sa->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), + s, maxlen); + break; + + case AF_INET6: + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), + s, maxlen); + break; + + default: + strncpy(s, "Unknown AF", maxlen); + return NULL; + } + + return s; +} + +/* socket options */ +int +socket_set_options(int fd) +{ +#ifndef _WIN32 + // Set non-blocking flag + int flags = fcntl(fd, F_GETFL, NULL); + if (flags < 0) { + perror("fcntl"); + return -1; + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("fcntl"); + return -1; + } +#else + // Set non-blocking flag + int result = ioctlsocket(fd, FIONBIO, &(int){1}); + if (result != NO_ERROR) { + perror("ioctlsocket"); + return -1; + } +#endif + + // don't hang onto address after listener has closed + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) { + perror("setsockopt"); + return -1; + } + +#ifdef WITH_GSO +//● choosing gso_size +//○ ETH_DATA_LEN +//○ IP_MTU_DISCOVER +//● choosing number of segments +//○ fit in network layer +//○ <= UDP_MAX_SEGMENTS +//○ > gso_size +//● checksum offload +//○ csum_and_copy_from_user + int gso_size = ETH_DATA_LEN - sizeof(struct ipv6hdr) - sizeof(struct udphdr); + if (setsockopt(fd, SOL_UDP, UDP_SEGMENT, &gso_size, sizeof(gso_size)) < 0) { + perror("setsockopt"); + return -1; + } +#endif /* WITH_GSO */ + +#ifdef WITH_GRO + if (setsockopt(fd, IPPROTO_UDP, UDP_GRO, &(int){1}, sizeof(int)) < 0) { + perror("setsockopt"); + return -1; + } +#endif /* WITH_GRO */ + +#ifdef WITH_ZEROCOPY + if (setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &(int){1}, sizeof(int))) { + perror("setsockopt"); + return -1; + } +#endif /* WITH_ZEROCOPY */ + + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &(int){BATCH_SOCKET_BUFFER}, sizeof(int)) < 0) { + perror("setsockopt"); + return -1; + } + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &(int){BATCH_SOCKET_BUFFER}, sizeof(int)) < 0) { + perror("setsockopt"); + return -1; + } + return 0; +} + +#ifdef __linux__ +/* bind to device */ +int +socket_bind_to_device(int fd, const char * interface_name) +{ + if (strncmp("lo", interface_name, 2) == 0) + return 0; + + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface_name, + strlen(interface_name) + 1) < 0) { + perror("setsockopt"); + goto ERR_BIND_TO_DEVICE; + } + + return 0; + +ERR_BIND_TO_DEVICE: +#ifdef __ANDROID__ + if (bindSocket(fd, interface_name) < 0) + return -1; + return 0; +#else + return -1; +#endif /* __ANDROID__ */ +} +#endif /* __linux__ */ + +static +int +listener_udp_initialize(listener_t * listener) +{ + assert(listener); + + listener_udp_data_t * data = listener->data; + assert(data); + + init_batch_buffers(&data->bb); + + // XXX Socket creation should be a function per-se and not be called in + // initialize ! + listener->fd = listener_get_socket(listener, &listener->address, NULL, + listener->interface_name); + if (listener->fd < 0) { + ERROR("Error creating UDP socket: (%d) %s", errno, strerror(errno)); + return -1; + } + return 0; +} + +static +void +listener_udp_finalize(listener_t * listener) +{ + assert(listener); + assert(listener_get_type(listener) == FACE_TYPE_UDP); + + return; +} + +static +int +listener_udp_punt(const listener_t * listener, const char * prefix_s) +{ + return -1; +} + +static +int +listener_udp_get_socket(const listener_t * listener, const address_t * local, + const address_t * remote, const char * interface_name) +{ + int fd = socket(address_family(remote), SOCK_DGRAM, 0); + if (fd < 0) + goto ERR_SOCKET; + + if (socket_set_options(fd) < 0) { + goto ERR; + } + + if (bind(fd, address_sa(local), address_socklen(remote)) < 0) { + perror("bind"); + goto ERR; + } + +#ifdef __linux__ + if (socket_bind_to_device(fd, interface_name) < 0) { + goto ERR; + } +#endif /* __linux__ */ + + if (remote) { + if (connect(fd, address_sa(remote), address_socklen(remote)) < 0) { + perror("connect"); + goto ERR; + } + } + + return fd; + +ERR: +#ifndef _WIN32 + close(fd); +#else + closesocket(fd); +#endif +ERR_SOCKET: + return -1; +} + +static +void +listener_udp_read_callback(listener_t * listener, int fd, void * user_data) +{ + assert(listener); + assert(!user_data); + + listener_udp_data_t * data = listener->data; + assert(data); + + listener_batch_read_callback(listener->forwarder, listener, fd, &listener->address, &data->bb); +} + +DECLARE_LISTENER(udp); + +/****************************************************************************** + * Connection + ******************************************************************************/ + +typedef struct { + batch_buffer_t bb; + int queue_len; +} connection_udp_data_t; + +static +int +connection_udp_initialize(connection_t * connection) +{ + + assert(connection); + assert(connection->type == FACE_TYPE_UDP); + assert(interface_name); + assert(address_pair); + + connection_udp_data_t * data = connection->data; + assert(data); + + init_batch_buffers(&data->bb); + + data->queue_len = 0; + + return 0; +} + +static +void +connection_udp_finalize(connection_t * connection) +{ + ERROR("[connection_udp_finalize] Not implemented"); + +} + +/** + * @function metisUdpConnection_Send + * @abstract Non-destructive send of the message. + * @discussion + * sends a message to the peer. + * + * @param dummy is ignored. A udp connection has only one peer. + * @return <#return#> + */ +// XXX address not used anywhere +static +int +connection_udp_send(const connection_t * connection, msgbuf_t * msgbuf, bool queue) +{ + assert(connection); + /* msgbuf can be NULL */ + + connection_udp_data_t * data = connection->data; + assert(data); + + /* Flush if required or if queue is full */ + if ((!msgbuf) || (queue && (data->queue_len > MAX_MSG))) { + /* Flush operation */ +#ifdef WITH_ZEROCOPY + int flags = MSG_ZEROCOPY; +#else + int flags = 0; +#endif /* WITH_ZEROCOPY */ + int n = sendmmsg(connection->fd, data->bb.msghdr, data->queue_len, flags); + if (n == -1) { + perror("sendmmsg()"); + data->queue_len = 0; + return false; + } + + if (n < data->queue_len) { + // XXX TODO + printf("Unhandled Error after sending n=%d msgbufs\n", n); + } + + /* XXX check msglen */ + data->queue_len = 0; + return true; + } + + if (queue) { + struct iovec *iovec = &data->bb.iovecs[data->queue_len++]; + iovec->iov_base = msgbuf_get_packet(msgbuf); + iovec->iov_len = msgbuf_get_len(msgbuf); + + } else { + ssize_t writeLength = write(connection->fd, msgbuf_get_packet(msgbuf), + msgbuf_get_len(msgbuf)); + + if (writeLength < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return false; + } else { + // this print is for debugging + printf("Incorrect write length %zd, expected %u: (%d) %s\n", writeLength, + msgbuf_get_len(msgbuf), errno, strerror(errno)); + return false; + } + } + } + + return true; +} + +#if 0 +static +bool +connection_udp_sendv(const connection_t * connection, struct iovec * iov, + size_t size) +{ + + assert(connetion); + assert(iov); + + connection_udp_data_t * data = connection->data; + assert(data); + +#ifndef _WIN32 + // Perform connect before to establish association between this peer and + // the remote peer. This is required to use writev. + // Connection association can be changed at any time. + + if (writev(connection->fd, iov, (int)size) < 0) + return false; +#else + WSABUF *buf = (WSABUF *) malloc(size * sizeof(WSABUF)); + + DWORD bytes_sent = 0; + + for (int i = 0; i < size; i++) { + buf[i].buf = iov[i].iov_base; + buf[i].len = (ULONG)iov[i].iov_len; + } + + int rc = WSASendTo(udp->fd, buf, size, &bytes_sent, 0, + (SOCKADDR *)address_sa(address_pair_remote(&udp->pair)), + address_socklen(address_pair_remote(&udp->pair)), NULL, NULL); + free(dataBuf); + if (rc == SOCKET_ERROR) + return false; +#endif + + return true; +} +#endif + +static +int +connection_udp_send_packet(const connection_t * connection, const uint8_t * packet, size_t size) +{ + assert(ops); + assert(packet); + + if(connection_is_local(connection)) + return -1; + + ssize_t n = sendto(connection->fd, packet, size, 0, + address_sa(address_pair_get_remote(&connection->pair)), + address_socklen(address_pair_get_remote(&connection->pair))); + if (n < 0) + return -1; + return 0; +} + +static +void +connection_udp_read_callback(connection_t * connection, int fd, void * user_data) +{ + assert(connection); + assert(!user_data); + + connection_udp_data_t * data = connection->data; + assert(data); + listener_batch_read_callback(connection->forwarder, NULL, fd, address_pair_get_local(&connection->pair), &data->bb); +} + +DECLARE_CONNECTION(udp); diff --git a/hicn-light/src/hicn/io/udpConnection.c b/hicn-light/src/hicn/io/udpConnection.c deleted file mode 100644 index cd3ccc84a..000000000 --- a/hicn-light/src/hicn/io/udpConnection.c +++ /dev/null @@ -1,495 +0,0 @@ -/* - * 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. - */ - -/** - * Embodies the reader/writer for a UDP connection - * - * NB The Send() function may overflow the output buffer - * - */ - -#ifndef _WIN32 -#include <sys/uio.h> -#endif -#include <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdio.h> -#include <string.h> - -#include <hicn/core/messageHandler.h> -#include <hicn/io/udpConnection.h> - -#include <parc/algol/parc_Hash.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/core/connection.h> -#include <hicn/core/forwarder.h> -#include <hicn/core/message.h> - -typedef struct udp_state { - Forwarder *forwarder; - char * interfaceName; - Logger *logger; - - // the udp listener socket we receive packets on - int udpListenerSocket; - - AddressPair *addressPair; - - // We need to access this all the time, so grab it out - // of the addressPair; - struct sockaddr *peerAddress; - socklen_t peerAddressLength; - - bool isLocal; - bool isUp; - unsigned id; - - unsigned delay; - - /* This information would better be stored in the connection data structure - * but it is currently not reachable from within the implementation. */ - connection_state_t state; - connection_state_t admin_state; -#ifdef WITH_POLICY - uint32_t priority; -#endif /* WITH_POLICY */ -} _UdpState; - -// Prototypes -static bool _send(IoOperations *ops, const Address *nexthop, Message *message); -static bool _sendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size); -static const Address *_getRemoteAddress(const IoOperations *ops); -static const AddressPair *_getAddressPair(const IoOperations *ops); -static unsigned _getConnectionId(const IoOperations *ops); -static bool _isUp(const IoOperations *ops); -static bool _isLocal(const IoOperations *ops); -static void _destroy(IoOperations **opsPtr); -static list_connections_type _getConnectionType(const IoOperations *ops); -static void _sendProbe(IoOperations *ops, uint8_t *message); -static connection_state_t _getState(const IoOperations *ops); -static void _setState(IoOperations *ops, connection_state_t state); -static connection_state_t _getAdminState(const IoOperations *ops); -static void _setAdminState(IoOperations *ops, connection_state_t admin_state); -#ifdef WITH_POLICY -static uint32_t _getPriority(const IoOperations *ops); -static void _setPriority(IoOperations *ops, uint32_t priority); -#endif /* WITH_POLICY */ -static const char * _getInterfaceName(const IoOperations *ops); - -/* - * This assigns a unique pointer to the void * which we use - * as a GUID for this class. - */ -static const void *_IoOperationsGuid = __FILE__; - -/* - * Return our GUID - */ -static const void *_streamConnection_Class(const IoOperations *ops) { - return _IoOperationsGuid; -} - -static IoOperations _template = { - .closure = NULL, - .send = &_send, - .sendIOVBuffer = &_sendIOVBuffer, - .getRemoteAddress = &_getRemoteAddress, - .getAddressPair = &_getAddressPair, - .getConnectionId = &_getConnectionId, - .isUp = &_isUp, - .isLocal = &_isLocal, - .destroy = &_destroy, - .class = &_streamConnection_Class, - .getConnectionType = &_getConnectionType, - .sendProbe = &_sendProbe, - .getState = &_getState, - .setState = &_setState, - .getAdminState = &_getAdminState, - .setAdminState = &_setAdminState, -#ifdef WITH_POLICY - .getPriority = &_getPriority, - .setPriority = &_setPriority, -#endif /* WITH_POLICY */ - .getInterfaceName = &_getInterfaceName, -}; - -// ================================================================= - -static void _setConnectionState(_UdpState *Udp, bool isUp); -static bool _saveSockaddr(_UdpState *udpConnState, const AddressPair *pair); - -IoOperations *udpConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd, - const AddressPair *pair, bool isLocal) { - IoOperations *io_ops = NULL; - - _UdpState *udpConnState = parcMemory_AllocateAndClear(sizeof(_UdpState)); - parcAssertNotNull(udpConnState, - "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(_UdpState)); - - udpConnState->forwarder = forwarder; - udpConnState->interfaceName = strdup(interfaceName); - udpConnState->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - - bool saved = _saveSockaddr(udpConnState, pair); - if (saved) { - udpConnState->udpListenerSocket = fd; - udpConnState->id = forwarder_GetNextConnectionId(forwarder); - udpConnState->addressPair = addressPair_Acquire(pair); - udpConnState->isLocal = isLocal; - - // allocate a connection - io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations)); - parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(IoOperations)); - memcpy(io_ops, &_template, sizeof(IoOperations)); - io_ops->closure = udpConnState; - - _setConnectionState(udpConnState, true); - -#ifdef WITH_POLICY - udpConnState->priority = 0; -#endif /* WITH_POLICY */ - - if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - char *str = addressPair_ToString(udpConnState->addressPair); - logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Info, - __func__, - "UdpConnection %p created for address %s (isLocal %d)", - (void *)udpConnState, str, udpConnState->isLocal); - free(str); - } - - messenger_Send( - forwarder_GetMessenger(forwarder), - missive_Create(MissiveType_ConnectionCreate, udpConnState->id)); - messenger_Send(forwarder_GetMessenger(forwarder), - missive_Create(MissiveType_ConnectionUp, udpConnState->id)); - } else { - // _saveSockaddr will already log an error, no need for extra log message - // here - logger_Release(&udpConnState->logger); - - free(udpConnState->interfaceName); - parcMemory_Deallocate((void **)&udpConnState); - } - - return io_ops; -} - -// ================================================================= -// I/O Operations implementation - -static void _destroy(IoOperations **opsPtr) { - parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer"); - parcAssertNotNull(*opsPtr, - "Parameter opsPtr must dereference to non-null pointer"); - - IoOperations *ops = *opsPtr; - parcAssertNotNull(ioOperations_GetClosure(ops), - "ops->context must not be null"); - - _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops); - addressPair_Release(&udpConnState->addressPair); - parcMemory_Deallocate((void **)&(udpConnState->peerAddress)); - - messenger_Send( - forwarder_GetMessenger(udpConnState->forwarder), - missive_Create(MissiveType_ConnectionDestroyed, udpConnState->id)); - - if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO, - PARCLogLevel_Info)) { - logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Info, - __func__, "UdpConnection %p destroyed", (void *)udpConnState); - } - - // do not close udp->udpListenerSocket, the listener will close - // that when its done - - logger_Release(&udpConnState->logger); - free(udpConnState->interfaceName); - parcMemory_Deallocate((void **)&udpConnState); - parcMemory_Deallocate((void **)&ops); - - *opsPtr = NULL; -} - -static bool _isUp(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->isUp; -} - -static bool _isLocal(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->isLocal; -} - -static const Address *_getRemoteAddress(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return addressPair_GetRemote(udpConnState->addressPair); -} - -static const AddressPair *_getAddressPair(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->addressPair; -} - -static unsigned _getConnectionId(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->id; -} - -/** - * @function metisUdpConnection_Send - * @abstract Non-destructive send of the message. - * @discussion - * sends a message to the peer. - * - * @param dummy is ignored. A udp connection has only one peer. - * @return <#return#> - */ -static bool _send(IoOperations *ops, const Address *dummy, Message *message) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops); - - // NAT for HICN - // in this particular connection we don't need natting beacause we send the - // packet to the next hop using upd connection - - ssize_t writeLength = - sendto(udpConnState->udpListenerSocket, message_FixedHeader(message), - (int)message_Length(message), 0, udpConnState->peerAddress, - udpConnState->peerAddressLength); - - if (writeLength < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - return false; - } else { - // this print is for debugging - printf("Incorrect write length %zd, expected %zd: (%d) %s\n", writeLength, - message_Length(message), errno, strerror(errno)); - return false; - } - } - - return true; -} - -static bool _sendIOVBuffer(IoOperations *ops, struct iovec *message, - size_t size) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops); - -#ifndef _WIN32 - // Perform connect before to establish association between this peer and - // the remote peer. This is required to use writev. - // Connection association can be changed at any time. - connect(udpConnState->udpListenerSocket, - udpConnState->peerAddress, - udpConnState->peerAddressLength); - - ssize_t writeLength = writev(udpConnState->udpListenerSocket, message, (int)size); - - struct sockaddr any_address = {0}; - any_address.sa_family = AF_UNSPEC; - connect(udpConnState->udpListenerSocket, - &any_address, (socklen_t)sizeof(any_address)); - - if (writeLength < 0) { - return false; - } -#else - - WSABUF *dataBuf = (WSABUF *) malloc(size * sizeof (dataBuf)); - DWORD BytesSent = 0; - - for (int i = 0; i < size; i++) { - dataBuf[i].buf = message[i].iov_base; - dataBuf[i].len = (ULONG)message[i].iov_len; - } - - int rc = WSASendTo(udpConnState->udpListenerSocket, dataBuf, size, - &BytesSent, 0, (SOCKADDR *)udpConnState->peerAddress, - udpConnState->peerAddressLength, NULL, NULL); - free(dataBuf); - if (rc == SOCKET_ERROR) { - return false; - } -#endif - return true; -} - -static list_connections_type _getConnectionType(const IoOperations *ops) { - return CONN_UDP; -} - -static void _sendProbe(IoOperations *ops, uint8_t *message) { - parcAssertNotNull(ops, "Parameter ops must be non-null"); - parcAssertNotNull(message, "Parameter message must be non-null"); - _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops); - - if(udpConnState->isLocal) - return; - - ssize_t writeLength = - sendto(udpConnState->udpListenerSocket, message, - messageHandler_GetTotalPacketLength(message), 0, udpConnState->peerAddress, - udpConnState->peerAddressLength); - - if (writeLength < 0) { - return; - } -} - -// ================================================================= -// Internal API - -static bool _saveSockaddr(_UdpState *udpConnState, const AddressPair *pair) { - bool success = false; - const Address *remoteAddress = addressPair_GetRemote(pair); - - switch (addressGetType(remoteAddress)) { - case ADDR_INET: { - size_t bytes = sizeof(struct sockaddr_in); - udpConnState->peerAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(udpConnState->peerAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet(remoteAddress, - (struct sockaddr_in *)udpConnState->peerAddress); - udpConnState->peerAddressLength = (socklen_t)bytes; - - success = true; - break; - } - - case ADDR_INET6: { - size_t bytes = sizeof(struct sockaddr_in6); - udpConnState->peerAddress = parcMemory_Allocate(bytes); - parcAssertNotNull(udpConnState->peerAddress, - "parcMemory_Allocate(%zu) returned NULL", bytes); - - addressGetInet6(remoteAddress, - (struct sockaddr_in6 *)udpConnState->peerAddress); - udpConnState->peerAddressLength = (socklen_t)bytes; - - success = true; - break; - } - - default: - if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO, - PARCLogLevel_Error)) { - char *str = addressToString(remoteAddress); - logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Error, - __func__, "Remote address is not INET or INET6: %s", str); - parcMemory_Deallocate((void **)&str); - } - break; - } - return success; -} - -static void _setConnectionState(_UdpState *udpConnState, bool isUp) { - parcAssertNotNull(udpConnState, "Parameter Udp must be non-null"); - - Messenger *messenger = forwarder_GetMessenger(udpConnState->forwarder); - - bool oldStateIsUp = udpConnState->isUp; - udpConnState->isUp = isUp; - - if (oldStateIsUp && !isUp) { - // bring connection DOWN - Missive *missive = - missive_Create(MissiveType_ConnectionDown, udpConnState->id); - messenger_Send(messenger, missive); - return; - } - - if (!oldStateIsUp && isUp) { - // bring connection UP - Missive *missive = - missive_Create(MissiveType_ConnectionUp, udpConnState->id); - messenger_Send(messenger, missive); - return; - } -} - -static connection_state_t _getState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->state; -} - -static void _setState(IoOperations *ops, connection_state_t state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _UdpState *udpConnState = - (_UdpState *)ioOperations_GetClosure(ops); - udpConnState->state = state; -} - -static connection_state_t _getAdminState(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->admin_state; -} - -static void _setAdminState(IoOperations *ops, connection_state_t admin_state) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _UdpState *udpConnState = - (_UdpState *)ioOperations_GetClosure(ops); - udpConnState->admin_state = admin_state; -} - -#ifdef WITH_POLICY -static uint32_t _getPriority(const IoOperations *ops) { - parcAssertNotNull(ops, "Parameter must be non-null"); - const _UdpState *udpConnState = - (const _UdpState *)ioOperations_GetClosure(ops); - return udpConnState->priority; -} - -static void _setPriority(IoOperations *ops, uint32_t priority) { - parcAssertNotNull(ops, "Parameter must be non-null"); - _UdpState *udpConnState = - (_UdpState *)ioOperations_GetClosure(ops); - udpConnState->priority = priority; -} -#endif /* WITH_POLICY */ - -static const char * _getInterfaceName(const IoOperations *ops) -{ - parcAssertNotNull(ops, "Parameter must be non-null"); - _UdpState *udpConnState = - (_UdpState *)ioOperations_GetClosure(ops); - return udpConnState->interfaceName; -} diff --git a/hicn-light/src/hicn/io/udpConnection.h b/hicn-light/src/hicn/io/udpConnection.h deleted file mode 100644 index 9fbc5348b..000000000 --- a/hicn-light/src/hicn/io/udpConnection.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 udpConnection.h - * @brief Represents a UDP connection (socket) for the connection table - * - * <#Detailed Description#> - * - */ - -#ifndef udpConnection_h -#define udpConnection_h - -#include <hicn/core/forwarder.h> -#include <hicn/io/addressPair.h> -#include <hicn/io/ioOperations.h> -#include <hicn/utils/address.h> - -/** - * Creates a UDP connection that can send to the remote address - * - * The address pair must both be same type (i.e. INET or INET6). - * - * @param [in] metis An allocated MetisForwarder (saves reference) - * @param [in] fd The socket to use - * @param [in] pair An allocated address pair for the connection (saves - * reference) - * @param [in] isLocal determines if the remote address is on the current system - * - * @retval non-null An allocated Io operations - * @retval null An error - * - * Example: - * @code - * <#example#> - * @endcode - */ -IoOperations *udpConnection_Create(Forwarder *forwarder, const char * interfaceName, int fd, - const AddressPair *pair, bool isLocal); -#endif // udpConnection_h diff --git a/hicn-light/src/hicn/io/udpListener.c b/hicn-light/src/hicn/io/udpListener.c deleted file mode 100644 index 21b4f6190..000000000 --- a/hicn-light/src/hicn/io/udpListener.c +++ /dev/null @@ -1,649 +0,0 @@ -/* - * 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 <arpa/inet.h> -#include <unistd.h> -#endif -#include <errno.h> -#include <fcntl.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <hicn/core/messageHandler.h> - -#include <hicn/io/udpConnection.h> -#include <hicn/io/udpListener.h> - -#include <parc/algol/parc_Network.h> -#include <parc/algol/parc_Memory.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/core/connection.h> -#include <hicn/core/forwarder.h> -#include <hicn/core/messagePacketType.h> - -#define IPv4 4 -#define IPv6 6 - -struct udp_listener { - char *listenerName; - Forwarder *forwarder; - Logger *logger; - - PARCEvent *udp_event; - SocketType udp_socket; - uint16_t port; - - unsigned id; - char *interfaceName; - Address *localAddress; -}; - -static void _destroy(ListenerOps **listenerOpsPtr); -static const char *_getListenerName(const ListenerOps *ops); -static unsigned _getInterfaceIndex(const ListenerOps *ops); -static const Address *_getListenAddress(const ListenerOps *ops); -static EncapType _getEncapType(const ListenerOps *ops); -static const char *_getInterfaceName(const ListenerOps *ops); -static int _getSocket(const ListenerOps *ops); -static unsigned _createNewConnection(ListenerOps *listener, int fd, const AddressPair *pair); -static const Connection * _lookupConnection(ListenerOps * listener, const AddressPair *pair); - -static ListenerOps udpTemplate = { - .context = NULL, - .destroy = &_destroy, - .getInterfaceIndex = &_getInterfaceIndex, - .getListenAddress = &_getListenAddress, - .getEncapType = &_getEncapType, - .getSocket = &_getSocket, - .getListenerName = &_getListenerName, - .createConnection = &_createNewConnection, - .lookupConnection = &_lookupConnection, - .getInterfaceName = &_getInterfaceName, -}; - - -static void _readcb(int fd, PARCEventType what, void * listener_void); - -#ifdef __ANDROID__ -extern int bindSocket(int sock, const char* ifname); -#endif - -ListenerOps *udpListener_CreateInet6(Forwarder *forwarder, char *listenerName, - struct sockaddr_in6 sin6, const char *interfaceName) { - ListenerOps *ops = NULL; - - UdpListener *udp = parcMemory_AllocateAndClear(sizeof(UdpListener)); - parcAssertNotNull(udp, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(UdpListener)); - udp->forwarder = forwarder; - udp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName)); - udp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName)); - udp->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - udp->localAddress = addressCreateFromInet6(&sin6); - udp->id = forwarder_GetNextConnectionId(forwarder); - - udp->udp_socket = (SocketType)socket(AF_INET6, SOCK_DGRAM, 0); - parcAssertFalse(udp->udp_socket < 0, "Error opening UDP socket: (%d) %s", - errno, strerror(errno)); - - int failure = 0; -#ifndef _WIN32 - // Set non-blocking flag - int flags = fcntl(udp->udp_socket, F_GETFL, NULL); - parcAssertTrue(flags != -1, - "fcntl failed to obtain file descriptor flags (%d)", errno); - failure = fcntl(udp->udp_socket, F_SETFL, flags | O_NONBLOCK); - parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)", - errno); -#else - // Set non-blocking flag - u_long mode = 1; - int result = ioctlsocket(udp->udp_socket, FIONBIO, &mode); - if (result != NO_ERROR) { - parcAssertTrue(result != NO_ERROR, - "ioctlsocket failed to set file descriptor"); - } -#endif - - int one = 1; - // don't hang onto address after listener has closed - failure = setsockopt(udp->udp_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&one, - (socklen_t)sizeof(one)); - parcAssertFalse(failure, "failed to set REUSEADDR on socket(%d)", errno); - - failure = bind(udp->udp_socket, (struct sockaddr *)&sin6, sizeof(sin6)); - - if (failure == 0) { -#ifdef __linux__ - if (strncmp("lo", interfaceName, 2) != 0) { - int ret = setsockopt(udp->udp_socket, SOL_SOCKET, SO_BINDTODEVICE, - interfaceName, strlen(interfaceName) + 1); - if (ret < 0) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "setsockopt(%d, SO_BINDTODEVICE, %s) failed (%d) %s", - udp->udp_socket, interfaceName, errno, strerror(errno)); -#ifdef __ANDROID__ - ret = bindSocket(udp->udp_socket, interfaceName); - if (ret < 0) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "bindSocket(%d, %s) failed", udp->udp_socket, interfaceName); - close(udp->udp_socket); - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - return NULL; - } else { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "bindSocket(%d, %s) success", udp->udp_socket, interfaceName); - } -#else - close(udp->udp_socket); - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - return NULL; -#endif - } - } -#endif - - ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - memcpy(ops, &udpTemplate, sizeof(ListenerOps)); - ops->context = udp; - - udp->udp_event = - dispatcher_CreateNetworkEvent(forwarder_GetDispatcher(forwarder), true, - _readcb, (void*)ops, udp->udp_socket); - dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder), - udp->udp_event); - - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - char *str = addressToString(udp->localAddress); - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "UdpListener %p created for address %s", (void *)udp, str); - parcMemory_Deallocate((void **)&str); - } - } else { - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Error)) { - int myerrno = errno; - char *str = addressToString(udp->localAddress); - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Error binding UDP socket to address %s: (%d) %s", str, - myerrno, strerror(myerrno)); - parcMemory_Deallocate((void **)&str); - } - parcMemory_Deallocate((void **)&udp->listenerName); - parcMemory_Deallocate((void **)&udp->interfaceName); -#ifndef _WIN32 - close(udp->udp_socket); -#else - closesocket(udp->udp_socket); -#endif - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - } - - return ops; -} - -ListenerOps *udpListener_CreateInet(Forwarder *forwarder, char *listenerName, - struct sockaddr_in sin, const char *interfaceName) { - ListenerOps *ops = NULL; - - UdpListener *udp = parcMemory_AllocateAndClear(sizeof(UdpListener)); - parcAssertNotNull(udp, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(UdpListener)); - udp->forwarder = forwarder; - udp->listenerName = parcMemory_StringDuplicate(listenerName, strlen(listenerName)); - udp->interfaceName = parcMemory_StringDuplicate(interfaceName, strlen(interfaceName)); - udp->logger = logger_Acquire(forwarder_GetLogger(forwarder)); - udp->localAddress = addressCreateFromInet(&sin); - udp->id = forwarder_GetNextConnectionId(forwarder); - - udp->udp_socket = (SocketType)socket(AF_INET, SOCK_DGRAM, 0); - parcAssertFalse(udp->udp_socket < 0, "Error opening UDP socket: (%d) %s", - errno, strerror(errno)); - - int failure = 0; -#ifndef _WIN32 - // Set non-blocking flag - int flags = fcntl(udp->udp_socket, F_GETFL, NULL); - parcAssertTrue(flags != -1, - "fcntl failed to obtain file descriptor flags (%d)", errno); - failure = fcntl(udp->udp_socket, F_SETFL, flags | O_NONBLOCK); - parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)", - errno); -#else - u_long mode = 1; - int result = ioctlsocket(udp->udp_socket, FIONBIO, &mode); - if (result != NO_ERROR) { - parcAssertTrue(result != NO_ERROR, - "ioctlsocket failed to set file descriptor"); - } -#endif - - int one = 1; - // don't hang onto address after listener has closed - failure = setsockopt(udp->udp_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&one, - (socklen_t)sizeof(one)); - parcAssertFalse(failure, "failed to set REUSEADDR on socket(%d)", errno); - - failure = bind(udp->udp_socket, (struct sockaddr *)&sin, sizeof(sin)); - if (failure == 0) { -#ifdef __linux__ - if (strncmp("lo", interfaceName, 2) != 0) { - int ret = setsockopt(udp->udp_socket, SOL_SOCKET, SO_BINDTODEVICE, - interfaceName, strlen(interfaceName) + 1); - if (ret < 0) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "setsockopt(%d, SO_BINDTODEVICE, %s) failed (%d) %s", - udp->udp_socket, interfaceName, errno, strerror(errno)); -#ifdef __ANDROID__ - ret = bindSocket(udp->udp_socket, interfaceName); - if (ret < 0) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "bindSocket(%d, %s) failed", udp->udp_socket, interfaceName); - close(udp->udp_socket); - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - return NULL; - } else { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "bindSocket(%d, %s) success", udp->udp_socket, interfaceName); - } -#else - close(udp->udp_socket); - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - return NULL; -#endif - } - } -#endif - ops = parcMemory_AllocateAndClear(sizeof(ListenerOps)); - parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", - sizeof(ListenerOps)); - memcpy(ops, &udpTemplate, sizeof(ListenerOps)); - ops->context = udp; - - udp->udp_event = - dispatcher_CreateNetworkEvent(forwarder_GetDispatcher(forwarder), true, - _readcb, (void *)ops, udp->udp_socket); - dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder), - udp->udp_event); - - - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - char *str = addressToString(udp->localAddress); - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "UdpListener %p created for address %s", (void *)udp, str); - parcMemory_Deallocate((void **)&str); - } - } else { - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Error)) { - int myerrno = errno; - char *str = addressToString(udp->localAddress); - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Error binding UDP socket to address %s: (%d) %s", str, - myerrno, strerror(myerrno)); - parcMemory_Deallocate((void **)&str); - } - parcMemory_Deallocate((void **)&udp->listenerName); - parcMemory_Deallocate((void **)&udp->interfaceName); -#ifndef _WIN32 - close(udp->udp_socket); -#else - closesocket(udp->udp_socket); -#endif - addressDestroy(&udp->localAddress); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - } - - return ops; -} - -static void udpListener_Destroy(UdpListener **listenerPtr) { - parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer"); - parcAssertNotNull(*listenerPtr, - "Parameter must derefernce to non-null pointer"); - - UdpListener *udp = *listenerPtr; - - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "UdpListener %p destroyed", (void *)udp); - } - - parcMemory_Deallocate((void **)&udp->listenerName); - parcMemory_Deallocate((void **)&udp->interfaceName); -#ifndef _WIN32 - close(udp->udp_socket); -#else - closesocket(udp->udp_socket); -#endif - - addressDestroy(&udp->localAddress); - dispatcher_DestroyNetworkEvent(forwarder_GetDispatcher(udp->forwarder), - &udp->udp_event); - logger_Release(&udp->logger); - parcMemory_Deallocate((void **)&udp); - *listenerPtr = NULL; -} - -static const char *_getListenerName(const ListenerOps *ops) { - UdpListener *udp = (UdpListener *)ops->context; - return udp->listenerName; -} - -static const char *_getInterfaceName(const ListenerOps *ops) { - UdpListener *udp = (UdpListener *)ops->context; - return udp->interfaceName; -} - -static void _destroy(ListenerOps **listenerOpsPtr) { - ListenerOps *ops = *listenerOpsPtr; - UdpListener *udp = (UdpListener *)ops->context; - udpListener_Destroy(&udp); - parcMemory_Deallocate((void **)&ops); - *listenerOpsPtr = NULL; -} - -static unsigned _getInterfaceIndex(const ListenerOps *ops) { - UdpListener *udp = (UdpListener *)ops->context; - return udp->id; -} - -static const Address *_getListenAddress(const ListenerOps *ops) { - UdpListener *udp = (UdpListener *)ops->context; - return udp->localAddress; -} - -static EncapType _getEncapType(const ListenerOps *ops) { return ENCAP_UDP; } - -static int _getSocket(const ListenerOps *ops) { - UdpListener *udp = (UdpListener *)ops->context; - return (int)udp->udp_socket; -} - -// ===================================================================== - -/** - * @function _constructAddressPair - * @abstract Creates the address pair that uniquely identifies the connection - * @discussion - * The peerIpAddress must be of AF_INET or AF_INET6 family. - * - * @param <#param1#> - * @return Allocated MetisAddressPair, must be destroyed - */ -static AddressPair *_constructAddressPair(UdpListener *udp, - struct sockaddr *peerIpAddress, - socklen_t peerIpAddressLength) { - Address *remoteAddress; - - switch (peerIpAddress->sa_family) { - case AF_INET: - remoteAddress = - addressCreateFromInet((struct sockaddr_in *)peerIpAddress); - break; - - case AF_INET6: - remoteAddress = - addressCreateFromInet6((struct sockaddr_in6 *)peerIpAddress); - break; - - default: - parcTrapIllegalValue(peerIpAddress, - "Peer address unrecognized family for IP: %d", - peerIpAddress->sa_family); - } - - AddressPair *pair = addressPair_Create(udp->localAddress, remoteAddress); - addressDestroy(&remoteAddress); - - return pair; -} - -static const Connection * _lookupConnection(ListenerOps * listener, - const AddressPair *pair) { - UdpListener * udp = (UdpListener *)listener->context; - ConnectionTable *connTable = forwarder_GetConnectionTable(udp->forwarder); - return connectionTable_FindByAddressPair(connTable, pair); - -} - -/** - * @function _createNewConnection - * @abstract Creates a new Metis connection for the peer - * @discussion - * PRECONDITION: you know there's not an existing connection with the address - * pair - * - * Creates a new connection and adds it to the connection table. - * - * @param <#param1#> - * @return The connection id for the new connection - */ - -static unsigned _createNewConnection(ListenerOps * listener, int fd, - const AddressPair *pair) { - UdpListener * udp = (UdpListener *)listener->context; - - //check it the connection is local - bool isLocal = false; - const Address *localAddress = addressPair_GetLocal(pair); - if(addressGetType(localAddress) == ADDR_INET){ - struct sockaddr_in tmpAddr; - addressGetInet(localAddress, &tmpAddr); - if(parcNetwork_IsSocketLocal((struct sockaddr *)&tmpAddr)) - isLocal = true; - }else{ - struct sockaddr_in6 tmpAddr6; - addressGetInet6(localAddress, &tmpAddr6); - if(parcNetwork_IsSocketLocal((struct sockaddr *)&tmpAddr6)) - isLocal = true; - } - - // metisUdpConnection_Create takes ownership of the pair - IoOperations *ops = udpConnection_Create(udp->forwarder, udp->interfaceName, fd, pair, isLocal); - Connection *conn = connection_Create(ops); - // connection_AllowWldrAutoStart(conn); - - connectionTable_Add(forwarder_GetConnectionTable(udp->forwarder), conn); - unsigned connid = ioOperations_GetConnectionId(ops); - - return connid; -} - -static void _handleWldrNotification(UdpListener *udp, unsigned connId, - uint8_t *msgBuffer) { - const Connection *conn = connectionTable_FindById( - forwarder_GetConnectionTable(udp->forwarder), connId); - if (conn == NULL) { - return; - } - - Message *message = message_CreateFromByteArray( - connId, msgBuffer, MessagePacketType_WldrNotification, - forwarder_GetTicks(udp->forwarder), forwarder_GetLogger(udp->forwarder)); - - connection_HandleWldrNotification((Connection *)conn, message); - - message_Release(&message); -} - -static Message *_readMessage(ListenerOps * listener, int fd, - AddressPair *pair, uint8_t * packet, bool * processed) { - UdpListener * udp = (UdpListener *)listener->context; - - Message *message = NULL; - - unsigned connid; - bool foundConnection; - - const Connection *conn = _lookupConnection(listener, pair); - if (conn) { - connid = connection_GetConnectionId(conn); - foundConnection = true; - } else { - connid = 0; - foundConnection = false; - } - - if (messageHandler_IsTCP(packet)) { - *processed = true; - MessagePacketType pktType; - - if (messageHandler_IsData(packet)) { - pktType = MessagePacketType_ContentObject; - if (!foundConnection) { - parcMemory_Deallocate((void **)&packet); - return message; - } - } else if (messageHandler_IsInterest(packet)) { - pktType = MessagePacketType_Interest; - if (!foundConnection) { - connid = _createNewConnection(listener, fd, pair); - } - } else { - printf("Got a packet that is not a data nor an interest, drop it!\n"); - parcMemory_Deallocate((void **)&packet); - return message; - } - - message = message_CreateFromByteArray( - connid, packet, pktType, forwarder_GetTicks(udp->forwarder), - forwarder_GetLogger(udp->forwarder)); - - if (message == NULL) { - parcMemory_Deallocate((void **)&packet); - } - } else if (messageHandler_IsWldrNotification(packet)) { - *processed = true; - _handleWldrNotification(udp, connid, packet); - } else { - - *processed = messageHandler_handleHooks(udp->forwarder, packet, listener, fd, pair); - } - - return message; -} - -static void _readCommand(ListenerOps * listener, int fd, - AddressPair *pair, uint8_t * command) { - UdpListener * udp = (UdpListener *)listener->context; - - if (*command != REQUEST_LIGHT){ - printf("the message received is not a command, drop\n"); - return; - } - - command_id id = *(command + 1); - - if (id >= LAST_COMMAND_VALUE){ - printf("the message received is not a valid command, drop\n"); - return; - } - - unsigned connid; - - const Connection *conn = _lookupConnection(listener, pair); - if (conn) { - connid = connection_GetConnectionId(conn); - } else { - connid = _createNewConnection(listener, fd, pair); - } - - struct iovec *request; - if (!(request = (struct iovec *) parcMemory_AllocateAndClear( - sizeof(struct iovec) * 2))) { - return; - } - - request[0].iov_base = command; - request[0].iov_len = sizeof(header_control_message); - request[1].iov_base = command + sizeof(header_control_message); - request[1].iov_len = payloadLengthDaemon(id); - - forwarder_ReceiveCommand(udp->forwarder, id, request, connid); - parcMemory_Deallocate((void **) &command); - parcMemory_Deallocate((void **) &request); -} - - -static bool _receivePacket(ListenerOps * listener, int fd, - AddressPair *pair, - uint8_t * packet) { - UdpListener * udp = (UdpListener *)listener->context; - bool processed = false; - Message *message = _readMessage(listener, fd, pair, - packet, &processed); - if (message) { - forwarder_Receive(udp->forwarder, message); - } - return processed; -} - -static void _readcb(int fd, PARCEventType what, void * listener_void) { - ListenerOps * listener = (ListenerOps *)listener_void; - UdpListener * udp = (UdpListener *)listener->context; - - if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) { - logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__, - "%s socket %d what %s%s%s%s data %p", __func__, fd, - (what & PARCEventType_Timeout) ? " timeout" : "", - (what & PARCEventType_Read) ? " read" : "", - (what & PARCEventType_Write) ? " write" : "", - (what & PARCEventType_Signal) ? " signal" : "", udp); - } - - if (what & PARCEventType_Read) { - struct sockaddr_storage peerIpAddress; - socklen_t peerIpAddressLength = sizeof(peerIpAddress); - - //packet it deallocated by _receivePacket or _readCommand - uint8_t * packet = parcMemory_AllocateAndClear(1500); //max MTU - ssize_t readLength = recvfrom(fd, packet, 1500, 0, - (struct sockaddr *)&peerIpAddress, &peerIpAddressLength); - -#ifdef __APPLE__ - peerIpAddress.ss_len = 0x00; -#endif - - if(readLength < 0) { - printf("unable to read the message\n"); - return; - } - - AddressPair *pair = _constructAddressPair( - udp, (struct sockaddr *)&peerIpAddress, peerIpAddressLength); - - bool done = _receivePacket(listener, fd, pair, packet); - if(!done){ - _readCommand(listener, fd, pair, packet); - } - - addressPair_Release(&pair); - } -} diff --git a/hicn-light/src/hicn/io/udpListener.h b/hicn-light/src/hicn/io/udpListener.h deleted file mode 100644 index 62c09e4db..000000000 --- a/hicn-light/src/hicn/io/udpListener.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 udpListener_h -#define udpListener_h - -#ifndef _WIN32 -#include <netinet/in.h> -#endif - -#include <hicn/core/forwarder.h> -#include <hicn/io/listener.h> -#include <stdlib.h> - -struct udp_listener; -typedef struct udp_listener UdpListener; - -ListenerOps *udpListener_CreateInet6(Forwarder *forwarder, char *listenerName, - struct sockaddr_in6 sin6, const char *if_bind); -ListenerOps *udpListener_CreateInet(Forwarder *forwarder, char *listenerName, - struct sockaddr_in sin, const char *if_bind); -// void udpListener_SetPacketType(ListenerOps *ops, MessagePacketType type); -#endif // udpListener_h diff --git a/hicn-light/src/hicn/io/udpTunnel.c b/hicn-light/src/hicn/io/udpTunnel.c deleted file mode 100644 index 9f5249e3c..000000000 --- a/hicn-light/src/hicn/io/udpTunnel.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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 <errno.h> -#include <hicn/hicn-light/config.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> - -#include <parc/algol/parc_Network.h> -#include <parc/assert/parc_Assert.h> -#include <hicn/io/udpConnection.h> -#include <hicn/io/udpListener.h> -#include <hicn/io/udpTunnel.h> - -IoOperations *udpTunnel_CreateOnListener(Forwarder *forwarder, - ListenerOps *localListener, - const Address *remoteAddress) { - parcAssertNotNull(forwarder, "Parameter metis must be non-null"); - parcAssertNotNull(localListener, "Parameter localListener must be non-null"); - parcAssertNotNull(remoteAddress, "Parameter remoteAddress must be non-null"); - - Logger *logger = forwarder_GetLogger(forwarder); - - IoOperations *ops = NULL; - if (localListener->getEncapType(localListener) == ENCAP_UDP) { - const Address *localAddress = - localListener->getListenAddress(localListener); - address_type localType = addressGetType(localAddress); - address_type remoteType = addressGetType(remoteAddress); - - if (localType == remoteType) { - AddressPair *pair = addressPair_Create(localAddress, remoteAddress); - - //check it the connection is local - bool isLocal = false; - if(localType == ADDR_INET){ - struct sockaddr_in tmpAddr; - addressGetInet(localAddress, &tmpAddr); - if(parcNetwork_IsSocketLocal((struct sockaddr *)&tmpAddr)) - isLocal = true; - }else{ - struct sockaddr_in6 tmpAddr6; - addressGetInet6(localAddress, &tmpAddr6); - if(parcNetwork_IsSocketLocal((struct sockaddr *)&tmpAddr6)) - isLocal = true; - } - int fd = localListener->getSocket(localListener); - // udpListener_SetPacketType(localListener, - // MessagePacketType_ContentObject); - ops = udpConnection_Create(forwarder, localListener->getInterfaceName(localListener), fd, pair, isLocal); - - addressPair_Release(&pair); - } else { - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Local listener of type %s and remote type %s, cannot " - "establish tunnel", - addressTypeToString(localType), - addressTypeToString(remoteType)); - } - } - } else { - if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) { - logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__, - "Local listener %p is not type UDP, cannot establish tunnel", - (void *)localListener); - } - } - - return ops; -} - -IoOperations *udpTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress) { - ListenerSet *set = forwarder_GetListenerSet(forwarder); - ListenerOps *listener = listenerSet_Find(set, ENCAP_UDP, localAddress); - IoOperations *ops = NULL; - if (listener) { - ops = udpTunnel_CreateOnListener(forwarder, listener, remoteAddress); - } else { - if (logger_IsLoggable(forwarder_GetLogger(forwarder), LoggerFacility_IO, - PARCLogLevel_Error)) { - char *str = addressToString(localAddress); - logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_IO, - PARCLogLevel_Error, __func__, - "Could not find listener to match address %s", str); - parcMemory_Deallocate((void **)&str); - } - } - return ops; -} diff --git a/hicn-light/src/hicn/io/udpTunnel.h b/hicn-light/src/hicn/io/udpTunnel.h deleted file mode 100644 index dacfdbb01..000000000 --- a/hicn-light/src/hicn/io/udpTunnel.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 udpTunnel.h - * @brief Establish a tunnel to a remote system - * - */ - -#ifndef udpTunnel_h -#define udpTunnel_h - -#include <hicn/core/forwarder.h> -#include <hicn/io/ioOperations.h> -#include <hicn/io/listener.h> -#include <hicn/utils/address.h> - -/** - */ -IoOperations *udpTunnel_CreateOnListener(Forwarder *forwarder, - ListenerOps *localListener, - const Address *remoteAddress); - -/** - */ -IoOperations *udpTunnel_Create(Forwarder *forwarder, - const Address *localAddress, - const Address *remoteAddress); - -#endif // udpTunnel_h |