[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/include/proto/proto_tcp.h b/include/proto/proto_tcp.h
index 37d8ea8..1b46d37 100644
--- a/include/proto/proto_tcp.h
+++ b/include/proto/proto_tcp.h
@@ -25,6 +25,7 @@
 #include <common/config.h>
 #include <types/proto_tcp.h>
 #include <types/task.h>
+#include <proto/stick_table.h>
 
 int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct sockaddr_in *remote);
 void tcpv4_add_listener(struct listener *listener);
@@ -37,6 +38,22 @@
 int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit);
 int tcp_exec_req_rules(struct session *s);
 
+/* Converts the TCPv4 source address to a stick_table key usable for table
+ * lookups. Returns either NULL if the source cannot be converted (eg: not
+ * IPv4) or a pointer to the converted result in static_table_key in the
+ * appropriate format (IP).
+ */
+static inline struct stktable_key *tcpv4_src_to_stktable_key(struct session *s)
+{
+	/* right now we only support IPv4 */
+	if (s->cli_addr.ss_family != AF_INET)
+		return NULL;
+
+	static_table_key.key = (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr;
+	return &static_table_key;
+}
+
+
 #endif /* _PROTO_PROTO_TCP_H */
 
 /*
diff --git a/include/proto/session.h b/include/proto/session.h
index c7a693e..3d56f8e 100644
--- a/include/proto/session.h
+++ b/include/proto/session.h
@@ -25,6 +25,7 @@
 #include <common/config.h>
 #include <common/memory.h>
 #include <types/session.h>
+#include <proto/stick_table.h>
 
 extern struct pool_head *pool2_session;
 extern struct list sessions;
@@ -40,6 +41,31 @@
 struct task *process_session(struct task *t);
 void sess_set_term_flags(struct session *s);
 void default_srv_error(struct session *s, struct stream_interface *si);
+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);
+
+/* Remove the refcount from the session to the tracked counters, and clear the
+ * pointer to ensure this is only performed once. The caller is responsible for
+ * ensuring that the pointer is valid first.
+ */
+static inline void session_store_counters(struct session *s)
+{
+	s->tracked_counters->ref_cnt--;
+	s->tracked_counters = NULL;
+}
+
+/* Enable tracking of session counters on stksess <ts>. The caller is
+ * responsible for ensuring that <t> and <ts> are valid pointers and that no
+ * previous tracked_counters was assigned to the session.
+ */
+static inline void session_track_counters(struct session *s, struct stktable *t, struct stksess *ts)
+{
+	ts->ref_cnt++;
+	s->tracked_table = t;
+	s->tracked_counters = ts;
+}
 
 static void inline trace_term(struct session *s, unsigned int code)
 {
diff --git a/include/proto/stick_table.h b/include/proto/stick_table.h
index db45760..813b3b9 100644
--- a/include/proto/stick_table.h
+++ b/include/proto/stick_table.h
@@ -36,6 +36,7 @@
 
 int stktable_init(struct stktable *t);
 int stktable_parse_type(char **args, int *idx, unsigned long *type, size_t *key_size);
+struct stksess *stktable_get_entry(struct stktable *table, struct stktable_key *key);
 struct stksess *stktable_store(struct stktable *t, struct stksess *ts);
 struct stksess *stktable_touch(struct stktable *t, struct stksess *ts);
 struct stksess *stktable_lookup(struct stktable *t, struct stksess *ts);