CONTRIB: spoa_example: allow to compile outside HAProxy.

Don't include haproxy's includes anymore and use a local copy instead.
This commit is contained in:
Eric Salama 2017-11-10 11:02:23 +01:00 committed by Willy Tarreau
parent f46bf95d2b
commit 8a9c6c2154
6 changed files with 822 additions and 6 deletions

View File

@ -6,8 +6,8 @@ CC = gcc
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

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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