MEDIUM: streams: support looking up stkctr in the session

In order to support sessions tracking counters, we first ensure that there
is no overlap between streams' stkctr and sessions', and we allow an
automatic lookup into the session's counters when the stream doesn't
have a counter or when the stream doesn't exist during an access via
a sample fetch. The functions used to update the stream counters only
update them and not the session counters however.
diff --git a/src/stream.c b/src/stream.c
index e21a2a5..7f2f27a 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -454,18 +454,19 @@
 
 	for (i = 0; i < MAX_SESS_STKCTR; i++) {
 		void *ptr;
+		struct stkctr *stkctr = &sess->stkctr[i];
 
-		if (!stkctr_entry(&s->stkctr[i]))
+		if (!stkctr_entry(stkctr))
 			continue;
 
-		ptr = stktable_data_ptr(s->stkctr[i].table, stkctr_entry(&s->stkctr[i]), STKTABLE_DT_SESS_CNT);
+		ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_CNT);
 		if (ptr)
 			stktable_data_cast(ptr, sess_cnt)++;
 
-		ptr = stktable_data_ptr(s->stkctr[i].table, stkctr_entry(&s->stkctr[i]), STKTABLE_DT_SESS_RATE);
+		ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_SESS_RATE);
 		if (ptr)
 			update_freq_ctr_period(&stktable_data_cast(ptr, sess_rate),
-					       s->stkctr[i].table->data_arg[STKTABLE_DT_SESS_RATE].u, 1);
+					       stkctr->table->data_arg[STKTABLE_DT_SESS_RATE].u, 1);
 	}
 
 	/* this part should be common with other protocols */
@@ -807,21 +808,22 @@
 			sess->listener->counters->bytes_in += bytes;
 
 		for (i = 0; i < MAX_SESS_STKCTR; i++) {
-			if (!stkctr_entry(&s->stkctr[i]))
-				continue;
+			struct stkctr *stkctr = &s->stkctr[i];
+
+			if (!stkctr_entry(stkctr)) {
+				stkctr = &sess->stkctr[i];
+				if (!stkctr_entry(stkctr))
+					continue;
+			}
 
-			ptr = stktable_data_ptr(s->stkctr[i].table,
-						stkctr_entry(&s->stkctr[i]),
-						STKTABLE_DT_BYTES_IN_CNT);
+			ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_CNT);
 			if (ptr)
 				stktable_data_cast(ptr, bytes_in_cnt) += bytes;
 
-			ptr = stktable_data_ptr(s->stkctr[i].table,
-						stkctr_entry(&s->stkctr[i]),
-						STKTABLE_DT_BYTES_IN_RATE);
+			ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_IN_RATE);
 			if (ptr)
 				update_freq_ctr_period(&stktable_data_cast(ptr, bytes_in_rate),
-						       s->stkctr[i].table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u, bytes);
+						       stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u, bytes);
 		}
 	}
 
@@ -839,21 +841,22 @@
 			sess->listener->counters->bytes_out += bytes;
 
 		for (i = 0; i < MAX_SESS_STKCTR; i++) {
-			if (!stkctr_entry(&s->stkctr[i]))
-				continue;
+			struct stkctr *stkctr = &s->stkctr[i];
+
+			if (!stkctr_entry(stkctr)) {
+				stkctr = &sess->stkctr[i];
+				if (!stkctr_entry(stkctr))
+					continue;
+			}
 
-			ptr = stktable_data_ptr(s->stkctr[i].table,
-						stkctr_entry(&s->stkctr[i]),
-						STKTABLE_DT_BYTES_OUT_CNT);
+			ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_CNT);
 			if (ptr)
 				stktable_data_cast(ptr, bytes_out_cnt) += bytes;
 
-			ptr = stktable_data_ptr(s->stkctr[i].table,
-						stkctr_entry(&s->stkctr[i]),
-						STKTABLE_DT_BYTES_OUT_RATE);
+			ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_BYTES_OUT_RATE);
 			if (ptr)
 				update_freq_ctr_period(&stktable_data_cast(ptr, bytes_out_rate),
-						       s->stkctr[i].table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u, bytes);
+						       stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u, bytes);
 		}
 	}
 }
@@ -2890,12 +2893,14 @@
  * passed. When present, the currently tracked key is then looked up
  * in the specified table instead of the current table. The purpose is
  * to be able to convery multiple values per key (eg: have gpc0 from
- * multiple tables).
+ * multiple tables). <strm> is allowed to be NULL, in which case only
+ * the session will be consulted.
  */
 struct stkctr *
 smp_fetch_sc_stkctr(struct session *sess, struct stream *strm, const struct arg *args, const char *kw)
 {
 	static struct stkctr stkctr;
+	struct stkctr *stkptr;
 	struct stksess *stksess;
 	unsigned int num = kw[2] - '0';
 	int arg = 0;
@@ -2924,9 +2929,18 @@
 
 	/* Here, <num> contains the counter number from 0 to 9 for
 	 * the sc[0-9]_ form, or even higher using sc_(num) if needed.
-	 * args[arg] is the first optional argument.
+	 * args[arg] is the first optional argument. We first lookup the
+	 * ctr form the stream, then from the session if it was not there.
 	 */
-	stksess = stkctr_entry(&strm->stkctr[num]);
+
+	stkptr = &strm->stkctr[num];
+	if (!strm || !stkctr_entry(stkptr)) {
+		stkptr = &sess->stkctr[num];
+		if (!stkctr_entry(stkptr))
+			return NULL;
+	}
+
+	stksess = stkctr_entry(stkptr);
 	if (!stksess)
 		return NULL;
 
@@ -2936,7 +2950,7 @@
 		stkctr_set_entry(&stkctr, stktable_lookup(stkctr.table, stksess));
 		return &stkctr;
 	}
-	return &strm->stkctr[num];
+	return stkptr;
 }
 
 /* set return a boolean indicating if the requested stream counter is