Esempio n. 1
0
gint
rspamd_symbols_cache_add_symbol (struct symbols_cache *cache,
	const gchar *name,
	double weight,
	gint priority,
	symbol_func_t func,
	gpointer user_data,
	enum rspamd_symbol_type type,
	gint parent)
{
	struct cache_item *item = NULL;

	g_assert (cache != NULL);

	if (name == NULL && type != SYMBOL_TYPE_CALLBACK) {
		msg_warn ("no name for non-callback symbol!");
	}
	else if (type == SYMBOL_TYPE_VIRTUAL && parent == -1) {
		msg_warn ("no parent symbol is associated with virtual symbol %s",
			name);
	}

	if (name != NULL) {
		if (g_hash_table_lookup (cache->items_by_symbol, name) != NULL) {
			msg_err ("skip duplicate symbol registration for %s", name);
			return -1;
		}
	}

	item = rspamd_mempool_alloc0_shared (cache->static_pool,
			sizeof (struct cache_item));
	/*
	 * We do not share cd to skip locking, instead we'll just calculate it on
	 * save or accumulate
	 */
	item->cd = rspamd_mempool_alloc0 (cache->static_pool,
			sizeof (struct counter_data));

	if (name != NULL) {
		item->symbol = rspamd_mempool_strdup (cache->static_pool, name);
	}

	item->func = func;
	item->user_data = user_data;
	item->priority = priority;
	item->type = type;
	item->weight = weight;

	if (item->weight < 0 && item->priority == 0) {
		/* Make priority for negative weighted symbols */
		item->priority = 1;
	}

	item->id = cache->used_items;
	item->parent = parent;
	cache->used_items ++;
	msg_debug ("used items: %d, added symbol: %s", cache->used_items, name);
	rspamd_set_counter (item, 0);
	g_ptr_array_add (cache->items_by_id, item);
	g_ptr_array_add (cache->items_by_order, item);
	item->deps = g_ptr_array_new ();
	item->rdeps = g_ptr_array_new ();
	rspamd_mempool_add_destructor (cache->static_pool,
			rspamd_ptr_array_free_hard, item->deps);
	rspamd_mempool_add_destructor (cache->static_pool,
			rspamd_ptr_array_free_hard, item->rdeps);

	if (name != NULL) {
		g_hash_table_insert (cache->items_by_symbol, item->symbol, item);
	}

	return item->id;
}
Esempio n. 2
0
static gboolean
rspamd_symbols_cache_check_symbol (struct rspamd_task *task,
		struct symbols_cache *cache,
		struct cache_item *item,
		struct cache_savepoint *checkpoint,
		gdouble *total_diff)
{
	guint pending_before, pending_after;
	double t1, t2;
	gdouble diff;
	struct rspamd_task **ptask;
	lua_State *L;
	gboolean check = TRUE;
	const gdouble slow_diff_limit = 1e5;

	if (item->type & (SYMBOL_TYPE_NORMAL|SYMBOL_TYPE_CALLBACK)) {

		g_assert (item->func != NULL);
		/* Check has been started */
		setbit (checkpoint->processed_bits, item->id * 2);

		if (RSPAMD_TASK_IS_EMPTY (task) && !(item->type & SYMBOL_TYPE_EMPTY)) {
			check = FALSE;
		}
		else if (item->condition_cb != -1) {
			/* We also executes condition callback to check if we need this symbol */
			L = task->cfg->lua_state;
			lua_rawgeti (L, LUA_REGISTRYINDEX, item->condition_cb);
			ptask = lua_newuserdata (L, sizeof (struct rspamd_task *));
			rspamd_lua_setclass (L, "rspamd{task}", -1);
			*ptask = task;

			if (lua_pcall (L, 1, 1, 0) != 0) {
				msg_info_task ("call to condition for %s failed: %s",
						item->symbol, lua_tostring (L, -1));
				lua_pop (L, 1);
			}
			else {
				check = lua_toboolean (L, -1);
				lua_pop (L, 1);
			}
		}

		if (check) {
			t1 = rspamd_get_ticks ();
			pending_before = rspamd_session_events_pending (task->s);
			/* Watch for events appeared */
			rspamd_session_watch_start (task->s, rspamd_symbols_cache_watcher_cb,
					item);

			msg_debug_task ("execute %s, %d", item->symbol, item->id);
			item->func (task, item->user_data);

			t2 = rspamd_get_ticks ();
			diff = (t2 - t1) * 1e6;

			if (total_diff) {
				*total_diff += diff;
			}

			if (diff > slow_diff_limit) {
				msg_info_task ("slow rule: %s: %d ms", item->symbol,
						(gint)(diff / 1000.));
			}

			rspamd_set_counter (item, diff);
			rspamd_session_watch_stop (task->s);
			pending_after = rspamd_session_events_pending (task->s);

			if (pending_before == pending_after) {
				/* No new events registered */
				setbit (checkpoint->processed_bits, item->id * 2 + 1);

				return TRUE;
			}

			return FALSE;
		}
		else {
			msg_debug_task ("skipping check of %s as its condition is false",
					item->symbol);
			setbit (checkpoint->processed_bits, item->id * 2 + 1);

			return TRUE;
		}
	}
	else {
		setbit (checkpoint->processed_bits, item->id * 2);
		setbit (checkpoint->processed_bits, item->id * 2 + 1);

		return TRUE;
	}
}