int event_listener_unregister(struct event_reg *evt_reg, void *obj) { struct event_listener *lst; for (lst = evt_reg->listeners; lst && lst->obj != obj; lst = lst->next); if (!lst) { pomlog(POMLOG_ERR "Object %p not found in the listeners list of event %s", obj, evt_reg->info->name); return POM_ERR; } if (lst->next) lst->next->prev = lst->prev; if (lst->prev) lst->prev->next = lst->next; else evt_reg->listeners = lst->next; free(lst); if (!evt_reg->listeners) { if (evt_reg->info->listeners_notify && evt_reg->info->listeners_notify(evt_reg->info->source_obj, evt_reg, 0) != POM_OK) { pomlog(POMLOG_WARN "Error while notifying event object that it has no listeners"); } } registry_perf_dec(evt_reg->perf_listeners, 1); return POM_OK; }
int proto_expectation_expiry(void *priv, ptime now) { struct proto_expectation *e = priv; struct proto *proto = e->tail->proto; timer_cleanup(e->expiry); pom_rwlock_wlock(&proto->expectation_lock); if (e->next) e->next->prev = e->prev; if (e->prev) e->prev->next = e->next; else proto->expectations = e->next; pom_rwlock_unlock(&proto->expectation_lock); if (e->priv && proto->info->ct_info->cleanup_handler) { if (proto->info->ct_info->cleanup_handler(e->priv) != POM_OK) pomlog(POMLOG_WARN "Unable to free the conntrack priv of the proto_expectation"); } registry_perf_dec(e->proto->perf_expt_pending, 1); proto_expectation_cleanup(e); return POM_OK; }
int proto_expectation_remove(struct proto_expectation *e) { struct proto *proto = e->tail->proto; pom_rwlock_wlock(&proto->expectation_lock); if (!(e->flags & PROTO_EXPECTATION_FLAG_QUEUED)) { pom_rwlock_unlock(&proto->expectation_lock); return POM_ERR; } if (!e->next && !e->prev && proto->expectations != e) { // The expectation is not queued pom_rwlock_unlock(&proto->expectation_lock); return POM_OK; } if (e->next) e->next->prev = e->prev; if (e->prev) e->prev->next = e->next; else proto->expectations = e->next; __sync_fetch_and_and(&e->flags, ~PROTO_EXPECTATION_FLAG_QUEUED); pom_rwlock_unlock(&proto->expectation_lock); registry_perf_dec(e->proto->perf_expt_pending, 1); return POM_OK; }
int timer_cleanup(struct timer *t) { if (t->queue) timer_dequeue(t); free(t); registry_perf_dec(perf_timer_allocated, 1); return POM_OK; }
int event_process_end(struct event *evt) { debug_event("Processing event end %s", evt->reg->info->name); if (!(evt->flags & EVENT_FLAG_PROCESS_BEGAN)) { pomlog(POMLOG_ERR "Internal error: event %s processing hasn't begun", evt->reg->info->name); event_cleanup(evt); return POM_ERR; } if (evt->flags & EVENT_FLAG_PROCESS_DONE) { pomlog(POMLOG_ERR "Internal error: event %s has already been processed entirely", evt->reg->info->name); event_cleanup(evt); return POM_ERR; } struct event_listener *lst; for (lst = evt->reg->listeners; lst; lst = lst->next) { if (lst->process_end && lst->process_end(evt, lst->obj) != POM_OK) { pomlog(POMLOG_WARN "An error occured while processing event %s", evt->reg->info->name); } } for (lst = evt->tmp_listeners; lst; lst = lst->next) { if (lst->process_end && lst->process_end(evt, lst->obj) != POM_OK) { pomlog(POMLOG_WARN "An error occured while processing event %s", evt->reg->info->name); } registry_perf_dec(evt->reg->perf_listeners, 1); } evt->ce = NULL; evt->flags |= EVENT_FLAG_PROCESS_DONE; registry_perf_dec(evt->reg->perf_ongoing, 1); registry_perf_inc(evt->reg->perf_processed, 1); return event_refcount_dec(evt); }
int output_file_pload_close(void *output_priv, void *pload_instance_priv) { struct output_file_pload_priv *ppriv = pload_instance_priv; int fd = ppriv->fd; pomlog(POMLOG_DEBUG "File %s closed", ppriv->filename); free(ppriv->filename); free(ppriv); struct output_file_priv *priv = output_priv; if (priv) { if (priv->perf_files_open) registry_perf_dec(priv->perf_files_open, 1); if (priv->perf_files_closed) registry_perf_inc(priv->perf_files_closed, 1); } return close(fd); }
int timer_dequeue(struct timer *t) { // First let's check if it's the one at the begining of the queue pom_mutex_lock(&timer_main_lock); if (!t->queue) { pomlog(POMLOG_WARN "Warning, timer %p was already dequeued", t); pom_mutex_unlock(&timer_main_lock); return POM_OK; } if (t->prev) { t->prev->next = t->next; } else { t->queue->head = t->next; if (t->queue->head) t->queue->head->prev = NULL; } if (t->next) { t->next->prev = t->prev; } else { t->queue->tail = t->prev; if (t->queue->tail) t->queue->tail->next = NULL; } // Make sure this timer will not reference anything t->prev = NULL; t->next = NULL; t->queue = NULL; pom_mutex_unlock(&timer_main_lock); registry_perf_dec(perf_timer_queued, 1); return POM_OK; }
int packet_release(struct packet *p) { // Release the multipart struct packet_multipart *multipart = __sync_fetch_and_and(&p->multipart, 0); if (multipart && packet_multipart_cleanup(multipart) != POM_OK) return POM_ERR; // The packet refcount will be 0 afterwards // We can clean up the buffer if any if (p->refcount > 1) { __sync_fetch_and_sub(&p->refcount, 1); return POM_OK; } if (p->pkt_buff) packet_buffer_release(p->pkt_buff); registry_perf_dec(perf_pkt_in_use, 1); free(p); return POM_OK; }
int timers_process() { static int processing = 0; int res = pthread_mutex_trylock(&timer_main_lock); if (res == EBUSY) { // Already locked, give up return POM_OK; } else if (res) { // Something went wrong pomlog(POMLOG_ERR "Error while trying to lock the main timer lock : %s", pom_strerror(res)); abort(); return POM_ERR; } // Another thread is already processing the timers, drop out if (processing) { pom_mutex_unlock(&timer_main_lock); return POM_OK; } processing = 1; ptime now = core_get_clock(); struct timer_queue *tq; tq = timer_queues; while (tq) { while (tq->head && (tq->head->expires < now)) { // Dequeue the timer struct timer *tmp = tq->head; tq->head = tq->head->next; if (tq->head) tq->head->prev = NULL; else tq->tail = NULL; tmp->next = NULL; tmp->prev = NULL; tmp->queue = NULL; pom_mutex_unlock(&timer_main_lock); registry_perf_dec(perf_timer_queued, 1); // Process it debug_timer( "Timer 0x%lx reached. Starting handler ...", (unsigned long) tmp); if ((*tmp->handler) (tmp->priv, now) != POM_OK) { return POM_ERR; } registry_perf_inc(perf_timer_processed, 1); pom_mutex_lock(&timer_main_lock); } tq = tq->next; } processing = 0; pom_mutex_unlock(&timer_main_lock); return POM_OK; }
void packet_buffer_release(struct packet_buffer *pb) { registry_perf_dec(perf_pkt_buff, pb->buff_size); free(pb); }
int proto_process(struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) { struct proto_process_stack *s = &stack[stack_index]; struct proto *proto = s->proto; if (!proto || !proto->info->process) return PROTO_ERR; int res = proto->info->process(proto->priv, p, stack, stack_index); registry_perf_inc(proto->perf_pkts, 1); registry_perf_inc(proto->perf_bytes, s->plen); if (res != PROTO_OK) return res; // Process the expectations ! pom_rwlock_rlock(&proto->expectation_lock); struct proto_expectation *e = proto->expectations; while (e) { int expt_dir = POM_DIR_UNK; struct proto_expectation_stack *es = e->tail; struct ptype *fwd_value = s->pkt_info->fields_value[s->proto->info->ct_info->fwd_pkt_field_id]; struct ptype *rev_value = s->pkt_info->fields_value[s->proto->info->ct_info->rev_pkt_field_id]; if ((!es->fields[POM_DIR_FWD] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], fwd_value)) && (!es->fields[POM_DIR_REV] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], rev_value))) { // Expectation matched the forward direction expt_dir = POM_DIR_FWD; } else if ((!es->fields[POM_DIR_FWD] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], rev_value)) && (!es->fields[POM_DIR_REV] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], fwd_value))) { // Expectation matched the reverse direction expt_dir = POM_DIR_REV; } if (expt_dir == POM_DIR_UNK) { // Expectation not matched e = e->next; continue; } es = es->prev; int stack_index_tmp = stack_index - 1; while (es) { struct proto_process_stack *s_tmp = &stack[stack_index_tmp]; if (s_tmp->proto != es->proto) { e = e->next; continue; } fwd_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->fwd_pkt_field_id]; rev_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->rev_pkt_field_id]; if (expt_dir == POM_DIR_FWD) { if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], fwd_value)) || (es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], rev_value))) { e = e->next; continue; } } else { if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], rev_value)) || (es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], fwd_value))) { e = e->next; continue; } } es = es->prev; stack_index_tmp--; } // Expectation matched ! // Relock with write access pom_rwlock_unlock(&proto->expectation_lock); pom_rwlock_wlock(&proto->expectation_lock); debug_expectation("Expectation %p matched !", e); // Remove it from the list if (e->next) e->next->prev = e->prev; if (e->prev) e->prev->next = e->next; else proto->expectations = e->next; struct proto_process_stack *s_next = &stack[stack_index + 1]; s_next->proto = e->proto; if (conntrack_get_unique_from_parent(stack, stack_index + 1) != POM_OK) { proto_expectation_cleanup(e); return PROTO_ERR; } s_next->ce->priv = e->priv; if (conntrack_session_bind(s_next->ce, e->session)) { proto_expectation_cleanup(e); return PROTO_ERR; } registry_perf_dec(e->proto->perf_expt_pending, 1); registry_perf_inc(e->proto->perf_expt_matched, 1); proto_expectation_cleanup(e); conntrack_unlock(s_next->ce); break; } pom_rwlock_unlock(&proto->expectation_lock); return res; }
void *core_processing_thread_func(void *priv) { struct core_processing_thread *tpriv = priv; if (packet_info_pool_init()) { halt("Error while initializing the packet_info_pool", 1); return NULL; } registry_perf_inc(perf_thread_active, 1); pom_mutex_lock(&tpriv->pkt_queue_lock); while (core_run) { while (!tpriv->pkt_queue_head) { // We are not active while waiting for a packet registry_perf_dec(perf_thread_active, 1); debug_core("thread %u : waiting", tpriv->thread_id); if (registry_perf_getval(perf_thread_active) == 0) { if (core_get_state() == core_state_finishing) core_set_state(core_state_idle); } if (!core_run) { pom_mutex_unlock(&tpriv->pkt_queue_lock); goto end; } int res = pthread_cond_wait(&tpriv->pkt_queue_cond, &tpriv->pkt_queue_lock); if (res) { pomlog(POMLOG_ERR "Error while waiting for restart condition : %s", pom_strerror(res)); abort(); return NULL; } registry_perf_inc(perf_thread_active, 1); } // Dequeue a packet struct core_packet_queue *tmp = tpriv->pkt_queue_head; tpriv->pkt_queue_head = tmp->next; if (!tpriv->pkt_queue_head) tpriv->pkt_queue_tail = NULL; // Add it to the unused list tmp->next = tpriv->pkt_queue_unused; tpriv->pkt_queue_unused = tmp; tpriv->pkt_count--; registry_perf_dec(perf_pkt_queue, 1); __sync_fetch_and_sub(&core_pkt_queue_count, 1); if (tpriv->pkt_count < CORE_THREAD_PKT_QUEUE_MIN) { pom_mutex_lock(&core_pkt_queue_wait_lock); // Tell the input processes that they can continue queuing packets int res = pthread_cond_broadcast(&core_pkt_queue_wait_cond); if (res) { pomlog(POMLOG_ERR "Error while signaling the main pkt_queue condition : %s", pom_strerror(res)); abort(); } pom_mutex_unlock(&core_pkt_queue_wait_lock); } // Keep track of our packet struct packet *pkt = tmp->pkt; debug_core("thread %u : Processing packet %p (%u.%06u)", tpriv->thread_id, pkt, pom_ptime_sec(pkt->ts), pom_ptime_usec(pkt->ts)); pom_mutex_unlock(&tpriv->pkt_queue_lock); // Lock the processing lock pom_rwlock_rlock(&core_processing_lock); // Update the current clock if (core_clock[tpriv->thread_id] < pkt->ts) // Make sure we keep it monotonous core_clock[tpriv->thread_id] = pkt->ts; //pomlog(POMLOG_DEBUG "Thread %u processing ...", pthread_self()); if (core_process_packet(pkt) == POM_ERR) { core_run = 0; pom_rwlock_unlock(&core_processing_lock); break; } // Process timers if (timers_process() != POM_OK) { pom_rwlock_unlock(&core_processing_lock); break; } pom_rwlock_unlock(&core_processing_lock); if (packet_release(pkt) != POM_OK) { pomlog(POMLOG_ERR "Error while releasing the packet"); break; } debug_core("thread %u : Processed packet %p (%u.%06u)", tpriv->thread_id, pkt, pom_ptime_sec(pkt->ts), pom_ptime_usec(pkt->ts)); // Re-lock our queue for the next run pom_mutex_lock(&tpriv->pkt_queue_lock); } halt("Processing thread encountered an error", 1); end: packet_info_pool_cleanup(); return NULL; }
int conntrack_cleanup(struct conntrack_tables *ct, uint32_t hash, struct conntrack_entry *ce) { // Remove the conntrack from the conntrack table pom_mutex_lock(&ct->locks[hash]); // Try to find the conntrack in the list struct conntrack_list *lst = NULL; for (lst = ct->table[hash]; lst && lst->ce != ce; lst = lst->next); if (!lst) { pom_mutex_unlock(&ct->locks[hash]); pomlog(POMLOG_ERR "Trying to cleanup a non existing conntrack : %p", ce); return POM_OK; } conntrack_lock(ce); if (ce->refcount) { debug_conntrack(POMLOG_ERR "Conntrack %p is still being referenced : %u !", ce, ce->refcount); conntrack_delayed_cleanup(ce, 1, core_get_clock_last()); conntrack_unlock(ce); pom_mutex_unlock(&ct->locks[hash]); return POM_OK; } if (lst->prev) lst->prev->next = lst->next; else ct->table[hash] = lst->next; if (lst->next) lst->next->prev = lst->prev; free(lst); pom_mutex_unlock(&ct->locks[hash]); if (ce->cleanup_timer && ce->cleanup_timer != (void *) -1) { conntrack_timer_cleanup(ce->cleanup_timer); ce->cleanup_timer = (void *) -1; // Mark that the conntrack is being cleaned up } // Once the conntrack is removed from the hash table, it will not be referenced ever again conntrack_unlock(ce); if (ce->parent) { debug_conntrack("Cleaning up conntrack %p, with parent %p", ce, ce->parent->ce); } else { debug_conntrack("Cleaning up conntrack %p, with no parent", ce); } if (ce->parent) { // Remove the child from the parent // Make sure the parent still exists uint32_t hash = ce->parent->hash; pom_mutex_lock(&ce->parent->ct->locks[hash]); for (lst = ce->parent->ct->table[hash]; lst && lst->ce != ce->parent->ce; lst = lst->next); if (lst) { conntrack_lock(ce->parent->ce); struct conntrack_node_list *tmp = ce->parent->ce->children; for (; tmp && tmp->ce != ce; tmp = tmp->next); if (tmp) { if (tmp->prev) tmp->prev->next = tmp->next; else ce->parent->ce->children = tmp->next; if (tmp->next) tmp->next->prev = tmp->prev; free(tmp); } else { pomlog(POMLOG_WARN "Conntrack %s not found in parent's %s children list", ce, ce->parent->ce); } if (!ce->parent->ce->children) // Parent has no child anymore, clean it up after some time conntrack_delayed_cleanup(ce->parent->ce, CONNTRACK_CHILDLESS_TIMEOUT, core_get_clock_last()); conntrack_unlock(ce->parent->ce); } else { debug_conntrack("Parent conntrack %p not found while cleaning child %p !", ce->parent->ce, ce); } pom_mutex_unlock(&ce->parent->ct->locks[hash]); free(ce->parent); } if (ce->session) conntrack_session_refcount_dec(ce->session); // Cleanup private stuff from the conntrack if (ce->priv && ce->proto->info->ct_info->cleanup_handler) { if (ce->proto->info->ct_info->cleanup_handler(ce->priv) != POM_OK) pomlog(POMLOG_WARN "Unable to free the private memory of a conntrack"); } // Cleanup the priv_list struct conntrack_priv_list *priv_lst = ce->priv_list; while (priv_lst) { if (priv_lst->cleanup) { if (priv_lst->cleanup(priv_lst->obj, priv_lst->priv) != POM_OK) pomlog(POMLOG_WARN "Error while cleaning up private objects in conntrack_entry"); } ce->priv_list = priv_lst->next; free(priv_lst); priv_lst = ce->priv_list; } // Cleanup the children while (ce->children) { struct conntrack_node_list *child = ce->children; ce->children = child->next; if (conntrack_cleanup(child->ct, child->hash, child->ce) != POM_OK) return POM_ERR; free(child); } if (ce->fwd_value) ptype_cleanup(ce->fwd_value); if (ce->rev_value) ptype_cleanup(ce->rev_value); pthread_mutex_destroy(&ce->lock); registry_perf_dec(ce->proto->perf_conn_cur, 1); free(ce); return POM_OK; }
int proto_process(struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) { struct proto_process_stack *s = &stack[stack_index]; struct proto *proto = s->proto; if (!proto || !proto->info->process) return PROTO_ERR; int res = proto->info->process(proto->priv, p, stack, stack_index); registry_perf_inc(proto->perf_pkts, 1); registry_perf_inc(proto->perf_bytes, s->plen); if (res != PROTO_OK) return res; int matched = 0; // Process the expectations ! pom_rwlock_rlock(&proto->expectation_lock); struct proto_expectation *e = NULL; for (e = proto->expectations; e; e = e->next) { if (e->flags & PROTO_EXPECTATION_FLAG_MATCHED) { // Another thread already matched the expectation, continue continue; } // Bit one means it matches the forward direction // Bit two means it matches the reverse direction int expt_dir = 3; struct proto_expectation_stack *es = e->tail; int stack_index_tmp = stack_index; while (es) { struct proto_process_stack *s_tmp = &stack[stack_index_tmp]; if (s_tmp->proto != es->proto) { expt_dir = 0; break; } struct ptype *fwd_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->fwd_pkt_field_id]; struct ptype *rev_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->rev_pkt_field_id]; if (expt_dir & 1) { if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], fwd_value)) || (es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], rev_value))) { expt_dir &= ~1; // It doesn't match in the forward direction } } if (expt_dir & 2) { if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], rev_value)) || (es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], fwd_value))) { expt_dir &= ~2; } } if (!expt_dir) break; es = es->prev; stack_index_tmp--; } if (expt_dir) { // It matched if (!(__sync_fetch_and_or(&e->flags, PROTO_EXPECTATION_FLAG_MATCHED) & PROTO_EXPECTATION_FLAG_MATCHED)) { // Something matched matched++; } } } pom_rwlock_unlock(&proto->expectation_lock); if (!matched) return POM_OK; // At least one expectation matched ! debug_expectation("%u expectation matched !", matched); // Relock with write access pom_rwlock_wlock(&proto->expectation_lock); e = proto->expectations; while (e) { struct proto_expectation *cur = e; e = e->next; if (!(cur->flags & PROTO_EXPECTATION_FLAG_MATCHED)) continue; // Remove the expectation from the conntrack if (cur->next) cur->next->prev = cur->prev; if (cur->prev) cur->prev->next = cur->next; else proto->expectations = cur->next; // Remove matched and queued flags __sync_fetch_and_and(&cur->flags, ~(PROTO_EXPECTATION_FLAG_MATCHED | PROTO_EXPECTATION_FLAG_QUEUED)); struct proto_process_stack *s_next = &stack[stack_index + 1]; s_next->proto = cur->proto; if (conntrack_get_unique_from_parent(stack, stack_index + 1) != POM_OK) { proto_expectation_cleanup(cur); continue; } if (!s_next->ce->priv) { s_next->ce->priv = cur->priv; // Prevent cleanup of private data while cleaning the expectation cur->priv = NULL; } if (cur->session) { if (conntrack_session_bind(s_next->ce, cur->session)) { proto_expectation_cleanup(cur); continue; } } registry_perf_dec(cur->proto->perf_expt_pending, 1); registry_perf_inc(cur->proto->perf_expt_matched, 1); if (cur->match_callback) { // Call the callback with the conntrack locked cur->match_callback(cur, cur->callback_priv, s_next->ce); // Nullify callback_priv so it doesn't get cleaned up cur->callback_priv = NULL; } if (cur->expiry) { // The expectation was added using 'add_and_cleanup' function proto_expectation_cleanup(cur); } conntrack_unlock(s_next->ce); } pom_rwlock_unlock(&proto->expectation_lock); return res; }