]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: listener: add a minimal framework to register "bind" keyword options
authorWilly Tarreau <w@1wt.eu>
Wed, 12 Sep 2012 21:17:10 +0000 (23:17 +0200)
committerWilly Tarreau <w@1wt.eu>
Sat, 15 Sep 2012 20:33:08 +0000 (22:33 +0200)
With the arrival of SSL, the "bind" keyword has received even more options,
all of which are processed in cfgparse in a cumbersome way. So it's time to
let modules register their own bind options. This is done very similarly to
the ACLs with a small difference in that we make the difference between an
unknown option and a known, unimplemented option.

include/proto/listener.h
include/types/listener.h
src/cfgparse.c
src/listener.c

index 4019ff13285c4b246fca6eb3a7dc8dd15b3728c5..e570a9bb0e8c0a813f8a2908cdfa08eaf345b5d6 100644 (file)
@@ -105,6 +105,15 @@ void delete_listener(struct listener *listener);
  */
 int listener_accept(int fd);
 
+/*
+ * Registers the bind keyword list <kwl> as a list of valid keywords for next
+ * parsing sessions.
+ */
+void bind_register_keywords(struct bind_kw_list *kwl);
+
+/* Return a pointer to the bind keyword <kw>, or NULL if not found. */
+struct bind_kw *bind_find_kw(const char *kw);
+
 /* allocate an bind_conf struct for a bind line, and chain it to list head <lh>.
  * If <arg> is not NULL, it is duplicated into ->arg to store useful config
  * information for error reporting.
index 24061486ee669050a3e8f739e499c34b979c8ed3..f21a28d6c1438c137e9d63241ff3ff93ffcbc0b7 100644 (file)
@@ -156,6 +156,31 @@ struct listener {
        } conf;                         /* config information */
 };
 
+/* Descriptor for a "bind" keyword. The ->parse() function returns 0 in case of
+ * success, or a combination of ERR_* flags if an error is encountered. The
+ * function pointer can be NULL if not implemented. The function also has an
+ * access to the current "bind" conf, which is the conf of the last listener,
+ * reachable via px->listen->bind_conf. The ->skip value tells the parser how
+ * many words have to be skipped after the keyword.
+ */
+struct bind_kw {
+       const char *kw;
+       int (*parse)(char **args, int cur_arg, struct proxy *px, struct listener *last, char **err);
+       int skip; /* nb of args to skip */
+};
+
+/*
+ * A keyword list. It is a NULL-terminated array of keywords. It embeds a
+ * struct list in order to be linked to other lists, allowing it to easily
+ * be declared where it is needed, and linked without duplicating data nor
+ * allocating memory.
+ */
+struct bind_kw_list {
+       struct list list;
+       struct bind_kw kw[VAR_ARRAY];
+};
+
+
 #endif /* _TYPES_LISTENER_H */
 
 /*
index 07b73471c48a38dcd403ea54fc714cbbaa13f143..c0b29c6571099a5b0aa175b0b1d718988c672a8c 100644 (file)
@@ -1711,6 +1711,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                }
                cur_arg = 2;
                while (*(args[cur_arg])) {
+                       struct bind_kw *kw;
+
                        if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
 #ifdef SO_BINDTODEVICE
                                struct listener *l;
@@ -2147,6 +2149,41 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                                continue;
                         }
 
+                       kw = bind_find_kw(args[cur_arg]);
+                       if (kw) {
+                               char *err = NULL;
+                               int code;
+
+                               if (!kw->parse) {
+                                       Alert("parsing [%s:%d] : '%s' : '%s' option is not implemented in this version (check build options).\n",
+                                             file, linenum, args[0], args[cur_arg]);
+                                       cur_arg += 1 + kw->skip ;
+                                       err_code |= ERR_ALERT | ERR_FATAL;
+                                       goto out;
+                               }
+
+                               code = kw->parse(args, cur_arg, curproxy, last_listen, &err);
+                               err_code |= code;
+
+                               if (code) {
+                                       if (err && *err) {
+                                               indent_msg(&err, 2);
+                                               Alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, args[0], err);
+                                       }
+                                       else
+                                               Alert("parsing [%s:%d] : '%s' : error encountered while processing '%s'.\n",
+                                                     file, linenum, args[0], args[cur_arg]);
+                                       if (code & ERR_FATAL) {
+                                               free(err);
+                                               cur_arg += 1 + kw->skip;
+                                               goto out;
+                                       }
+                               }
+                               free(err);
+                               cur_arg += 1 + kw->skip;
+                               continue;
+                       }
+
                        Alert("parsing [%s:%d] : '%s' only supports the 'transparent', 'accept-proxy', 'defer-accept', 'name', 'id', 'mss', 'mode', 'uid', 'gid', 'user', 'group' and 'interface' options.\n",
                              file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
index 0e864b2aa2cc9ef192553e17b81fbdf5e837958b..13eb27209f3e3fc8a4fa988ba4fc5149ae289a30 100644 (file)
 #include <proto/log.h>
 #include <proto/task.h>
 
+/* List head of all known bind keywords */
+static struct bind_kw_list bind_keywords = {
+       .list = LIST_HEAD_INIT(bind_keywords.list)
+};
+
 /* This function adds the specified listener's file descriptor to the polling
  * lists if it is in the LI_LISTEN state. The listener enters LI_READY or
  * LI_FULL state depending on its number of connections.
@@ -409,6 +414,47 @@ void listener_accept(int fd)
        return;
 }
 
+/*
+ * Registers the bind keyword list <kwl> as a list of valid keywords for next
+ * parsing sessions.
+ */
+void bind_register_keywords(struct bind_kw_list *kwl)
+{
+       LIST_ADDQ(&bind_keywords.list, &kwl->list);
+}
+
+/* Return a pointer to the bind keyword <kw>, or NULL if not found. If the
+ * keyword is found with a NULL ->parse() function, then an attempt is made to
+ * find one with a valid ->parse() function. This way it is possible to declare
+ * platform-dependant, known keywords as NULL, then only declare them as valid
+ * if some options are met. Note that if the requested keyword contains an
+ * opening parenthesis, everything from this point is ignored.
+ */
+struct bind_kw *bind_find_kw(const char *kw)
+{
+       int index;
+       const char *kwend;
+       struct bind_kw_list *kwl;
+       struct bind_kw *ret = NULL;
+
+       kwend = strchr(kw, '(');
+       if (!kwend)
+               kwend = kw + strlen(kw);
+
+       list_for_each_entry(kwl, &bind_keywords.list, list) {
+               for (index = 0; kwl->kw[index].kw != NULL; index++) {
+                       if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
+                           kwl->kw[index].kw[kwend-kw] == 0) {
+                               if (kwl->kw[index].parse)
+                                       return &kwl->kw[index]; /* found it !*/
+                               else
+                                       ret = &kwl->kw[index];  /* may be OK */
+                       }
+               }
+       }
+       return ret;
+}
+
 /************************************************************************/
 /*           All supported ACL keywords must be declared here.          */
 /************************************************************************/