[MAJOR] session: add track-counters to track counters related to the session

This patch adds the ability to set a pointer in the session to an
entry in a stick table which holds various counters related to a
specific pattern.

Right now the syntax matches the target syntax and only the "src"
pattern can be specified, to track counters related to the session's
IPv4 source address. There is a special function to extract it and
convert it to a key. But the goal is to be able to later support as
many patterns as for the stick rules, and get rid of the specific
function.

The "track-counters" directive may only be set in a "tcp-request"
statement right now. Only the first one applies. Probably that later
we'll support multi-criteria tracking for a single session and that
we'll have to name tracking pointers.

No counter is updated right now, only the refcount is. Some subsequent
patches will have to bring that feature.
diff --git a/src/session.c b/src/session.c
index 96933d3..4e2bedd 100644
--- a/src/session.c
+++ b/src/session.c
@@ -63,6 +63,8 @@
 	/* minimum session initialization required for monitor mode below */
 	s->flags = 0;
 	s->logs.logwait = p->to_log;
+	s->tracked_counters = NULL;
+	s->tracked_table = NULL;
 
 	/* if this session comes from a known monitoring system, we want to ignore
 	 * it as soon as possible, which means closing it immediately for TCP, but
@@ -117,6 +119,8 @@
 	 * even initializing the stream interfaces.
 	 */
 	if ((l->options & LI_O_TCP_RULES) && !tcp_exec_req_rules(s)) {
+		if (s->tracked_counters)
+			session_store_counters(s);
 		task_free(t);
 		LIST_DEL(&s->list);
 		pool_free2(pool2_session, s);
@@ -176,7 +180,6 @@
 
 	/* init store persistence */
 	s->store_count = 0;
-	s->tracked_src_counters = NULL;
 
 	/* Adjust some socket options */
 	if (unlikely(fcntl(cfd, F_SETFL, O_NONBLOCK) == -1)) {
@@ -257,6 +260,8 @@
 			/* work is finished, we can release everything (eg: monitoring) */
 			pool_free2(pool2_buffer, s->rep);
 			pool_free2(pool2_buffer, s->req);
+			if (s->tracked_counters)
+				session_store_counters(s);
 			task_free(t);
 			LIST_DEL(&s->list);
 			pool_free2(pool2_session, s);
@@ -279,6 +284,8 @@
 	pool_free2(pool2_buffer, s->req);
  out_free_task:
 	p->feconn--;
+	if (s->tracked_counters)
+		session_store_counters(s);
 	task_free(t);
  out_free_session:
 	LIST_DEL(&s->list);
@@ -341,6 +348,9 @@
 		pool_free2(fe->req_cap_pool, txn->req.cap);
 	}
 
+	if (s->tracked_counters)
+		session_store_counters(s);
+
 	list_for_each_entry_safe(bref, back, &s->back_refs, users) {
 		/* we have to unlink all watchers. We must not relink them if
 		 * this session was the last one in the list.
@@ -2040,6 +2050,56 @@
 		s->flags |= fin;
 }
 
+
+/* Parse a "track-counters" line starting with "track-counters" in args[arg-1].
+ * Returns the number of warnings emitted, or -1 in case of fatal errors. The
+ * <prm> struct is fed with the table name if any. If unspecified, the caller
+ * will assume that the current proxy's table is used.
+ */
+int parse_track_counters(char **args, int *arg,
+			 int section_type, struct proxy *curpx,
+			 struct track_ctr_prm *prm,
+			 struct proxy *defpx, char *err, int errlen)
+{
+	int pattern_type = 0;
+
+	/* parse the arguments of "track-counters" before the condition in the
+	 * following form :
+	 *      track-counters src [ table xxx ] [ if|unless ... ]
+	 */
+	while (args[*arg]) {
+		if (strcmp(args[*arg], "src") == 0) {
+			prm->type = STKTABLE_TYPE_IP;
+			pattern_type = 1;
+		}
+		else if (strcmp(args[*arg], "table") == 0) {
+			if (!args[*arg + 1]) {
+				snprintf(err, errlen,
+					 "missing table for track-counter in %s '%s'.",
+					 proxy_type_str(curpx), curpx->id);
+				return -1;
+			}
+			/* we copy the table name for now, it will be resolved later */
+			prm->table.n = strdup(args[*arg + 1]);
+			(*arg)++;
+		}
+		else {
+			/* unhandled keywords are handled by the caller */
+			break;
+		}
+		(*arg)++;
+	}
+
+	if (!pattern_type) {
+		snprintf(err, errlen,
+			 "track-counter key not specified in %s '%s' (found %s, only 'src' is supported).",
+			 proxy_type_str(curpx), curpx->id, quote_arg(args[*arg]));
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * Local variables:
  *  c-indent-level: 8