]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: server: split parse_server
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 8 Mar 2021 09:29:33 +0000 (10:29 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 18 Mar 2021 14:37:05 +0000 (15:37 +0100)
The huge parse_server function is splitted into two smaller ones.
* _srv_parse_init allocates a new server instance and parses the address
  parameter
* _srv_parse_kw parse the current server keyword

This simplify a bit the parse_server function. Besides, it will be
useful for dynamic server creation.

src/server.c

index 336257135e5ab6267e212d8f20ceec2c7af6b57b..29ea88e55d17d8722c749f81c3b7a983e3b9ed8d 100644 (file)
@@ -2363,8 +2363,19 @@ static int server_template_init(struct server *srv, struct proxy *px)
        return i - srv->tmpl_info.nb_low;
 }
 
-int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy,
-                 const struct proxy *defproxy, int parse_addr, int in_peers_section, int initial_resolve)
+/* Allocate a new server pointed by <srv> and try to parse the first arguments
+ * in <args> as an address for a server or an address-range for a template or
+ * nothing for a default-server. <cur_arg> is incremented to the next argument.
+ *
+ * This function is first intented to be used through parse_server to
+ * initialize a new server on startup.
+ *
+ * A mask of errors is returned. On a parsing error, ERR_FATAL is set. In case
+ * of memory exhaustion, ERR_ABORT is set. If the server cannot be allocated,
+ * <srv> will be set to NULL.
+ */
+static int _srv_parse_init(struct server **srv, const char *file, int linenum, char **args, int *cur_arg, struct proxy *curproxy,
+                           int parse_addr, int in_peers_section, int initial_resolve)
 {
        struct server *newsrv = NULL;
        const char *err = NULL;
@@ -2372,39 +2383,25 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
        int err_code = 0;
        char *fqdn = NULL;
 
+       *srv = NULL;
+
        if (strcmp(args[0], "server") == 0         ||
            strcmp(args[0], "peer") == 0           ||
            strcmp(args[0], "default-server") == 0 ||
            strcmp(args[0], "server-template") == 0) {
-               int cur_arg;
                int defsrv = (*args[0] == 'd');
-               int srv = !defsrv && (*args[0] == 'p' || strcmp(args[0], "server") == 0);
-               int srv_tmpl = !defsrv && !srv;
+               int srv_kw = !defsrv && (*args[0] == 'p' || strcmp(args[0], "server") == 0);
+               int srv_tmpl = !defsrv && !srv_kw;
                int tmpl_range_low = 0, tmpl_range_high = 0;
 
-               if (!defsrv && curproxy == defproxy) {
-                       ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-               else if (failifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
-                       err_code |= ERR_ALERT | ERR_FATAL;
-                       goto out;
-               }
-
                /* There is no mandatory first arguments for default server. */
-               if (srv && parse_addr) {
+               if (srv_kw && parse_addr) {
                        if (!*args[2]) {
-                               if (in_peers_section) {
-                                       return 0;
-                               }
-                               else {
-                                       /* 'server' line number of argument check. */
-                                       ha_alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
-                                                 file, linenum, args[0]);
-                                       err_code |= ERR_ALERT | ERR_FATAL;
-                                       goto out;
-                               }
+                               /* 'server' line number of argument check. */
+                               ha_alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
+                                        file, linenum, args[0]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
                        }
 
                        err = invalid_char(args[1]);
@@ -2423,28 +2420,28 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
 
                if (err) {
                        ha_alert("parsing [%s:%d] : character '%c' is not permitted in %s %s '%s'.\n",
-                             file, linenum, *err, args[0], srv ? "name" : "prefix", args[1]);
+                             file, linenum, *err, args[0], srv_kw ? "name" : "prefix", args[1]);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
 
-               cur_arg = 2;
+               *cur_arg = 2;
                if (srv_tmpl) {
                        /* Parse server-template <nb | range> arg. */
-                       if (srv_tmpl_parse_range(newsrv, args[cur_arg], &tmpl_range_low, &tmpl_range_high) < 0) {
+                       if (srv_tmpl_parse_range(newsrv, args[*cur_arg], &tmpl_range_low, &tmpl_range_high) < 0) {
                                ha_alert("parsing [%s:%d] : Wrong %s number or range arg '%s'.\n",
-                                         file, linenum, args[0], args[cur_arg]);
+                                         file, linenum, args[0], args[*cur_arg]);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                goto out;
                        }
-                       cur_arg++;
+                       (*cur_arg)++;
                }
 
                if (!defsrv) {
                        struct sockaddr_storage *sk;
                        int port1, port2, port;
 
-                       newsrv = new_server(curproxy);
+                       *srv = newsrv = new_server(curproxy);
                        if (!newsrv) {
                                ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
                                err_code |= ERR_ALERT | ERR_ABORT;
@@ -2459,13 +2456,11 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
                        /* the servers are linked backwards first */
                        newsrv->next = curproxy->srv;
                        curproxy->srv = newsrv;
-                       newsrv->conf.file = strdup(file);
-                       newsrv->conf.line = linenum;
                        /* Note: for a server template, its id is its prefix.
                         * This is a temporary id which will be used for server allocations to come
                         * after parsing.
                         */
-                       if (srv)
+                       if (srv_kw)
                                newsrv->id = strdup(args[1]);
                        else
                                newsrv->tmpl_info.prefix = strdup(args[1]);
@@ -2480,7 +2475,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
                        if (!parse_addr)
                                goto skip_addr;
 
-                       sk = str2sa_range(args[cur_arg], &port, &port1, &port2, NULL, NULL,
+                       sk = str2sa_range(args[*cur_arg], &port, &port1, &port2, NULL, NULL,
                                          &errmsg, NULL, &fqdn,
                                          (initial_resolve ? PA_O_RESOLVE : 0) | PA_O_PORT_OK | PA_O_PORT_OFS | PA_O_STREAM | PA_O_XPRT | PA_O_CONNECT);
                        if (!sk) {
@@ -2521,80 +2516,148 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
 
                        if (!newsrv->srvrq && !newsrv->hostname && !protocol_by_family(newsrv->addr.ss_family)) {
                                ha_alert("parsing [%s:%d] : Unknown protocol family %d '%s'\n",
-                                     file, linenum, newsrv->addr.ss_family, args[cur_arg]);
+                                     file, linenum, newsrv->addr.ss_family, args[*cur_arg]);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                goto out;
                        }
 
-                       cur_arg++;
+                       (*cur_arg)++;
  skip_addr:
                        /* Copy default server settings to new server settings. */
                        srv_settings_cpy(newsrv, &curproxy->defsrv, 0);
                        HA_SPIN_INIT(&newsrv->lock);
                } else {
-                       newsrv = &curproxy->defsrv;
-                       cur_arg = 1;
+                       *srv = newsrv = &curproxy->defsrv;
+                       *cur_arg = 1;
                        newsrv->resolv_opts.family_prio = AF_INET6;
                        newsrv->resolv_opts.accept_duplicate_ip = 0;
                }
+       }
 
-               while (*args[cur_arg]) {
-                       struct srv_kw *kw;
-                       const char *best;
-
-                       kw = srv_find_kw(args[cur_arg]);
-                       if (kw) {
-                               char *err = NULL;
-                               int code;
-
-                               if (!kw->parse) {
-                                       ha_alert("parsing [%s:%d] : '%s %s' : '%s' option is not implemented in this version (check build options).\n",
-                                                file, linenum, args[0], args[1], args[cur_arg]);
-                                       if (kw->skip != -1)
-                                               cur_arg += 1 + kw->skip ;
-                                       err_code |= ERR_ALERT | ERR_FATAL;
-                                       goto out;
-                               }
+       free(fqdn);
+       return 0;
 
-                               if (defsrv && !kw->default_ok) {
-                                       ha_alert("parsing [%s:%d] : '%s %s' : '%s' option is not accepted in default-server sections.\n",
-                                                file, linenum, args[0], args[1], args[cur_arg]);
-                                       if (kw->skip != -1)
-                                               cur_arg += 1 + kw->skip;
-                                       err_code |= ERR_ALERT;
-                                       continue;
-                               }
+out:
+       free(fqdn);
+       return err_code;
+}
 
-                               code = kw->parse(args, &cur_arg, curproxy, newsrv, &err);
-                               err_code |= code;
+/* Parse the server keyword in <args>.
+ * <cur_arg> is incremented beyond the keyword optional value. Note that this
+ * might not be the case if an error is reported.
+ *
+ * This function is first intented to be used through parse_server to
+ * initialize a new server on startup.
+ *
+ * A mask of errors is returned. ERR_FATAL is set if the parsing should be
+ * interrupted.
+ */
+static int _srv_parse_kw(struct server *srv, int defsrv, const char *file, int linenum, char **args, int *cur_arg, struct proxy *curproxy,
+                         int parse_addr, int in_peers_section, int initial_resolve)
+{
+       int err_code = 0;
+       struct srv_kw *kw;
+       const char *best;
+
+       kw = srv_find_kw(args[*cur_arg]);
+       if (kw) {
+               char *err = NULL;
+               int code;
+
+               if (!kw->parse) {
+                       ha_alert("parsing [%s:%d] : '%s %s' : '%s' option is not implemented in this version (check build options).\n",
+                             file, linenum, args[0], args[1], args[*cur_arg]);
+                       if (kw->skip != -1)
+                               *cur_arg += 1 + kw->skip ;
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
 
-                               if (code) {
-                                       display_parser_err(file, linenum, args, cur_arg, code, &err);
-                                       if (code & ERR_FATAL) {
-                                               free(err);
-                                               if (kw->skip != -1)
-                                                       cur_arg += 1 + kw->skip;
-                                               goto out;
-                                       }
-                               }
+               if (defsrv && !kw->default_ok) {
+                       ha_alert("parsing [%s:%d] : '%s %s' : '%s' option is not accepted in default-server sections.\n",
+                             file, linenum, args[0], args[1], args[*cur_arg]);
+                       if (kw->skip != -1)
+                               *cur_arg += 1 + kw->skip ;
+                       err_code |= ERR_ALERT;
+                       return 0;
+               }
+
+               code = kw->parse(args, &*cur_arg, curproxy, srv, &err);
+               err_code |= code;
+
+               if (code) {
+                       display_parser_err(file, linenum, args, *cur_arg, code, &err);
+                       if (code & ERR_FATAL) {
                                free(err);
                                if (kw->skip != -1)
-                                       cur_arg += 1 + kw->skip;
-                               continue;
+                                       *cur_arg += 1 + kw->skip;
+                               goto out;
                        }
+               }
+               free(err);
+               if (kw->skip != -1)
+                       *cur_arg += 1 + kw->skip;
+               return 0;
+       }
 
-                       best = srv_find_best_kw(args[cur_arg]);
-                       if (best)
-                               ha_alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'; did you mean '%s' maybe ?\n",
-                                        file, linenum, args[0], args[1], args[cur_arg], best);
-                       else
-                               ha_alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'.\n",
-                                        file, linenum, args[0], args[1], args[cur_arg]);
+       best = srv_find_best_kw(args[*cur_arg]);
+       if (best)
+               ha_alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'; did you mean '%s' maybe ?\n",
+                        file, linenum, args[0], args[1], args[*cur_arg], best);
+       else
+               ha_alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'.\n",
+                        file, linenum, args[0], args[1], args[*cur_arg]);
+
+       err_code |= ERR_ALERT | ERR_FATAL;
+
+out:
+       return err_code;
+}
 
+int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy,
+                 const struct proxy *defproxy, int parse_addr, int in_peers_section, int initial_resolve)
+{
+       struct server *newsrv = NULL;
+       int err_code = 0;
+
+       if (strcmp(args[0], "server") == 0         ||
+           strcmp(args[0], "peer") == 0           ||
+           strcmp(args[0], "default-server") == 0 ||
+           strcmp(args[0], "server-template") == 0) {
+               int cur_arg;
+               int defsrv = (*args[0] == 'd');
+               int srv = !defsrv && (*args[0] == 'p' || strcmp(args[0], "server") == 0);
+               int srv_tmpl = !defsrv && !srv;
+
+               if (!defsrv && curproxy == defproxy) {
+                       ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               else if (failifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
 
+               if (srv && parse_addr) {
+                       if (!*args[2]) {
+                               if (in_peers_section)
+                                       return 0;
+                       }
+               }
+               err_code = _srv_parse_init(&newsrv, file, linenum, args, &cur_arg, curproxy,
+                                          parse_addr, in_peers_section, initial_resolve);
+               if (err_code & ERR_CODE)
+                       goto out;
+
+               while (*args[cur_arg]) {
+                       err_code = _srv_parse_kw(newsrv, defsrv, file, linenum, args, &cur_arg, curproxy,
+                                                parse_addr, in_peers_section, initial_resolve);
+
+                       if (err_code & ERR_FATAL)
+                               goto out;
+               }
+
                if (!defsrv)
                        err_code |= server_finalize_init(file, linenum, args, cur_arg, newsrv, curproxy);
                if (err_code & ERR_FATAL)
@@ -2602,12 +2665,9 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
                if (srv_tmpl)
                        server_template_init(newsrv, curproxy);
        }
-       free(fqdn);
        return 0;
 
  out:
-       free(fqdn);
-       free(errmsg);
        return err_code;
 }