CONTRIB: spoa_example: allow to compile outside HAProxy.

Don't include haproxy's includes anymore and use a local copy instead.
diff --git a/contrib/spoa_example/Makefile b/contrib/spoa_example/Makefile
index 3105ef0..d04a01e 100644
--- a/contrib/spoa_example/Makefile
+++ b/contrib/spoa_example/Makefile
@@ -6,8 +6,8 @@
 LD = $(CC)
 
 CFLAGS  = -g -O2 -Wall -Werror -pthread
-LDFLAGS = -lpthread  -levent -levent_pthreads
-INCS += -I../../include -I../../ebtree
+LDFLAGS = -lpthread -levent -levent_pthreads
+INCS += -I../../ebtree -I./include
 LIBS =
 
 OBJS = spoa.o
diff --git a/contrib/spoa_example/include/mini-clist.h b/contrib/spoa_example/include/mini-clist.h
new file mode 100644
index 0000000..56fb28d
--- /dev/null
+++ b/contrib/spoa_example/include/mini-clist.h
@@ -0,0 +1,122 @@
+#ifndef _COMMON_MINI_CLIST_H
+#define _COMMON_MINI_CLIST_H
+
+/* these are circular or bidirectionnal lists only. Each list pointer points to
+ * another list pointer in a structure, and not the structure itself. The
+ * pointer to the next element MUST be the first one so that the list is easily
+ * cast as a single linked list or pointer.
+ */
+struct list {
+    struct list *n;	/* next */
+    struct list *p;	/* prev */
+};
+
+/* a back-ref is a pointer to a target list entry. It is used to detect when an
+ * element being deleted is currently being tracked by another user. The best
+ * example is a user dumping the session table. The table does not fit in the
+ * output buffer so we have to set a mark on a session and go on later. But if
+ * that marked session gets deleted, we don't want the user's pointer to go in
+ * the wild. So we can simply link this user's request to the list of this
+ * session's users, and put a pointer to the list element in ref, that will be
+ * used as the mark for next iteration.
+ */
+struct bref {
+	struct list users;
+	struct list *ref; /* pointer to the target's list entry */
+};
+
+/* a word list is a generic list with a pointer to a string in each element. */
+struct wordlist {
+	struct list list;
+	char *s;
+};
+
+/* this is the same as above with an additional pointer to a condition. */
+struct cond_wordlist {
+	struct list list;
+	void *cond;
+	char *s;
+};
+
+/* First undefine some macros which happen to also be defined on OpenBSD,
+ * in sys/queue.h, used by sys/event.h
+ */
+#undef LIST_HEAD
+#undef LIST_INIT
+#undef LIST_NEXT
+
+/* ILH = Initialized List Head : used to prevent gcc from moving an empty
+ * list to BSS. Some older version tend to trim all the array and cause
+ * corruption.
+ */
+#define ILH		{ .n = (struct list *)1, .p = (struct list *)2 }
+
+#define LIST_HEAD(a)	((void *)(&(a)))
+
+#define LIST_INIT(l) ((l)->n = (l)->p = (l))
+
+#define LIST_HEAD_INIT(l) { &l, &l }
+
+/* adds an element at the beginning of a list ; returns the element */
+#define LIST_ADD(lh, el) ({ (el)->n = (lh)->n; (el)->n->p = (lh)->n = (el); (el)->p = (lh); (el); })
+
+/* adds an element at the end of a list ; returns the element */
+#define LIST_ADDQ(lh, el) ({ (el)->p = (lh)->p; (el)->p->n = (lh)->p = (el); (el)->n = (lh); (el); })
+
+/* removes an element from a list and returns it */
+#define LIST_DEL(el) ({ typeof(el) __ret = (el); (el)->n->p = (el)->p; (el)->p->n = (el)->n; (__ret); })
+
+/* returns a pointer of type <pt> to a structure containing a list head called
+ * <el> at address <lh>. Note that <lh> can be the result of a function or macro
+ * since it's used only once.
+ * Example: LIST_ELEM(cur_node->args.next, struct node *, args)
+ */
+#define LIST_ELEM(lh, pt, el) ((pt)(((void *)(lh)) - ((void *)&((pt)NULL)->el)))
+
+/* checks if the list head <lh> is empty or not */
+#define LIST_ISEMPTY(lh) ((lh)->n == (lh))
+
+/* returns a pointer of type <pt> to a structure following the element
+ * which contains list head <lh>, which is known as element <el> in
+ * struct pt.
+ * Example: LIST_NEXT(args, struct node *, list)
+ */
+#define LIST_NEXT(lh, pt, el) (LIST_ELEM((lh)->n, pt, el))
+
+
+/* returns a pointer of type <pt> to a structure preceeding the element
+ * which contains list head <lh>, which is known as element <el> in
+ * struct pt.
+ */
+#undef LIST_PREV
+#define LIST_PREV(lh, pt, el) (LIST_ELEM((lh)->p, pt, el))
+
+/*
+ * Simpler FOREACH_ITEM macro inspired from Linux sources.
+ * Iterates <item> through a list of items of type "typeof(*item)" which are
+ * linked via a "struct list" member named <member>. A pointer to the head of
+ * the list is passed in <list_head>. No temporary variable is needed. Note
+ * that <item> must not be modified during the loop.
+ * Example: list_for_each_entry(cur_acl, known_acl, list) { ... };
+ */ 
+#define list_for_each_entry(item, list_head, member)                      \
+	for (item = LIST_ELEM((list_head)->n, typeof(item), member);     \
+	     &item->member != (list_head);                                \
+	     item = LIST_ELEM(item->member.n, typeof(item), member))
+
+/*
+ * Simpler FOREACH_ITEM_SAFE macro inspired from Linux sources.
+ * Iterates <item> through a list of items of type "typeof(*item)" which are
+ * linked via a "struct list" member named <member>. A pointer to the head of
+ * the list is passed in <list_head>. A temporary variable <back> of same type
+ * as <item> is needed so that <item> may safely be deleted if needed.
+ * Example: list_for_each_entry_safe(cur_acl, tmp, known_acl, list) { ... };
+ */ 
+#define list_for_each_entry_safe(item, back, list_head, member)           \
+	for (item = LIST_ELEM((list_head)->n, typeof(item), member),     \
+	     back = LIST_ELEM(item->member.n, typeof(item), member);     \
+	     &item->member != (list_head);                                \
+	     item = back, back = LIST_ELEM(back->member.n, typeof(back), member))
+
+
+#endif /* _COMMON_MINI_CLIST_H */
diff --git a/contrib/spoa_example/include/mini-sample.h b/contrib/spoa_example/include/mini-sample.h
new file mode 100644
index 0000000..96012c7
--- /dev/null
+++ b/contrib/spoa_example/include/mini-sample.h
@@ -0,0 +1,50 @@
+#ifndef _MINI_SAMPLE_H
+#define _MINI_SAMPLE_H
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+/* input and output sample types */
+enum {
+	SMP_T_ANY = 0,   /* any type */
+	SMP_T_BOOL,      /* boolean */
+	SMP_T_SINT,      /* signed 64bits integer type */
+	SMP_T_ADDR,      /* ipv4 or ipv6, only used for input type compatibility */
+	SMP_T_IPV4,      /* ipv4 type */
+	SMP_T_IPV6,      /* ipv6 type */
+	SMP_T_STR,       /* char string type */
+	SMP_T_BIN,       /* buffer type */
+	SMP_T_METH,      /* contain method */
+	SMP_TYPES        /* number of types, must always be last */
+};
+
+/* describes a chunk of string */
+struct chunk {
+	char *str;	/* beginning of the string itself. Might not be 0-terminated */
+	int size;	/* total size of the buffer, 0 if the *str is read-only */
+	int len;	/* current size of the string from first to last char. <0 = uninit. */
+};
+
+union sample_value {
+	long long int   sint;  /* used for signed 64bits integers */
+	struct in_addr  ipv4;  /* used for ipv4 addresses */
+	struct in6_addr ipv6;  /* used for ipv6 addresses */
+	struct chunk    str;   /* used for char strings or buffers */
+	//struct meth     meth;  /* used for http method */
+};
+
+/* Used to store sample constant */
+struct sample_data {
+	int type;                 /* SMP_T_* */
+	union sample_value u;     /* sample data */
+};
+
+/* a sample is a typed data extracted from a stream. It has a type, contents,
+ * validity constraints, a context for use in iterative calls.
+ */
+struct sample {
+	struct sample_data data;
+};
+#endif
+
diff --git a/contrib/spoa_example/include/spoe_types.h b/contrib/spoa_example/include/spoe_types.h
new file mode 100644
index 0000000..b5abf39
--- /dev/null
+++ b/contrib/spoa_example/include/spoe_types.h
@@ -0,0 +1,230 @@
+/*
+ * include/spoe_types.h
+ * Macros, variables and structures for the SPOE filter.
+ *
+ * Copyright (C) 2017 HAProxy Technologies, Christopher Faulet <cfaulet@haproxy.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _SPOE_TYPES_H
+#define _SPOE_TYPES_H
+
+#include <mini-clist.h>
+
+// Taken from HAProxy's defaults.h
+/* Maximum host name length */
+#ifndef MAX_HOSTNAME_LEN
+#if MAXHOSTNAMELEN
+#define MAX_HOSTNAME_LEN	MAXHOSTNAMELEN
+#else
+#define MAX_HOSTNAME_LEN	64
+#endif // MAXHOSTNAMELEN
+#endif // MAX_HOSTNAME_LEN
+
+/* Flags set on the SPOE agent */
+#define SPOE_FL_CONT_ON_ERR       0x00000001 /* Do not stop events processing when an error occurred */
+#define SPOE_FL_PIPELINING        0x00000002 /* Set when SPOE agent supports pipelining (set by default) */
+#define SPOE_FL_ASYNC             0x00000004 /* Set when SPOE agent supports async (set by default) */
+#define SPOE_FL_SND_FRAGMENTATION 0x00000008 /* Set when SPOE agent supports sending fragmented payload */
+#define SPOE_FL_RCV_FRAGMENTATION 0x00000010 /* Set when SPOE agent supports receiving fragmented payload */
+
+/* Flags set on the SPOE context */
+#define SPOE_CTX_FL_CLI_CONNECTED 0x00000001 /* Set after that on-client-session event was processed */
+#define SPOE_CTX_FL_SRV_CONNECTED 0x00000002 /* Set after that on-server-session event was processed */
+#define SPOE_CTX_FL_REQ_PROCESS   0x00000004 /* Set when SPOE is processing the request */
+#define SPOE_CTX_FL_RSP_PROCESS   0x00000008 /* Set when SPOE is processing the response */
+#define SPOE_CTX_FL_FRAGMENTED    0x00000010 /* Set when a fragmented frame is processing */
+
+#define SPOE_CTX_FL_PROCESS (SPOE_CTX_FL_REQ_PROCESS|SPOE_CTX_FL_RSP_PROCESS)
+
+/* Flags set on the SPOE applet */
+#define SPOE_APPCTX_FL_PIPELINING    0x00000001 /* Set if pipelining is supported */
+#define SPOE_APPCTX_FL_ASYNC         0x00000002 /* Set if asynchronus frames is supported */
+#define SPOE_APPCTX_FL_FRAGMENTATION 0x00000004 /* Set if fragmentation is supported */
+#define SPOE_APPCTX_FL_PERSIST       0x00000008 /* Set if the applet is persistent */
+
+#define SPOE_APPCTX_ERR_NONE    0x00000000 /* no error yet, leave it to zero */
+#define SPOE_APPCTX_ERR_TOUT    0x00000001 /* SPOE applet timeout */
+
+/* Flags set on the SPOE frame */
+#define SPOE_FRM_FL_FIN         0x00000001
+#define SPOE_FRM_FL_ABRT        0x00000002
+
+/* All possible states for a SPOE context */
+enum spoe_ctx_state {
+	SPOE_CTX_ST_NONE = 0,
+	SPOE_CTX_ST_READY,
+	SPOE_CTX_ST_ENCODING_MSGS,
+	SPOE_CTX_ST_SENDING_MSGS,
+	SPOE_CTX_ST_WAITING_ACK,
+	SPOE_CTX_ST_DONE,
+	SPOE_CTX_ST_ERROR,
+};
+
+/* All possible states for a SPOE applet */
+enum spoe_appctx_state {
+	SPOE_APPCTX_ST_CONNECT = 0,
+	SPOE_APPCTX_ST_CONNECTING,
+	SPOE_APPCTX_ST_IDLE,
+	SPOE_APPCTX_ST_PROCESSING,
+	SPOE_APPCTX_ST_SENDING_FRAG_NOTIFY,
+	SPOE_APPCTX_ST_WAITING_SYNC_ACK,
+	SPOE_APPCTX_ST_DISCONNECT,
+	SPOE_APPCTX_ST_DISCONNECTING,
+	SPOE_APPCTX_ST_EXIT,
+	SPOE_APPCTX_ST_END,
+};
+
+/* All supported SPOE actions */
+enum spoe_action_type {
+	SPOE_ACT_T_SET_VAR = 1,
+	SPOE_ACT_T_UNSET_VAR,
+	SPOE_ACT_TYPES,
+};
+
+/* All supported SPOE events */
+enum spoe_event {
+	SPOE_EV_NONE = 0,
+
+	/* Request events */
+	SPOE_EV_ON_CLIENT_SESS = 1,
+	SPOE_EV_ON_TCP_REQ_FE,
+	SPOE_EV_ON_TCP_REQ_BE,
+	SPOE_EV_ON_HTTP_REQ_FE,
+	SPOE_EV_ON_HTTP_REQ_BE,
+
+	/* Response events */
+	SPOE_EV_ON_SERVER_SESS,
+	SPOE_EV_ON_TCP_RSP,
+	SPOE_EV_ON_HTTP_RSP,
+
+	SPOE_EV_EVENTS
+};
+
+/* Errors triggered by streams */
+enum spoe_context_error {
+	SPOE_CTX_ERR_NONE = 0,
+	SPOE_CTX_ERR_TOUT,
+	SPOE_CTX_ERR_RES,
+	SPOE_CTX_ERR_TOO_BIG,
+	SPOE_CTX_ERR_FRAG_FRAME_ABRT,
+	SPOE_CTX_ERR_UNKNOWN = 255,
+	SPOE_CTX_ERRS,
+};
+
+/* Errors triggerd by SPOE applet */
+enum spoe_frame_error {
+	SPOE_FRM_ERR_NONE = 0,
+	SPOE_FRM_ERR_IO,
+	SPOE_FRM_ERR_TOUT,
+	SPOE_FRM_ERR_TOO_BIG,
+	SPOE_FRM_ERR_INVALID,
+	SPOE_FRM_ERR_NO_VSN,
+	SPOE_FRM_ERR_NO_FRAME_SIZE,
+	SPOE_FRM_ERR_NO_CAP,
+	SPOE_FRM_ERR_BAD_VSN,
+	SPOE_FRM_ERR_BAD_FRAME_SIZE,
+	SPOE_FRM_ERR_FRAG_NOT_SUPPORTED,
+	SPOE_FRM_ERR_INTERLACED_FRAMES,
+	SPOE_FRM_ERR_FRAMEID_NOTFOUND,
+	SPOE_FRM_ERR_RES,
+	SPOE_FRM_ERR_UNKNOWN = 99,
+	SPOE_FRM_ERRS,
+};
+
+/* Scopes used for variables set by agents. It is a way to be agnotic to vars
+ * scope. */
+enum spoe_vars_scope {
+	SPOE_SCOPE_PROC = 0, /* <=> SCOPE_PROC  */
+	SPOE_SCOPE_SESS,     /* <=> SCOPE_SESS */
+	SPOE_SCOPE_TXN,      /* <=> SCOPE_TXN  */
+	SPOE_SCOPE_REQ,      /* <=> SCOPE_REQ  */
+	SPOE_SCOPE_RES,      /* <=> SCOPE_RES  */
+};
+
+
+/* Describe an argument that will be linked to a message. It is a sample fetch,
+ * with an optional name. */
+struct spoe_arg {
+	char               *name;     /* Name of the argument, may be NULL */
+	unsigned int        name_len; /* The name length, 0 if NULL */
+	struct sample_expr *expr;     /* Sample expression */
+	struct list         list;     /* Used to chain SPOE args */
+};
+
+/* Used during the config parsing only because, when a SPOE agent section is
+ * parsed, messages can be undefined. */
+struct spoe_msg_placeholder {
+	char       *id;    /* SPOE message placeholder id */
+	struct list list;  /* Use to chain SPOE message placeholders */
+};
+
+/* Describe a message that will be sent in a NOTIFY frame. A message has a name,
+ * an argument list (see above) and it is linked to a specific event. */
+struct spoe_message {
+	char              *id;      /* SPOE message id */
+	unsigned int       id_len;  /* The message id length */
+	struct spoe_agent *agent;   /* SPOE agent owning this SPOE message */
+        struct {
+                char      *file;    /* file where the SPOE message appears */
+                int        line;    /* line where the SPOE message appears */
+        } conf;                     /* config information */
+	unsigned int       nargs;   /* # of arguments */
+	struct list        args;    /* Arguments added when the SPOE messages is sent */
+	struct list        list;    /* Used to chain SPOE messages */
+
+	enum spoe_event    event;   /* SPOE_EV_* */
+};
+
+enum spoe_frame_type {
+	SPOE_FRM_T_UNSET = 0,
+
+	/* Frames sent by HAProxy */
+	SPOE_FRM_T_HAPROXY_HELLO = 1,
+	SPOE_FRM_T_HAPROXY_DISCON,
+	SPOE_FRM_T_HAPROXY_NOTIFY,
+
+	/* Frames sent by the agents */
+	SPOE_FRM_T_AGENT_HELLO = 101,
+	SPOE_FRM_T_AGENT_DISCON,
+	SPOE_FRM_T_AGENT_ACK
+};
+
+/* All supported data types */
+enum spoe_data_type {
+	SPOE_DATA_T_NULL = 0,
+	SPOE_DATA_T_BOOL,
+	SPOE_DATA_T_INT32,
+	SPOE_DATA_T_UINT32,
+	SPOE_DATA_T_INT64,
+	SPOE_DATA_T_UINT64,
+	SPOE_DATA_T_IPV4,
+	SPOE_DATA_T_IPV6,
+	SPOE_DATA_T_STR,
+	SPOE_DATA_T_BIN,
+	SPOE_DATA_TYPES
+};
+
+/* Masks to get data type or flags value */
+#define SPOE_DATA_T_MASK  0x0F
+#define SPOE_DATA_FL_MASK 0xF0
+
+/* Flags to set Boolean values */
+#define SPOE_DATA_FL_FALSE 0x00
+#define SPOE_DATA_FL_TRUE  0x10
+
+
+#endif /* _TYPES_SPOE_H */
diff --git a/contrib/spoa_example/include/spop_functions.h b/contrib/spoa_example/include/spop_functions.h
new file mode 100644
index 0000000..17011d0
--- /dev/null
+++ b/contrib/spoa_example/include/spop_functions.h
@@ -0,0 +1,413 @@
+#ifndef _SPOP_FUNCTIONS_H
+#define _SPOP_FUNCTIONS_H
+
+#include <stdint.h>
+#include <string.h>
+#include <spoe_types.h>
+#include <mini-sample.h>
+
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+
+/* Encode the integer <i> into a varint (variable-length integer). The encoded
+ * value is copied in <*buf>. Here is the encoding format:
+ *
+ *        0 <= X < 240        : 1 byte  (7.875 bits)  [ XXXX XXXX ]
+ *      240 <= X < 2288       : 2 bytes (11 bits)     [ 1111 XXXX ] [ 0XXX XXXX ]
+ *     2288 <= X < 264432     : 3 bytes (18 bits)     [ 1111 XXXX ] [ 1XXX XXXX ]   [ 0XXX XXXX ]
+ *   264432 <= X < 33818864   : 4 bytes (25 bits)     [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
+ * 33818864 <= X < 4328786160 : 5 bytes (32 bits)     [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
+ * ...
+ *
+ * On success, it returns the number of written bytes and <*buf> is moved after
+ * the encoded value. Otherwise, it returns -1. */
+static inline int
+encode_varint(uint64_t i, char **buf, char *end)
+{
+	unsigned char *p = (unsigned char *)*buf;
+	int r;
+
+	if (p >= (unsigned char *)end)
+		return -1;
+
+	if (i < 240) {
+		*p++ = i;
+		*buf = (char *)p;
+		return 1;
+	}
+
+	*p++ = (unsigned char)i | 240;
+	i = (i - 240) >> 4;
+	while (i >= 128) {
+		if (p >= (unsigned char *)end)
+			return -1;
+		*p++ = (unsigned char)i | 128;
+		i = (i - 128) >> 7;
+	}
+
+	if (p >= (unsigned char *)end)
+		return -1;
+	*p++ = (unsigned char)i;
+
+	r    = ((char *)p - *buf);
+	*buf = (char *)p;
+	return r;
+}
+
+/* Decode a varint from <*buf> and save the decoded value in <*i>. See
+ * 'spoe_encode_varint' for details about varint.
+ * On success, it returns the number of read bytes and <*buf> is moved after the
+ * varint. Otherwise, it returns -1. */
+static inline int
+decode_varint(char **buf, char *end, uint64_t *i)
+{
+	unsigned char *p = (unsigned char *)*buf;
+	int r;
+
+	if (p >= (unsigned char *)end)
+		return -1;
+
+	*i = *p++;
+	if (*i < 240) {
+		*buf = (char *)p;
+		return 1;
+	}
+
+	r = 4;
+	do {
+		if (p >= (unsigned char *)end)
+			return -1;
+		*i += (uint64_t)*p << r;
+		r  += 7;
+	} while (*p++ >= 128);
+
+	r    = ((char *)p - *buf);
+	*buf = (char *)p;
+	return r;
+}
+
+/* Encode a buffer. Its length <len> is encoded as a varint, followed by a copy
+ * of <str>. It must have enough space in <*buf> to encode the buffer, else an
+ * error is triggered.
+ * On success, it returns <len> and <*buf> is moved after the encoded value. If
+ * an error occurred, it returns -1. */
+static inline int
+spoe_encode_buffer(const char *str, size_t len, char **buf, char *end)
+{
+	char *p = *buf;
+	int   ret;
+
+	if (p >= end)
+		return -1;
+
+	if (!len) {
+		*p++ = 0;
+		*buf = p;
+		return 0;
+	}
+
+	ret = encode_varint(len, &p, end);
+	if (ret == -1 || p + len > end)
+		return -1;
+
+	memcpy(p, str, len);
+	*buf = p + len;
+	return len;
+}
+
+/* Encode a buffer, possibly partially. It does the same thing than
+ * 'spoe_encode_buffer', but if there is not enough space, it does not fail.
+ * On success, it returns the number of copied bytes and <*buf> is moved after
+ * the encoded value. If an error occured, it returns -1. */
+static inline int
+spoe_encode_frag_buffer(const char *str, size_t len, char **buf, char *end)
+{
+	char *p = *buf;
+	int   ret;
+
+	if (p >= end)
+		return -1;
+
+	if (!len) {
+		*p++ = 0;
+		*buf = p;
+		return 0;
+	}
+
+	ret = encode_varint(len, &p, end);
+	if (ret == -1 || p >= end)
+		return -1;
+
+	ret = (p+len < end) ? len : (end - p);
+	memcpy(p, str, ret);
+	*buf = p + ret;
+	return ret;
+}
+
+/* Decode a buffer. The buffer length is decoded and saved in <*len>. <*str>
+ * points on the first byte of the buffer.
+ * On success, it returns the buffer length and <*buf> is moved after the
+ * encoded buffer. Otherwise, it returns -1. */
+static inline int
+spoe_decode_buffer(char **buf, char *end, char **str, uint64_t *len)
+{
+	char    *p = *buf;
+	uint64_t sz;
+	int      ret;
+
+	*str = NULL;
+	*len = 0;
+
+	ret = decode_varint(&p, end, &sz);
+	if (ret == -1 || p + sz > end)
+		return -1;
+
+	*str = p;
+	*len = sz;
+	*buf = p + sz;
+	return sz;
+}
+
+/* Encode a typed data using value in <smp>. On success, it returns the number
+ * of copied bytes and <*buf> is moved after the encoded value. If an error
+ * occured, it returns -1.
+ *
+ * If the value is too big to be encoded, depending on its type, then encoding
+ * failed or the value is partially encoded. Only strings and binaries can be
+ * partially encoded. In this case, the offset <*off> is updated to known how
+ * many bytes has been encoded. If <*off> is zero at the end, it means that all
+ * data has been encoded. */
+static inline int
+spoe_encode_data(struct sample *smp, unsigned int *off, char **buf, char *end)
+{
+	char *p = *buf;
+	int   ret;
+
+	if (p >= end)
+		return -1;
+
+	if (smp == NULL) {
+		*p++ = SPOE_DATA_T_NULL;
+		goto end;
+	}
+
+	switch (smp->data.type) {
+		case SMP_T_BOOL:
+			*p    = SPOE_DATA_T_BOOL;
+			*p++ |= ((!smp->data.u.sint) ? SPOE_DATA_FL_FALSE : SPOE_DATA_FL_TRUE);
+			break;
+
+		case SMP_T_SINT:
+			*p++ = SPOE_DATA_T_INT64;
+			if (encode_varint(smp->data.u.sint, &p, end) == -1)
+				return -1;
+			break;
+
+		case SMP_T_IPV4:
+			if (p + 5 > end)
+				return -1;
+			*p++ = SPOE_DATA_T_IPV4;
+			memcpy(p, &smp->data.u.ipv4, 4);
+			p += 4;
+			break;
+
+		case SMP_T_IPV6:
+			if (p + 17 > end)
+				return -1;
+			*p++ = SPOE_DATA_T_IPV6;
+			memcpy(p, &smp->data.u.ipv6, 16);
+			p += 16;
+			break;
+
+		case SMP_T_STR:
+		case SMP_T_BIN: {
+			struct chunk *chk = &smp->data.u.str;
+
+			/* Here, we need to know if the sample has already been
+			 * partially encoded. If yes, we only need to encode the
+			 * remaining, <*off> reprensenting the number of bytes
+			 * already encoded. */
+			if (!*off) {
+				/* First evaluation of the sample : encode the
+				 * type (string or binary), the buffer length
+				 * (as a varint) and at least 1 byte of the
+				 * buffer. */
+				struct chunk *chk = &smp->data.u.str;
+
+				*p++ = (smp->data.type == SMP_T_STR)
+					? SPOE_DATA_T_STR
+					: SPOE_DATA_T_BIN;
+				ret = spoe_encode_frag_buffer(chk->str, chk->len, &p, end);
+				if (ret == -1)
+					return -1;
+			}
+			else {
+				/* The sample has been fragmented, encode remaining data */
+				ret = MIN(chk->len - *off, end - p);
+				memcpy(p, chk->str + *off, ret);
+				p += ret;
+			}
+			/* Now update <*off> */
+			if (ret + *off != chk->len)
+				*off += ret;
+			else
+				*off = 0;
+			break;
+		}
+		/*
+		case SMP_T_METH: {
+			char   *m;
+			size_t  len;
+
+			*p++ = SPOE_DATA_T_STR;
+			switch (smp->data.u.meth.meth) {
+				case HTTP_METH_OPTIONS: m = "OPTIONS"; len = 7; break;
+				case HTTP_METH_GET    : m = "GET";     len = 3; break;
+				case HTTP_METH_HEAD   : m = "HEAD";    len = 4; break;
+				case HTTP_METH_POST   : m = "POST";    len = 4; break;
+				case HTTP_METH_PUT    : m = "PUT";     len = 3; break;
+				case HTTP_METH_DELETE : m = "DELETE";  len = 6; break;
+				case HTTP_METH_TRACE  : m = "TRACE";   len = 5; break;
+				case HTTP_METH_CONNECT: m = "CONNECT"; len = 7; break;
+
+				default :
+					m   = smp->data.u.meth.str.str;
+					len = smp->data.u.meth.str.len;
+			}
+			if (spoe_encode_buffer(m, len, &p, end) == -1)
+				return -1;
+			break;
+		}
+		*/
+
+		default:
+			*p++ = SPOE_DATA_T_NULL;
+			break;
+	}
+
+  end:
+	ret  = (p - *buf);
+	*buf = p;
+	return ret;
+}
+
+/* Skip a typed data. If an error occurred, -1 is returned, otherwise the number
+ * of skipped bytes is returned and the <*buf> is moved after skipped data.
+ *
+ * A types data is composed of a type (1 byte) and corresponding data:
+ *  - boolean: non additional data (0 bytes)
+ *  - integers: a variable-length integer (see decode_varint)
+ *  - ipv4: 4 bytes
+ *  - ipv6: 16 bytes
+ *  - binary and string: a buffer prefixed by its size, a variable-length
+ *    integer (see spoe_decode_buffer) */
+static inline int
+spoe_skip_data(char **buf, char *end)
+{
+	char    *str, *p = *buf;
+	int      type, ret;
+	uint64_t v, sz;
+
+	if (p >= end)
+		return -1;
+
+	type = *p++;
+	switch (type & SPOE_DATA_T_MASK) {
+		case SPOE_DATA_T_BOOL:
+			break;
+		case SPOE_DATA_T_INT32:
+		case SPOE_DATA_T_INT64:
+		case SPOE_DATA_T_UINT32:
+		case SPOE_DATA_T_UINT64:
+			if (decode_varint(&p, end, &v) == -1)
+				return -1;
+			break;
+		case SPOE_DATA_T_IPV4:
+			if (p+4 > end)
+				return -1;
+			p += 4;
+			break;
+		case SPOE_DATA_T_IPV6:
+			if (p+16 > end)
+				return -1;
+			p += 16;
+			break;
+		case SPOE_DATA_T_STR:
+		case SPOE_DATA_T_BIN:
+			/* All the buffer must be skipped */
+			if (spoe_decode_buffer(&p, end, &str, &sz) == -1)
+				return -1;
+			break;
+	}
+
+	ret  = (p - *buf);
+	*buf = p;
+	return ret;
+}
+
+/* Decode a typed data and fill <smp>. If an error occurred, -1 is returned,
+ * otherwise the number of read bytes is returned and <*buf> is moved after the
+ * decoded data. See spoe_skip_data for details. */
+static inline int
+spoe_decode_data(char **buf, char *end, struct sample *smp)
+{
+	char  *str, *p = *buf;
+	int    type, r = 0;
+	uint64_t sz;
+
+	if (p >= end)
+		return -1;
+
+	type = *p++;
+	switch (type & SPOE_DATA_T_MASK) {
+		case SPOE_DATA_T_BOOL:
+			smp->data.u.sint = ((type & SPOE_DATA_FL_MASK) == SPOE_DATA_FL_TRUE);
+			smp->data.type = SMP_T_BOOL;
+			break;
+		case SPOE_DATA_T_INT32:
+		case SPOE_DATA_T_INT64:
+		case SPOE_DATA_T_UINT32:
+		case SPOE_DATA_T_UINT64:
+			if (decode_varint(&p, end, (uint64_t *)&smp->data.u.sint) == -1)
+				return -1;
+			smp->data.type = SMP_T_SINT;
+			break;
+		case SPOE_DATA_T_IPV4:
+			if (p+4 > end)
+				return -1;
+			smp->data.type = SMP_T_IPV4;
+			memcpy(&smp->data.u.ipv4, p, 4);
+			p += 4;
+			break;
+		case SPOE_DATA_T_IPV6:
+			if (p+16 > end)
+				return -1;
+			memcpy(&smp->data.u.ipv6, p, 16);
+			smp->data.type = SMP_T_IPV6;
+			p += 16;
+			break;
+		case SPOE_DATA_T_STR:
+		case SPOE_DATA_T_BIN:
+			/* All the buffer must be decoded */
+			if (spoe_decode_buffer(&p, end, &str, &sz) == -1)
+				return -1;
+			smp->data.u.str.str = str;
+			smp->data.u.str.len = sz;
+			smp->data.type = (type == SPOE_DATA_T_STR) ? SMP_T_STR : SMP_T_BIN;
+			break;
+	}
+
+	r    = (p - *buf);
+	*buf = p;
+	return r;
+}
+
+
+#endif
diff --git a/contrib/spoa_example/spoa.c b/contrib/spoa_example/spoa.c
index 351313a..ee2e3de 100644
--- a/contrib/spoa_example/spoa.c
+++ b/contrib/spoa_example/spoa.c
@@ -21,7 +21,9 @@
 #include <errno.h>
 #include <stdio.h>
 #include <signal.h>
+#include <arpa/inet.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>
 #include <sys/socket.h>
 #include <err.h>
 #include <ctype.h>
@@ -33,10 +35,9 @@
 #include <event2/event_struct.h>
 #include <event2/thread.h>
 
-#include <common/mini-clist.h>
-#include <common/chunk.h>
-
-#include <proto/spoe.h>
+#include <mini-clist.h>
+#include <spoe_types.h>
+#include <spop_functions.h>
 
 #define DEFAULT_PORT       12345
 #define CONNECTION_BACKLOG 10