diff options
Diffstat (limited to 'hicn-light/src/hicn/core/listener.c')
-rw-r--r-- | hicn-light/src/hicn/core/listener.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/hicn-light/src/hicn/core/listener.c b/hicn-light/src/hicn/core/listener.c new file mode 100644 index 000000000..0ab73b1f4 --- /dev/null +++ b/hicn-light/src/hicn/core/listener.c @@ -0,0 +1,326 @@ +/* + * 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 listener.c + * @brief Implementation of hICN listeners + */ + + + +#include <string.h> // strdup + +#include <hicn/core/listener_vft.h> +#include <hicn/base/loop.h> +#include <hicn/core/forwarder.h> +#include <hicn/util/log.h> +#include "listener.h" + +listener_t * +listener_create(face_type_t type, const address_t * address, + const char * interface_name, const char * name, forwarder_t * forwarder) +{ + const listener_table_t * table = forwarder_get_listener_table(forwarder); + + listener_t * listener; + listener_key_t key = { + .type = type, + .address = *address, + }; + listener_table_allocate(table, listener, &key, name); + + unsigned listener_id = listener_table_get_listener_id(table, listener); + + listener_initialize(listener, type, name, listener_id, address, interface_name, forwarder); + return listener; +} + +int +listener_initialize(listener_t * listener, face_type_t type, const char * name, + unsigned listener_id, const address_t * address, + const char * interface_name, forwarder_t * forwarder) +{ + int rc; + + assert(listener); + assert(forwarder); + + *listener = (listener_t) { + .id = listener_id, + .name = strdup(name), + .type = type, + .interface_name = strdup(interface_name), + //.interface_index = , + //.family = , + .fd = 0, + .address = *address, + .forwarder = forwarder, + }; + + listener->data = malloc(listener_vft[listener->type]->data_size); + if (!listener->data) + goto ERR_DATA; + + assert(listener_has_valid_type(listener)); + + rc = listener_vft[listener->type]->initialize(listener); + if (rc < 0) + goto ERR_VFT; + + listener->fd = listener_vft[listener->type]->get_socket(listener, address, NULL, interface_name); + if (listener->fd < 0) { + ERROR("Error creating listener fd: (%d) %s", errno, strerror(errno)); + goto ERR_FD; + } + assert(listener->fd > 0); + + // XXX data should be pre-allocated here + + if (loop_register_fd(MAIN_LOOP, listener->fd, listener, + (fd_callback_t)listener_vft[listener->type]->read_callback, NULL) < 0) + goto ERR_REGISTER_FD; + + // XXX TODO + //char *str = addressToString(listener->local_addr); + DEBUG("%s UdpListener %p created for address %s", + face_type_str(listener->type), listener, "N/A"); + //free(str); + + return 0; + +ERR_REGISTER_FD: +#ifndef _WIN32 + close(listener->fd); +#else + closesocket(listener->fd); +#endif +ERR_FD: +ERR_VFT: + free(listener->data); +ERR_DATA: + free(listener->interface_name); + free(listener->name); + return -1; +} + +int +listener_finalize(listener_t * listener) +{ + assert(listener); + assert(listener_has_valid_type(listener)); + + loop_unregister_fd(MAIN_LOOP, listener->fd); + +#ifndef _WIN32 + close(listener->fd); +#else + closesocket(listener->fd); +#endif + + listener_vft[listener->type]->finalize(listener); + + free(listener->data); + free(listener->interface_name); + free(listener->name); + + return 0; +} + +int listener_get_socket(const listener_t * listener, const address_t * local, + const address_t * remote, const char * interface_name) +{ + assert(listener); + assert(listener_has_valid_type(listener)); + assert(pair); + + return listener_vft[listener->type]->get_socket(listener, local, remote, + interface_name); +} + +// XXX CHANGE : we now get the fd directly from the listener +unsigned listener_create_connection(const listener_t * listener, + const address_pair_t * pair) +{ + assert(listener); + assert(listener_has_valid_type(listener)); + assert(pair); + + // XXX TODO This code is likely common with connection creation code + const char * name = NULL; + + connection_table_t * table = forwarder_get_connection_table(listener->forwarder); + connection_t * connection; + connection_table_allocate(table, connection, pair, name); + + unsigned connid = connection_table_get_connection_id(table, connection); + + bool local = address_is_local(address_pair_get_local(pair)); + + int fd = listener_get_socket(listener, address_pair_get_local(pair), + address_pair_get_remote(pair), NULL); // XXX interfacename was not specified + + // XXX here we use the same interface name as the listener + int rc = connection_initialize(connection, listener->type, name, + listener->interface_name, fd, pair, local, connid, listener->forwarder); + if (rc < 0) + return ~0; // XXX how to return an error + + // This was already commented: + // connection_AllowWldrAutoStart(*conn_ptr); + + return connid; +} + +int +listener_punt(const listener_t * listener, const char * prefix_s) +{ + assert(listener); + assert(listener_get_type(listener) == FACE_TYPE_HICN); + assert(prefix_s); + + return listener_vft[listener_get_type(listener)]->punt(listener, prefix_s); +} + +ssize_t +listener_read_callback(forwarder_t * forwarder, listener_t * listener, int fd, + address_t * local_addr, uint8_t * packet, size_t size) +{ + // XXX TODO mutualize code across all listeners + // some do not support batches + // + // XXX negative in case of error + // 0 if we don't consume yet because we don't have enough + // needed for TCP !! + return size; +} + +void +listener_batch_read_callback(forwarder_t * forwarder, listener_t * listener, + int fd, address_t * local_addr, batch_buffer_t * bb) +{ + assert(bb); + + // XXX potential improvement : receive in a loop while we have messages to + // read + + // XXX + int r = recvmmsg(fd, bb->msghdr, MAX_MSG, 0, NULL); + if (r == 0) + return; + + if (r < 0) { + if (errno == EINTR) + return; + perror("recv()"); + return; + } + + for (int i = 0; i < r; i++) { + struct mmsghdr *msg = &bb->msghdr[i]; + uint8_t * packet = msg->msg_hdr.msg_iov->iov_base; + size_t size = msg->msg_hdr.msg_iovlen; + + /* BEGIN packet processing */ + +#ifdef __APPLE__ + // XXX explain + msg->msg_hdr.msg_namelen = 0x00; +#endif + + /* Construct address pair used for connection lookup */ + address_pair_t pair; + pair.local = *local_addr; + pair.remote = *(address_t*)msg->msg_hdr.msg_name; + // in the case of a connection, we should assert the remote + + process_packet(forwarder, listener, packet, size, &pair); + } +} + + +#if 0 +void +_listener_callback(evutil_socket_t fd, short what, void * arg) +{ + fd_callback_data_t * data = arg; + data->callback(data->owner, fd, data->data); +} + +int +listener_register_fd(listener_t * listener, int fd, fd_callback_t callback, void * data) +{ + fd_callback_data_t callback_data = { + .fd = fd, + .owner = listener, + .callback = callback, + .data = data, + }; + + return loop_register_fd(MAIN_LOOP, fd, listener, _listener_callback, callback_data); +} + +int +listener_unregister_fd(listener_t * listener, int fd) +{ + return loop_unregister_fd(MAIN_LOOP, fd); +} +#endif + +void +listener_setup_all(const forwarder_t * forwarder, uint16_t port, const char *localPath) +{ +#if 0 + InterfaceSet *set = system_Interfaces(forwarder); + + size_t interfaceSetLen = interfaceSetLength(set); + for (size_t i = 0; i < interfaceSetLen; i++) { + Interface *iface = interfaceSetGetByOrdinalIndex(set, i); + + const AddressList *addresses = interfaceGetAddresses(iface); + size_t addressListLen = addressListLength(addresses); + + for (size_t j = 0; j < addressListLen; j++) { + const address_t *address = addressListGetItem(addresses, j); + + // Do not start on link address + char listenerName[SYMBOLIC_NAME_LEN]; +#ifdef __ANDROID__ + snprintf(listenerName, SYMBOLIC_NAME_LEN, "local_%zu", i); +#else + snprintf(listenerName, SYMBOLIC_NAME_LEN, "local_%ld", i); +#endif + // XXX TODO if (addressGetType(address) != ADDR_LINK) { + _setupTcpListener(forwarder, listenerName, address, + (char *)interfaceGetName(iface)); + // } + } + } + + interfaceSetDestroy(&set); +#endif +} + +// XXX TODO +void +listener_setup_local_ipv4(const forwarder_t * forwarder, uint16_t port) +{ +#if 0 + // XXX memset + address_t address = ADDRESS4_LOCALHOST(port); + + _setupUdpListener(forwarder, "lo_udp", &address, "lo"); + _setupTcpListener(forwarder, "lo_tcp", &address, "lo"); +#endif +} |