/** * \brief Change mode of output manager * * Allow to change mode from single mode to multi mode and vice versa. * If new mode is different from current mode, all data managers are removed. * If the manager thread is running, it will be stopped and restarted later. * * \param[in] mode New mode of output manager * \return 0 on successs */ int output_manager_set_mode(enum om_mode mode) { if (conf->perman_odid_merge) { /* Nothing can be changed, permanent single manager mode enabled */ if (mode == OM_MULTIPLE) { MSG_WARNING(msg_module, "Unable to change Output Manager mode. " "Single manager mode permanently enabled ('-M' argument)"); } return 0; } if (conf->manager_mode == mode) { /* Mode is still the same */ return 0; } if (conf->running) { MSG_DEBUG(msg_module, "Stopping Output Manager thread"); rbuffer_write(conf->in_queue, NULL, 1); pthread_join(conf->thread_id, NULL); } /* Delete data managers */ struct data_manager_config *aux_config = conf->data_managers; while (aux_config) { struct data_manager_config *tmp = aux_config; aux_config = aux_config->next; data_manager_close(&tmp); } conf->data_managers = NULL; conf->last = NULL; conf->manager_mode = mode; if (mode == OM_SINGLE) { MSG_INFO(msg_module, "Switching Output Manager to single manager mode"); } else if (mode == OM_MULTIPLE) { MSG_INFO(msg_module, "Switching Output Manager to multiple manager mode"); } else { /* Unknown mode */ } if (conf->running) { /* Restart thread */ int retval; MSG_DEBUG(msg_module, "Restarting Output Manager thread"); retval = pthread_create(&(conf->thread_id), NULL, &output_manager_plugin_thread, (void *) conf); if (retval != 0) { MSG_ERROR(msg_module, "Unable to create Output Manager thread"); free(conf); return -1; } } return 0; }
static void read_cb(Stream *stream, RBuffer *buf, void *data, bool at_eof) { if (at_eof) { input_eof = true; } assert(rbuffer_space(input_buffer) >= rbuffer_size(buf)); RBUFFER_UNTIL_EMPTY(buf, ptr, len) { (void)rbuffer_write(input_buffer, ptr, len); rbuffer_consumed(buf, len); }
static void read_cb(RStream *rstream, void *data, bool at_eof) { if (at_eof) { input_eof = true; } char *buf = rbuffer_read_ptr(read_buffer); size_t buf_size = rbuffer_pending(read_buffer); (void)rbuffer_write(input_buffer, buf, buf_size); rbuffer_consumed(read_buffer, buf_size); }
size_t input_enqueue(String keys) { char *ptr = keys.data; char *end = ptr + keys.size; while (rbuffer_space(input_buffer) >= 6 && ptr < end) { uint8_t buf[6] = { 0 }; unsigned int new_size = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true, true); if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); rbuffer_write(input_buffer, (char *)buf, new_size); continue; } if (*ptr == '<') { char *old_ptr = ptr; // Invalid or incomplete key sequence, skip until the next '>' or *end. do { ptr++; } while (ptr < end && *ptr != '>'); if (*ptr != '>') { // Incomplete key sequence, return without consuming. ptr = old_ptr; break; } ptr++; continue; } // copy the character, escaping CSI and K_SPECIAL if ((uint8_t)*ptr == CSI) { rbuffer_write(input_buffer, (char *)&(uint8_t){K_SPECIAL}, 1); rbuffer_write(input_buffer, (char *)&(uint8_t){KS_EXTRA}, 1); rbuffer_write(input_buffer, (char *)&(uint8_t){KE_CSI}, 1); } else if ((uint8_t)*ptr == K_SPECIAL) { rbuffer_write(input_buffer, (char *)&(uint8_t){K_SPECIAL}, 1); rbuffer_write(input_buffer, (char *)&(uint8_t){KS_SPECIAL}, 1); rbuffer_write(input_buffer, (char *)&(uint8_t){KE_FILLER}, 1); } else { rbuffer_write(input_buffer, ptr, 1); } ptr++; } size_t rv = (size_t)(ptr - keys.data); process_interrupts(); return rv; }
/** * \brief Close Ouput Manager and all Data Managers */ void output_manager_close(void *config) { struct output_manager_config *manager = (struct output_manager_config *) config; struct data_manager_config *aux_config = NULL, *tmp = NULL; struct stat_thread *aux_thread = NULL, *tmp_thread = NULL; /* Stop Output Manager thread and free input buffer */ if (manager->running) { rbuffer_write(manager->in_queue, NULL, 1); pthread_join(manager->thread_id, NULL); rbuffer_free(manager->in_queue); /* Close statistics thread */ if (manager->stat_interval > 0) { manager->stats.done = 1; pthread_kill(manager->stat_thread, SIGUSR1); pthread_join(manager->stat_thread, NULL); } aux_config = manager->data_managers; /* Close all data managers */ while (aux_config) { tmp = aux_config; aux_config = aux_config->next; data_manager_close(&tmp); } /* Free input_info_list */ if (input_info_list) { struct input_info_node *aux_node = input_info_list; while (aux_node) { struct input_info_node *aux_node_rm = aux_node; aux_node = aux_node->next; free(aux_node_rm); } } /* Free all thread structures for statistics */ aux_thread = manager->stats.threads; while (aux_thread) { tmp_thread = aux_thread; aux_thread = aux_thread->next; free(tmp_thread); } } free(manager); }
/** * \brief Pass processed IPFIX message to the output queue. * * \param[in] config configuration structure * \param[in] message IPFIX message * \return 0 on success, negative value otherwise */ int pass_message(void *config, struct ipfix_message *message) { struct ip_config *conf; int ret; conf = (struct ip_config *) config; if (message == NULL) { MSG_WARNING(msg_module, "NULL message from intermediate plugin, skipping."); return 0; } ret = rbuffer_write(conf->out_queue, message, 1); return ret; }
/** * \brief Change process input queue */ int ip_change_in_queue(struct intermediate* conf, struct ring_buffer* in_queue) { pthread_mutex_lock(&conf->in_q_mutex); conf->new_in = in_queue; rbuffer_write(conf->in_queue, NULL, 1); /* Wait for change */ while (conf->in_queue != in_queue) { pthread_cond_wait(&conf->in_q_cond, &conf->in_q_mutex); } pthread_mutex_unlock(&conf->in_q_mutex); return 0; }
/** * \brief Stop Intermediate Process */ int ip_stop(struct intermediate *conf) { void *retval; int ret; if (!conf) { return -1; } /* wait for thread to terminate */ rbuffer_write(conf->in_queue, NULL, 1); ret = pthread_join(conf->thread_id, &retval); if (ret != 0) { MSG_DEBUG(msg_module, "pthread_join() error"); } return 0; }
int32_t bus_terminal_send(bus_terminal_t* bt, const char* buf, size_t buf_size, bus_addr_t to) { struct bus_terminal_channel_t* btc; int32_t ret; if (!bt) return bus_err_fail; btc = (struct bus_terminal_channel_t*)idtable_get(bt->send_channels, to); // if no channel, then dynamic alloc one if (!btc) { ret = _bus_terminal_register_channel(bt, to, BUS_CHANNEL_DEFAULT_SIZE); if (ret != bus_ok) { return ret; } } btc = (struct bus_terminal_channel_t*)idtable_get(bt->send_channels, to); assert(btc); // send buffer ret = rbuffer_write(bus_terminal_channel_rbuffer(btc), buf, buf_size); return ret == 0 ? bus_ok : bus_err_send_fail; }
/** * \brief Set new input queue */ void output_manager_set_in_queue(struct ring_buffer *in_queue) { if (conf->in_queue == in_queue) { return; } if (conf->running) { /* If already running, control message must be sent */ pthread_mutex_lock(&conf->in_q_mutex); conf->new_in = in_queue; rbuffer_write(conf->in_queue, NULL, 1); /* Wait for change */ while (conf->in_queue != in_queue) { pthread_cond_wait(&conf->in_q_cond, &conf->in_q_mutex); } pthread_mutex_unlock(&conf->in_q_mutex); } else { conf->in_queue = in_queue; } }
size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col) { modifier |= check_multiclick(code, grid, row, col); uint8_t buf[7], *p = buf; if (modifier) { p[0] = K_SPECIAL; p[1] = KS_MODIFIER; p[2] = modifier; p += 3; } p[0] = K_SPECIAL; p[1] = KS_EXTRA; p[2] = (uint8_t)code; mouse_grid = grid; mouse_row = row; mouse_col = col; size_t written = 3 + (size_t)(p-buf); rbuffer_write(input_buffer, (char *)buf, written); return written; }
/** * \brief Output Managers thread * * @param[in] config configuration structure * @return NULL */ static void *output_manager_plugin_thread(void* config) { struct data_manager_config *data_config = NULL; struct ipfix_message* msg = NULL; unsigned int index; conf = (struct output_manager_config *) config; index = conf->in_queue->read_offset; /* set the thread name to reflect the configuration */ prctl(PR_SET_NAME, "ipfixcol OM", 0, 0, 0); /* loop will break upon receiving NULL from buffer */ while (1) { /* get next data */ index = -1; msg = rbuffer_read(conf->in_queue, &index); if (!msg) { rbuffer_remove_reference(conf->in_queue, index, 1); if (conf->new_in) { /* Set new input queue */ conf->in_queue = (struct ring_buffer *) conf->new_in; conf->new_in = NULL; pthread_cond_signal(&conf->in_q_cond); continue; } /* End manager */ break; } /* get appropriate data manager's config according to Observation domain ID */ data_config = get_data_mngmt_config (msg->input_info->odid, conf->data_managers); if (data_config == NULL) { /* * no data manager config for this observation domain ID found - * we have a new observation domain ID, so create new data manager for * it */ data_config = data_manager_create(msg->input_info->odid, conf->storage_plugins); if (data_config == NULL) { MSG_WARNING(msg_module, "[%u] Unable to create Data Manager; skipping data...", msg->input_info->odid); rbuffer_remove_reference(conf->in_queue, index, 1); continue; } /* add config to data_mngmts structure */ output_manager_insert(conf, data_config); MSG_NOTICE(msg_module, "[%u] Data Manager created", msg->input_info->odid); } if (msg->source_status == SOURCE_STATUS_NEW) { /* New source, increment reference counter */ MSG_DEBUG(msg_module, "[%u] New source", data_config->observation_domain_id); data_config->references++; } else if (msg->source_status == SOURCE_STATUS_CLOSED) { /* Source closed, decrement reference counter */ MSG_DEBUG(msg_module, "[%u] Closed source", data_config->observation_domain_id); data_config->references--; if (data_config->references == 0) { /* No reference for this ODID, close DM */ MSG_DEBUG(msg_module, "[%u] No source; releasing templates...", data_config->observation_domain_id); output_manager_remove(conf, data_config); } rbuffer_remove_reference(conf->in_queue, index, 1); continue; } __sync_fetch_and_add(&(conf->packets), 1); __sync_fetch_and_add(&(conf->data_records), msg->data_records_count); /* Check for lost data records */ uint32_t seq_number = ntohl(msg->pkt_header->sequence_number); // Set sequence number during first iteration if (conf->first_seq == 0 && conf->last_seq == 0) { conf->first_seq = seq_number; } else if (seq_number < conf->first_seq) { // Sequence number resetted (modulo 2^32 = 4294967296) conf->first_seq = seq_number; uint8_t delta_seq = 4294967296 - conf->last_seq + seq_number; // Check for sequence number gap if (delta_seq > msg->data_records_count) { __sync_fetch_and_add(&(conf->lost_data_records), delta_seq - msg->data_records_count); } } else if (seq_number > conf->first_seq) { // Check for sequence number gap if (seq_number - msg->data_records_count > conf->last_seq) { __sync_fetch_and_add(&(conf->lost_data_records), seq_number - msg->data_records_count - conf->last_seq); } } else { // Do nothing } conf->last_seq = seq_number; /* Write data into input queue of Storage Plugins */ if (rbuffer_write(data_config->store_queue, msg, data_config->plugins_count) != 0) { MSG_WARNING(msg_module, "[%u] Unable to write into Data Manager's input queue; skipping data...", data_config->observation_domain_id); rbuffer_remove_reference(conf->in_queue, index, 1); free(msg); continue; } /* Remove data from queue (without deallocating) */ rbuffer_remove_reference(conf->in_queue, index, 0); } MSG_NOTICE(msg_module, "Closing Output Manager thread"); return (void *) 0; }
/** * \brief Output Manager thread * * @param[in] config configuration structure * @return NULL */ static void *output_manager_plugin_thread(void* config) { struct data_manager_config *data_config = NULL; struct ipfix_message* msg = NULL; unsigned int index; uint32_t odid; conf = (struct output_manager_config *) config; index = conf->in_queue->read_offset; /* Set thread name to reflect the configuration */ prctl(PR_SET_NAME, "ipfixcol OM", 0, 0, 0); /* loop will break upon receiving NULL from buffer */ while (1) { /* get next data */ index = -1; msg = rbuffer_read(conf->in_queue, &index); if (!msg) { rbuffer_remove_reference(conf->in_queue, index, 1); if (conf->new_in) { /* Set new input queue */ conf->in_queue = (struct ring_buffer *) conf->new_in; conf->new_in = NULL; pthread_cond_signal(&conf->in_q_cond); continue; } /* Stop manager */ break; } odid = (conf->perman_odid_merge || conf->manager_mode == OM_SINGLE) ? 0 : msg->input_info->odid; /* Get appropriate data Manager config according to ODID */ data_config = get_data_mngmt_config(odid, conf->data_managers); if (data_config == NULL) { /* * No data manager config for this observation domain ID found - * we have a new observation domain ID, so create new data manager for * it */ data_config = data_manager_create(odid, conf->storage_plugins); if (data_config == NULL) { MSG_WARNING(msg_module, "[%u] Unable to create Data Manager; skipping data...", odid); rbuffer_remove_reference(conf->in_queue, index, 1); continue; } /* Add config to data_mngmts structure */ output_manager_insert(conf, data_config); MSG_INFO(msg_module, "[%u] Data Manager created", odid); } if (msg->source_status == SOURCE_STATUS_NEW) { /* New source, increment reference counter */ MSG_DEBUG(msg_module, "[%u] New source", data_config->observation_domain_id); data_config->references++; /* Add input info for the statistics thread to read */ add_input_info(msg->input_info); } else if (msg->source_status == SOURCE_STATUS_CLOSED) { /* Source closed, decrement reference counter */ MSG_DEBUG(msg_module, "[%u] Closed source", data_config->observation_domain_id); data_config->references--; /* Remove a reference to a template record */ uint32_t original_odid = msg->input_info->odid; uint32_t source_crc = preprocessor_compute_crc(msg->input_info); if (tm_source_unregister(template_mgr, original_odid, source_crc)) { MSG_ERROR(msg_module, "[%u] Unable to unregister the source from the main template manager!", data_config->observation_domain_id); } /* Remove input_info from statistics */ remove_input_info(msg->input_info); if (data_config->references == 0) { /* No reference for this ODID, close DM */ MSG_DEBUG(msg_module, "[%u] No source; releasing templates...", data_config->observation_domain_id); output_manager_remove(conf, data_config); } rbuffer_remove_reference(conf->in_queue, index, 1); continue; } /* Write data into input queue of Storage Plugins */ if (rbuffer_write(data_config->store_queue, msg, data_config->plugins_count) != 0) { MSG_WARNING(msg_module, "[%u] Unable to write into Data Manager input queue; skipping data...", data_config->observation_domain_id); rbuffer_remove_reference(conf->in_queue, index, 1); free(msg); continue; } /* Remove data from queue (without memory deallocation) */ rbuffer_remove_reference(conf->in_queue, index, 0); } MSG_INFO(msg_module, "Closing Output Manager thread"); return (void *) 0; }