/** Handle a network control message callback for a new "watch directory" * * @param[in] ctx the network * @param[in] data the message * @param[in] data_size size of the data * @param[in] now the current time */ static void fr_network_directory_callback(void *ctx, void const *data, size_t data_size, UNUSED fr_time_t now) { int num_messages; fr_network_t *nr = ctx; fr_network_socket_t *s; fr_app_io_t const *app_io; fr_event_vnode_func_t funcs = { .extend = fr_network_vnode_extend }; rad_assert(data_size == sizeof(s->listen)); if (data_size != sizeof(s->listen)) return; s = talloc_zero(nr, fr_network_socket_t); rad_assert(s != NULL); s->nr = nr; memcpy(&s->listen, data, sizeof(s->listen)); s->number = nr->num_sockets++; MEM(s->waiting = fr_heap_create(s, waiting_cmp, fr_channel_data_t, channel.heap_id)); talloc_set_destructor(s, _network_socket_free); /* * Allocate the ring buffer for messages and packets. */ num_messages = s->listen->num_messages; if (num_messages < 8) num_messages = 8; s->ms = fr_message_set_create(s, num_messages, sizeof(fr_channel_data_t), s->listen->default_message_size * s->listen->num_messages); if (!s->ms) { fr_log(nr->log, L_ERR, "Failed creating message buffers for directory IO: %s", fr_strerror()); talloc_free(s); return; } app_io = s->listen->app_io; if (app_io->event_list_set) app_io->event_list_set(s->listen->app_io_instance, nr->el, nr); rad_assert(app_io->fd); s->fd = app_io->fd(s->listen->app_io_instance); s->filter = FR_EVENT_FILTER_VNODE; if (fr_event_filter_insert(nr, nr->el, s->fd, s->filter, &funcs, app_io->error ? fr_network_error : NULL, s) < 0) { PERROR("Failed adding new socket to event loop"); talloc_free(s); return; } (void) rbtree_insert(nr->sockets, s); (void) rbtree_insert(nr->sockets_by_num, s); DEBUG3("Using new socket with FD %d", s->fd); }
int main(int argc, char **arg) { fr_heap_t *hp; int i, array[1024]; hp = fr_heap_create(heap_cmp, 0); if (!hp) { fprintf(stderr, "Failed creating heap!\n"); exit(1); } for (i = 0; i < 1024; i++) { array[i] = (i * 257) % 65537; if (!fr_heap_insert(hp, &array[i])) { fprintf(stderr, "Failed inserting %d\n", i); exit(1); } } for (i = 0; i < 1024; i++) { int *p = fr_heap_peek(hp); if (!p) { fprintf(stderr, "Failed peeking %d\n", i); exit(1); } printf("%d\t%d\n", i, *p); if (!fr_heap_extract(hp, NULL)) { fprintf(stderr, "Failed extracting %d\n", i); exit(1); } } fr_heap_delete(hp); return 0; }
int main(int argc, char **argv) { fr_heap_t *hp; int i; heap_thing array[ARRAY_SIZE]; int skip = 0; int left; if (argc > 1) { skip = atoi(argv[1]); } hp = fr_heap_create(heap_cmp, offsetof(heap_thing, heap)); if (!hp) { fprintf(stderr, "Failed creating heap!\n"); fr_exit(1); } for (i = 0; i < ARRAY_SIZE; i++) { array[i].data = rand() % 65537; if (!fr_heap_insert(hp, &array[i])) { fprintf(stderr, "Failed inserting %d\n", i); fr_exit(1); } if (!fr_heap_check(hp, &array[i])) { fprintf(stderr, "Inserted but not in heap %d\n", i); fr_exit(1); } } #if 0 for (i = 0; i < ARRAY_SIZE; i++) { printf("Array %d has value %d at offset %d\n", i, array[i].data, array[i].heap); } #endif if (skip) { int entry; printf("%d elements to remove\n", ARRAY_SIZE / skip); for (i = 0; i < ARRAY_SIZE / skip; i++) { entry = i * skip; if (!fr_heap_extract(hp, &array[entry])) { fprintf(stderr, "Failed removing %d\n", entry); } if (fr_heap_check(hp, &array[entry])) { fprintf(stderr, "Deleted but still in heap %d\n", entry); fr_exit(1); } if (array[entry].heap != -1) { fprintf(stderr, "heap offset is wrong %d\n", entry); fr_exit(1); } } } left = fr_heap_num_elements(hp); printf("%d elements left in the heap\n", left); for (i = 0; i < left; i++) { heap_thing *t = fr_heap_peek(hp); if (!t) { fprintf(stderr, "Failed peeking %d\n", i); fr_exit(1); } printf("%d\t%d\n", i, t->data); if (!fr_heap_extract(hp, NULL)) { fprintf(stderr, "Failed extracting %d\n", i); fr_exit(1); } } if (fr_heap_num_elements(hp) > 0) { fprintf(stderr, "%d elements left at the end", fr_heap_num_elements(hp)); fr_exit(1); } fr_heap_delete(hp); return 0; }
/** Create a network * * @param[in] ctx the talloc ctx * @param[in] el the event list * @param[in] logger the destination for all logging messages * @param[in] lvl log level * @return * - NULL on error * - fr_network_t on success */ fr_network_t *fr_network_create(TALLOC_CTX *ctx, fr_event_list_t *el, fr_log_t const *logger, fr_log_lvl_t lvl) { fr_network_t *nr; nr = talloc_zero(ctx, fr_network_t); if (!nr) { fr_strerror_printf("Failed allocating memory"); return NULL; } nr->el = el; nr->log = logger; nr->lvl = lvl; nr->max_workers = MAX_WORKERS; nr->num_workers = 0; nr->kq = fr_event_list_kq(nr->el); rad_assert(nr->kq >= 0); nr->aq_control = fr_atomic_queue_create(nr, 1024); if (!nr->aq_control) { talloc_free(nr); return NULL; } nr->aq_ident = fr_event_user_insert(nr->el, fr_network_evfilt_user, nr); if (!nr->aq_ident) { fr_strerror_printf_push("Failed updating event list"); talloc_free(nr); return NULL; } nr->control = fr_control_create(nr, nr->kq, nr->aq_control, nr->aq_ident); if (!nr->control) { fr_strerror_printf_push("Failed creating control queue"); fail: (void) fr_event_user_delete(nr->el, fr_network_evfilt_user, nr); talloc_free(nr); return NULL; } /* * @todo - rely on thread-local variables. And then the * various users of this can check if (rb == nr->rb), and * if so, skip the whole control plane / kevent / * whatever roundabout thing. */ nr->rb = fr_ring_buffer_create(nr, FR_CONTROL_MAX_MESSAGES * FR_CONTROL_MAX_SIZE); if (!nr->rb) { fr_strerror_printf_push("Failed creating ring buffer"); fail2: fr_control_free(nr->control); goto fail; } if (fr_control_callback_add(nr->control, FR_CONTROL_ID_CHANNEL, nr, fr_network_channel_callback) < 0) { fr_strerror_printf_push("Failed adding channel callback"); goto fail2; } if (fr_control_callback_add(nr->control, FR_CONTROL_ID_SOCKET, nr, fr_network_socket_callback) < 0) { fr_strerror_printf_push("Failed adding socket callback"); goto fail2; } if (fr_control_callback_add(nr->control, FR_CONTROL_ID_DIRECTORY, nr, fr_network_directory_callback) < 0) { fr_strerror_printf_push("Failed adding socket callback"); goto fail2; } if (fr_control_callback_add(nr->control, FR_CONTROL_ID_WORKER, nr, fr_network_worker_callback) < 0) { fr_strerror_printf_push("Failed adding worker callback"); goto fail2; } if (fr_control_callback_add(nr->control, FR_CONTROL_ID_INJECT, nr, fr_network_inject_callback) < 0) { fr_strerror_printf_push("Failed adding packet injection callback"); goto fail2; } /* * Create the various heaps. */ nr->sockets = rbtree_talloc_create(nr, socket_listen_cmp, fr_network_socket_t, NULL, RBTREE_FLAG_NONE); if (!nr->sockets) { fr_strerror_printf_push("Failed creating listen tree for sockets"); goto fail2; } nr->sockets_by_num = rbtree_talloc_create(nr, socket_num_cmp, fr_network_socket_t, NULL, RBTREE_FLAG_NONE); if (!nr->sockets_by_num) { fr_strerror_printf_push("Failed creating number tree for sockets"); goto fail2; } nr->replies = fr_heap_create(nr, reply_cmp, fr_channel_data_t, channel.heap_id); if (!nr->replies) { fr_strerror_printf_push("Failed creating heap for replies"); goto fail2; } if (fr_event_post_insert(nr->el, fr_network_post_event, nr) < 0) { fr_strerror_printf("Failed inserting post-processing event"); goto fail2; } return nr; }
/** Handle a network control message callback for a new socket * * @param[in] ctx the network * @param[in] data the message * @param[in] data_size size of the data * @param[in] now the current time */ static void fr_network_socket_callback(void *ctx, void const *data, size_t data_size, UNUSED fr_time_t now) { fr_network_t *nr = ctx; fr_network_socket_t *s; fr_app_io_t const *app_io; size_t size; int num_messages; rad_assert(data_size == sizeof(s->listen)); if (data_size != sizeof(s->listen)) return; s = talloc_zero(nr, fr_network_socket_t); rad_assert(s != NULL); s->nr = nr; memcpy(&s->listen, data, sizeof(s->listen)); s->number = nr->num_sockets++; MEM(s->waiting = fr_heap_create(s, waiting_cmp, fr_channel_data_t, channel.heap_id)); talloc_set_destructor(s, _network_socket_free); /* * Put reasonable limits on the ring buffer size. Then * round it up to the nearest power of 2, which is * required by the ring buffer code. */ num_messages = s->listen->num_messages; if (num_messages < 8) num_messages = 8; size = s->listen->default_message_size * num_messages; if (!size) size = (1 << 17); /* * Allocate the ring buffer for messages and packets. */ s->ms = fr_message_set_create(s, num_messages, sizeof(fr_channel_data_t), size); if (!s->ms) { fr_log(nr->log, L_ERR, "Failed creating message buffers for network IO: %s", fr_strerror()); talloc_free(s); return; } app_io = s->listen->app_io; rad_assert(app_io->fd); s->fd = app_io->fd(s->listen->app_io_instance); s->filter = FR_EVENT_FILTER_IO; if (fr_event_fd_insert(nr, nr->el, s->fd, fr_network_read, NULL, fr_network_error, s) < 0) { PERROR("Failed adding new socket to network event loop"); talloc_free(s); return; } if (app_io->event_list_set) app_io->event_list_set(s->listen->app_io_instance, nr->el, nr); (void) rbtree_insert(nr->sockets, s); (void) rbtree_insert(nr->sockets_by_num, s); DEBUG3("Using new socket with FD %d", s->fd); }