Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Configuration handling.
0003  *   Additional validations:
0004  *    - If singleton groups are defined, sure that there are lock provider binary for
0005  *          the group defined
0006  *    - Check that only single lock provider is defined for the singleton group
0007  *    - If doing reload, ensure that if LP is running and it's locked group is different
0008  *       thant defined, then lock provider must be shutdown prior the configuration reload.
0009  *
0010  * @file appconfig.c
0011  */
0012 /* -----------------------------------------------------------------------------
0013  * Enduro/X Middleware Platform for Distributed Transaction Processing
0014  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0015  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0016  * This software is released under one of the following licenses:
0017  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0018  * See LICENSE file for full text.
0019  * -----------------------------------------------------------------------------
0020  * AGPL license:
0021  *
0022  * This program is free software; you can redistribute it and/or modify it under
0023  * the terms of the GNU Affero General Public License, version 3 as published
0024  * by the Free Software Foundation;
0025  *
0026  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0027  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0028  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0029  * for more details.
0030  *
0031  * You should have received a copy of the GNU Affero General Public License along 
0032  * with this program; if not, write to the Free Software Foundation, Inc.,
0033  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0034  *
0035  * -----------------------------------------------------------------------------
0036  * A commercial use license is available from Mavimax, Ltd
0037  * contact@mavimax.com
0038  * -----------------------------------------------------------------------------
0039  */
0040 #include <string.h>
0041 #include <stdio.h>
0042 #include <stdlib.h>
0043 #include <libgen.h>
0044 #include <memory.h>
0045 #include <libxml/xmlreader.h>
0046 #include <errno.h>
0047 #include <signal.h>
0048 
0049 #include <ndrstandard.h>
0050 #include <ndrxd.h>
0051 #include <exenv.h>
0052 #include <libndrxconf.h>
0053 #include <singlegrp.h>
0054 #include <lcfint.h>
0055 #include <ndrx_intdef.h>
0056 #include "ndebug.h"
0057 #include "utlist.h"
0058 #include "nstdutil.h"
0059 #include "exsha1.h"
0060 /*---------------------------Externs------------------------------------*/
0061 /*---------------------------Macros-------------------------------------*/
0062 #define     CHECK_PM_DEFAULT              2   /**< Check process model on every */
0063 
0064 #define     DDRREALOAD_DEFAULT           60  /**< Number of seconds route is not reloaded */
0065 /*---------------------------Enums--------------------------------------*/
0066 /*---------------------------Typedefs-----------------------------------*/
0067 
0068 /*---------------------------Globals------------------------------------*/
0069 
0070 /**
0071  * Active monitor configuration
0072  */
0073 config_t *G_app_config=NULL;
0074 
0075 /**
0076  * Active process model handler - linked list
0077  */
0078 pm_node_t *G_process_model = NULL;
0079 
0080 /**
0081  * Active Hash list by service IDs
0082  */
0083 pm_node_t **G_process_model_hash = NULL;
0084 
0085 /**
0086  * PID Hash table
0087  */
0088 pm_pidhash_t **G_process_model_pid_hash = NULL;
0089 /*---------------------------Statics------------------------------------*/
0090 /*---------------------------Prototypes---------------------------------*/
0091 exprivate int ndrx_prase_killseq(int *killseq, char *seq, int last_line);
0092 
0093 /**
0094  * Validate request address, also strip down any un-needed chars
0095  * @param rqaddr request address from config
0096  * @param section this is where error occurred
0097  * @return EXSUCCEED/EXFAIL
0098  */
0099 exprivate int rqaddr_chk(char *rqaddr, char *section)
0100 {
0101     int ret = EXSUCCEED;
0102     
0103     ndrx_str_strip(rqaddr, "\t ");
0104     
0105     if (NDRX_SYS_SVC_PFXC == rqaddr[0])
0106     {
0107         NDRX_LOG(log_error, "Request address cannot start with [%c]", 
0108                 NDRX_SYS_SVC_PFXC);
0109         
0110         NDRXD_set_error_fmt(NDRXD_EINVPARAM, "(%s) Request address "
0111                 "cannot start with [%c] at %s", G_sys_config.config_file_short, 
0112                 NDRX_SYS_SVC_PFXC, section);
0113         
0114         EXFAIL_OUT(ret);
0115     }
0116     
0117 out:
0118     return ret;
0119 }
0120 
0121 /**
0122  * Allocate empty configuration handler
0123  */
0124 exprivate config_t * config_alloc(void)
0125 {
0126     config_t *ret = NDRX_CALLOC(1, sizeof(config_t));
0127     
0128     if (NULL==ret)
0129     {
0130         NDRXD_set_error_msg(NDRXD_ESYSTEM, "Failed to malloc config_t");
0131         goto out;
0132     }
0133 
0134 out:
0135     return ret;
0136 }
0137 
0138 /**
0139  * Free up config memory
0140  * Free up the list of environments in defaults section and in process
0141  * sections.
0142  * @param app_config
0143  * @param process_model
0144  * @param process_model_hash
0145  * @param process_model_pid_hash
0146  */
0147 exprivate void config_free(config_t **app_config, pm_node_t **process_model,
0148             pm_node_t ***process_model_hash, pm_pidhash_t ***process_model_pid_hash)
0149 {
0150     NDRX_LOG(log_debug, "Free up config memory...");
0151     
0152     if (NULL!=*app_config)
0153     {
0154         conf_server_node_t *elt, *tmp;
0155 
0156         if (NULL!=(*app_config)->monitor_config)
0157         {
0158             DL_FOREACH_SAFE((*app_config)->monitor_config,elt,tmp)
0159             {
0160                 /* free up envs, if any */
0161                 ndrx_ndrxconf_envs_envs_free(&elt->envlist);
0162                 ndrx_ndrxconf_envs_grouplists_free(&elt->envgrouplist);
0163                 
0164                 DL_DELETE((*app_config)->monitor_config,elt);
0165                 NDRX_FREE(elt);
0166             }
0167         }
0168         
0169         /* kill any env groups */
0170         ndrx_ndrxconf_envs_groups_free(&(*app_config)->envgrouphash);
0171         
0172         /* remove any ddr segments */
0173         ndrx_ddr_free_all(*app_config);
0174 
0175         ndrx_ndrxconf_procgroups_free((*app_config)->procgroups);
0176         
0177         NDRX_FREE(*app_config);
0178 
0179         *app_config = NULL;
0180     }
0181     
0182     /* Free up process model? */
0183     if (NULL!=*process_model)
0184     {
0185         pm_node_t *elt, *tmp;
0186         DL_FOREACH_SAFE(*process_model,elt,tmp)
0187         {
0188             /* Remove any stuff from PID hash! */
0189             delete_from_pid_hash(*process_model_pid_hash,
0190                 pid_hash_get(*process_model_pid_hash, elt->pid));
0191             
0192             /* Remove process model by it self! */
0193             DL_DELETE(*process_model,elt);
0194             NDRX_FREE(elt);
0195         }
0196     }
0197     
0198     /* Free up the services */
0199     if (*process_model_hash)
0200     {
0201         NDRX_FREE(*process_model_hash);
0202         *process_model_hash=NULL;
0203     }
0204 
0205     if (*process_model_pid_hash)
0206     {
0207         NDRX_FREE(*process_model_pid_hash);
0208         *process_model_pid_hash=NULL;
0209     }
0210     
0211 }
0212 
0213 /**
0214  * Load live config
0215  * @return 
0216  */
0217 expublic int load_active_config_live(void)
0218 {
0219     int ret = EXSUCCEED;
0220     ret = load_active_config(&G_app_config, &G_process_model,
0221                 &G_process_model_hash, &G_process_model_pid_hash);
0222     
0223     if (EXSUCCEED==ret)
0224     {
0225         /* apply DDR */
0226         ndrx_ddr_apply();
0227         ndrx_ndrxconf_procgroups_apply_singlegrp(G_app_config->procgroups);
0228     }
0229     
0230     return ret;
0231 }
0232 
0233 /**
0234  * Validate process groups
0235  * @param app_config parsed config
0236  * @param process_model process model
0237  * @return EXSUCCEED/EXFAIL
0238  */
0239 exprivate int validate_process_groups(config_t *app_config, pm_node_t *process_model)
0240 {
0241     int ret=EXSUCCEED;
0242     int i;
0243     pm_node_t *p_pm;
0244     int procgrplps[ndrx_G_libnstd_cfg.pgmax];
0245 
0246     memset(procgrplps, 0, sizeof(int)*ndrx_G_libnstd_cfg.pgmax);
0247 
0248     DL_FOREACH(process_model, p_pm)
0249     {
0250         /* check for LPs */
0251         if (p_pm->conf->procgrp_lp_no > 0 && 
0252             0!=procgrplps[p_pm->conf->procgrp_lp_no-1])
0253         {
0254 /* lp group may have support servers:*/
0255 #if 0
0256             NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Lock provider "
0257                         "[%s]/%d duplicate for process group [%s]. "
0258                         "Lock already provided by srvid %d",
0259                         G_sys_config.config_file_short, 
0260                         p_pm->binary_name, p_pm->srvid, 
0261                         /* this is pre-validated, will be present: */
0262                         ndrx_ndrxconf_procgroups_resolveno(app_config->procgroups, p_pm->conf->procgrp_lp_no)->grpname, 
0263                         procgrplps[p_pm->conf->procgrp_lp_no-1]);
0264             EXFAIL_OUT(ret);
0265 #endif
0266         }
0267         else 
0268         {
0269             if (p_pm->conf->procgrp_lp_no > 0)
0270             {
0271                 /* mark provess as group LP */
0272                 procgrplps[p_pm->conf->procgrp_lp_no-1]=p_pm->srvid;
0273             }
0274         }
0275     }
0276 
0277     /* Check that for each singleton process group lock provider is defined 
0278      * Loop over all process groups and check are they loaded to the procgrplps
0279      */
0280     if (NULL!=app_config->procgroups)
0281     {
0282         ndrx_procgroup_t *p_grp;
0283         for (i=0; i<ndrx_G_libnstd_cfg.pgmax; i++)
0284         {
0285             p_grp = &app_config->procgroups->groups_by_no[i];
0286 
0287             if (    (p_grp->flags & NDRX_SG_IN_USE)
0288                     && (p_grp->flags & NDRX_SG_SINGLETON) 
0289                     && 0==procgrplps[p_grp->grpno-1])
0290             {
0291                 NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Singleton process group [%s] "
0292                             "does not have lock provider defined",
0293                             G_sys_config.config_file_short, 
0294                             p_grp->grpname);
0295                 EXFAIL_OUT(ret);
0296             }
0297         }
0298     }
0299     
0300 
0301 out:
0302     return ret;
0303 }
0304 
0305 /**
0306  * Load active configuration.
0307  * This should also build the main process model i.e. get ready for startup!
0308  * @return SUCCED/FAIL
0309  */
0310 expublic int load_active_config(config_t **app_config, pm_node_t **process_model,
0311             pm_node_t ***process_model_hash, pm_pidhash_t ***process_model_pid_hash)
0312 {
0313     int ret=EXSUCCEED;
0314     int cfg_ok = EXFALSE;
0315 
0316     if (*app_config!=NULL)
0317     {
0318         NDRX_LOG(log_debug, "Active configuration present - nothing to do");
0319         /* Reply to caller, that active configuration present */
0320         NDRXD_set_error(NDRXD_ECFGLDED);
0321         ret=EXFAIL;
0322         cfg_ok = EXTRUE;
0323         goto out;
0324     }
0325     else
0326     {
0327         NDRX_LOG(log_debug, "Active configuration not loaded - will load!");
0328         *app_config = config_alloc();
0329         if (NULL==*app_config)
0330         {
0331             /* Reply to caller that config failed to load */
0332             NDRXD_set_error(NDRXD_EOS);
0333             ret=EXFAIL;
0334             goto out;
0335         }
0336     }
0337 
0338     if (EXSUCCEED!=load_config(*app_config, G_sys_config.config_file))
0339     {
0340         NDRX_LOG(log_debug, "Failed to load configuration");
0341         /* Reply to caller that config failed to load */
0342         NDRXD_set_error(NDRXD_ECFGINVLD);
0343         ret=EXFAIL;
0344         goto out;
0345     }
0346 
0347     NDRX_LOG(log_debug, "building process model");
0348 
0349     /* Allocate hash, OK? */
0350     NDRX_LOG(log_debug, "G_sys_config.max_servers = %d", 
0351             ndrx_get_G_atmi_env()->max_servers);
0352     *process_model_hash = (pm_node_t **)NDRX_CALLOC(ndrx_get_G_atmi_env()->max_servers, 
0353             sizeof(pm_node_t *));
0354 
0355     if (NULL==*process_model_hash)
0356     {
0357         NDRXD_set_error_msg(NDRXD_EOS, "Failed to allocate *process_model_hash");
0358         ret = EXFAIL;
0359         goto out;
0360     }
0361 
0362     *process_model_pid_hash = (pm_pidhash_t **)NDRX_CALLOC(ndrx_get_G_atmi_env()->max_servers, 
0363             sizeof(pm_pidhash_t *));
0364 
0365     if (NULL==*process_model_pid_hash)
0366     {
0367         NDRXD_set_error_fmt(NDRXD_EOS, "(%s) Failed to allocate *process_model_pid_hash - %d bytes",
0368                             G_sys_config.config_file_short,
0369                             ndrx_get_G_atmi_env()->max_servers * sizeof(pm_pidhash_t *) );
0370         ret = EXFAIL;
0371         goto out;
0372     }
0373 
0374     if (EXSUCCEED!=build_process_model((*app_config)->monitor_config,
0375                                 &*process_model, /* proces model linked list */
0376                                 *process_model_hash/* Hash table models */))
0377     {
0378         NDRXD_set_error_msg(NDRXD_EOS, "Failed to allocate *process_model_hash");
0379         ret = EXFAIL;
0380         goto out;
0381     }
0382 
0383     if (EXSUCCEED!=validate_process_groups(*app_config, *process_model))
0384     {
0385         ret = EXFAIL;
0386         goto out;
0387     }
0388 
0389 out:
0390 
0391     /* Release memory, if config not loaded */
0392     if (EXSUCCEED!=ret && !cfg_ok)
0393     {
0394         config_free(app_config, process_model, process_model_hash, process_model_pid_hash);
0395     }
0396 
0397     NDRX_LOG(log_warn, "load_active_config returns with status %d", ret);
0398 
0399     return ret; /* Do not want to break the system! */
0400 }
0401 
0402 /**
0403  * Parse defaults
0404  * @param doc
0405  * @param cur
0406  * @return
0407  */
0408 exprivate int parse_defaults(config_t *config, xmlDocPtr doc, xmlNodePtr cur)
0409 {
0410     int ret=EXSUCCEED;
0411     char *p;
0412     char tmp[PATH_MAX];
0413     int last_line=0;
0414     
0415     if (!config->ctl_had_defaults)
0416     {
0417         config->default_respawn = 1; /* we want respawn by default! */
0418 
0419         config->default_rssmax = EXFAIL; /** Disabled */
0420         config->default_vszmax = EXFAIL; /** Disabled */
0421      
0422         /* next time reuse what ever we have */
0423         config->ctl_had_defaults = EXTRUE;
0424         config->default_mindispatchthreads = 1; /**< assumed as 1 by atmisrv */
0425         config->default_maxdispatchthreads = 1; /**< assumed as 1 by atmisrv */
0426         
0427         config->default_killseq[0] = SIGINT;
0428         config->default_killseq[1] = SIGTERM;
0429         config->default_killseq[2] = SIGKILL;
0430     }
0431     
0432     if (NULL!=cur)
0433     {
0434         do
0435         {
0436             if (0==strcmp((char*)cur->name, "min"))
0437             {
0438                
0439                 p = (char *)xmlNodeGetContent(cur);
0440                 
0441                 /* we should be able to setup this from env variables
0442                  * for external scripting...
0443                  */
0444                 NDRX_QENV_SUBST(tmp, p);
0445                 config->default_min = atoi(tmp);
0446                 NDRX_LOG(log_debug, "Got default min: [%s] - %d",
0447                                                   p, config->default_min);
0448                 xmlFree(p);
0449             }
0450             else if (0==strcmp((char*)cur->name, "max"))
0451             {
0452                 p = (char *)xmlNodeGetContent(cur);
0453                 NDRX_QENV_SUBST(tmp, p);
0454                 
0455                 config->default_max = atoi(tmp);
0456                 NDRX_LOG(log_debug, "Got default max: [%s] - %d",
0457                                                   p, config->default_max);
0458                 xmlFree(p);
0459             }
0460             else if (0==strcmp((char*)cur->name, "autokill"))
0461             {
0462                 p = (char *)xmlNodeGetContent(cur);
0463                 config->default_autokill = atoi(p);
0464                 NDRX_LOG(log_debug, "Got default autokill: [%s] - %d",
0465                                                   p, config->default_autokill);
0466                 xmlFree(p);
0467             }
0468             /* Load Environment override */
0469             else if (0==strcmp("env", (char *)cur->name))
0470             {
0471                 p = (char *)xmlNodeGetContent(cur);
0472                 NDRX_STRCPY_SAFE(config->default_env, p);
0473                 
0474                 /* process env */
0475                 ndrx_str_env_subs_len(config->default_env, sizeof(config->default_env));
0476                 
0477                 xmlFree(p);
0478             }
0479             else if (0==strcmp("envs", (char *)cur->name))
0480             {
0481                 if (EXSUCCEED!=ndrx_ndrxconf_envs_group_parse(doc, cur, 
0482                     &config->envgrouphash))
0483                 {
0484                     NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to parse <envs> tag!",
0485                             G_sys_config.config_file_short);
0486                     NDRX_LOG(log_error, "Failed to parse <envs> tag!");
0487                     EXFAIL_OUT(ret);
0488                 }
0489             }
0490             /* Startup control moved here...: */
0491             else if (0==strcmp((char*)cur->name, "start_max"))
0492             {
0493                 p = (char *)xmlNodeGetContent(cur);
0494                 config->default_start_max = atoi(p);
0495                 NDRX_LOG(log_debug, "start_max: [%s] - %d sty",
0496                                                   p, config->default_start_max);
0497                 xmlFree(p);
0498             }
0499             else if (0==strcmp((char*)cur->name, "end_max"))
0500             {
0501                 p = (char *)xmlNodeGetContent(cur);
0502                 config->default_end_max = atoi(p);
0503                 NDRX_LOG(log_debug, "end_max: [%s] - %d sty",
0504                                                   p, config->default_end_max);
0505                 xmlFree(p);
0506             }
0507             else if (0==strcmp((char*)cur->name, "pingtime"))
0508             {
0509                 p = (char *)xmlNodeGetContent(cur);
0510                 config->default_pingtime = atoi(p);
0511                 NDRX_LOG(log_debug, "pingtime: [%s] - %d sty",
0512                                                   p, config->default_pingtime);
0513                 xmlFree(p);
0514             }
0515             else if (0==strcmp((char*)cur->name, "ping_max"))
0516             {
0517                 p = (char *)xmlNodeGetContent(cur);
0518                 config->default_ping_max = atoi(p);
0519                 NDRX_LOG(log_debug, "ping_max: [%s] - %d sty",
0520                                                   p, config->default_ping_max);
0521                 xmlFree(p);
0522             }
0523             else if (0==strcmp((char*)cur->name, "exportsvcs"))
0524             {
0525                 p = (char *)xmlNodeGetContent(cur);
0526                 ndrx_str_strip(p, " \t"); /* strip spaces & tabs */
0527                 if (strlen(p)>=sizeof(config->default_exportsvcs))
0528                 {
0529                     NDRX_LOG(log_warn, "Trimming default exportsvcs");
0530                     p[sizeof(config->default_exportsvcs)-3] = EXEOS;
0531                 }
0532                 snprintf(config->default_exportsvcs, 
0533                         sizeof(config->default_exportsvcs), ",%s,", p);
0534                 NDRX_LOG(log_debug, "exportsvcs: [%s]", 
0535                             config->default_exportsvcs);
0536                 xmlFree(p);
0537             }
0538             else if (0==strcmp((char*)cur->name, "blacklistsvcs"))
0539             {
0540                 p = (char *)xmlNodeGetContent(cur);
0541                 ndrx_str_strip(p, " \t"); /* strip spaces & tabs */
0542                 if (strlen(p)>=sizeof(config->default_blacklistsvcs))
0543                 {
0544                     NDRX_LOG(log_warn, "Trimming default blacklistsvcs");
0545                     p[sizeof(config->default_blacklistsvcs)-3] = EXEOS;
0546                 }
0547                 snprintf(config->default_blacklistsvcs, 
0548                         sizeof(config->default_blacklistsvcs), ",%s,", p);
0549                 NDRX_LOG(log_debug, "blacklistsvcs: [%s]", 
0550                             config->default_blacklistsvcs);
0551                 xmlFree(p);
0552             }
0553             else if (0==strcmp((char*)cur->name, "killtime"))
0554             {
0555                 p = (char *)xmlNodeGetContent(cur);
0556                 config->default_killtime = atoi(p);
0557                 NDRX_LOG(log_debug, "killtime: [%s] - %d sty",
0558                                                   p, config->default_killtime);
0559                 xmlFree(p);
0560             }
0561             else if (0==strcmp((char*)cur->name, "srvstartwait"))
0562             {
0563                 p = (char *)xmlNodeGetContent(cur);
0564                 config->default_srvstartwait = atoi(p)*1000;
0565                 NDRX_LOG(log_debug, "srvstartwait: [%s] - %d msec",
0566                                             p, config->default_srvstartwait);
0567                 xmlFree(p);
0568             }
0569             else if (0==strcmp((char*)cur->name, "srvstopwait"))
0570             {
0571                 p = (char *)xmlNodeGetContent(cur);
0572                 config->default_srvstopwait = atoi(p)*1000;
0573                 NDRX_LOG(log_debug, "srvstopwait: [%s] - %d msec",
0574                                         p, config->default_srvstopwait);
0575                 xmlFree(p);
0576             }
0577             else if (0==strcmp((char*)cur->name, "cctag"))
0578             {
0579                 p = (char *)xmlNodeGetContent(cur);
0580                 NDRX_STRCPY_SAFE(config->default_cctag, p);
0581                 
0582                 /* process env */
0583                 ndrx_str_env_subs_len(config->default_cctag, sizeof(config->default_cctag));
0584                 
0585                 xmlFree(p);
0586             }
0587             else if (0==strcmp((char*)cur->name, "protected"))
0588             {
0589                 p = (char *)xmlNodeGetContent(cur);
0590                 if ('Y' == *p || 'y' == *p)
0591                 {
0592                     config->default_isprotected = 1;
0593                 }
0594                 else
0595                 {
0596                     config->default_isprotected = 0;
0597                 }
0598                 NDRX_LOG(log_debug, "protected: %c", config->default_isprotected?'Y':'N');
0599                 xmlFree(p);
0600             }
0601             else if (0==strcmp((char*)cur->name, "reloadonchange"))
0602             {
0603                 p = (char *)xmlNodeGetContent(cur);
0604                 if ('Y' == *p || 'y' == *p)
0605                 {
0606                     config->default_reloadonchange = 1;
0607                 }
0608                 else
0609                 {
0610                     config->default_reloadonchange = 0;
0611                 }
0612                 NDRX_LOG(log_debug, "reloadonchange: %c", config->default_reloadonchange?'Y':'N');
0613                 xmlFree(p);
0614             }
0615         else if (0==strcmp((char*)cur->name, "respawn"))
0616             {
0617                 p = (char *)xmlNodeGetContent(cur);
0618                 if ('N' == *p || 'n' == *p || '0' == *p)
0619                 {
0620                     config->default_respawn = 0;
0621                 }
0622 
0623                 NDRX_LOG(log_debug, "respawn: %c", config->default_respawn?'Y':'N');
0624                 xmlFree(p);
0625             }
0626             else if (0==strcmp((char*)cur->name, "rqaddr"))
0627             {
0628                 p = (char *)xmlNodeGetContent(cur);
0629                 NDRX_STRCPY_SAFE(config->default_rqaddr, p);
0630                 xmlFree(p);
0631 
0632                 /* validate the request address - it must not start with @ 
0633                  * also we need to strip down any tabs & spaces
0634                  */
0635                 if (EXSUCCEED!=rqaddr_chk(config->default_rqaddr, "defaults section"))
0636                 {
0637                     EXFAIL_OUT(ret);
0638                 }
0639 
0640                 NDRX_LOG(log_debug, "rqaddr: [%s]", config->default_rqaddr);
0641             }
0642             else if (0==strcmp((char*)cur->name, "rssmax"))
0643             {
0644                 p = (char *)xmlNodeGetContent(cur);
0645                 
0646                 if (EXSUCCEED!=ndrx_storage_decode(p, &config->default_rssmax))
0647                 {
0648                     NDRX_LOG(log_error, "Failed to parse `rssmax', invalid value");
0649                     
0650                     NDRXD_set_error_fmt(NDRXD_EINVPARAM, "Invalid value `rssmax' "
0651                             "at defaults section");
0652                     
0653                     EXFAIL_OUT(ret);
0654                 }
0655                 
0656                 NDRX_LOG(log_debug, "rssmax: %ld bytes", config->default_rssmax);
0657                 xmlFree(p);
0658             }
0659             else if (0==strcmp((char*)cur->name, "vszmax"))
0660             {
0661                 p = (char *)xmlNodeGetContent(cur);
0662                 
0663                 if (EXSUCCEED!=ndrx_storage_decode(p, &config->default_vszmax))
0664                 {
0665                     NDRX_LOG(log_error, "Failed to parse `vszmax', invalid value");
0666                     
0667                     NDRXD_set_error_fmt(NDRXD_EINVPARAM, "Invalid value `vszmax' "
0668                             "at defaults section");
0669                     
0670                     EXFAIL_OUT(ret);
0671                 }
0672                 
0673                 NDRX_LOG(log_debug, "vszmax: %ld bytes", config->default_vszmax);
0674                 xmlFree(p);
0675             }
0676             else if (0==strcmp((char*)cur->name, "mindispatchthreads"))
0677             {
0678                 p = (char *)xmlNodeGetContent(cur);
0679                 config->default_mindispatchthreads = atoi(p);
0680                 NDRX_LOG(log_debug, "default mindispatchthreads: [%s] - %d",
0681                                         p, config->default_mindispatchthreads);
0682                 xmlFree(p);
0683             }
0684             else if (0==strcmp((char*)cur->name, "maxdispatchthreads"))
0685             {
0686                 p = (char *)xmlNodeGetContent(cur);
0687                 config->default_maxdispatchthreads = atoi(p);
0688                 NDRX_LOG(log_debug, "default maxdispatchthreads: [%s] - %d",
0689                                         p, config->default_maxdispatchthreads);
0690                 xmlFree(p);
0691             }
0692             else if (0==strcmp((char*)cur->name, "threadstacksize"))
0693             {
0694                 p = (char *)xmlNodeGetContent(cur);
0695                 config->default_threadstacksize = atoi(p);
0696                 NDRX_LOG(log_debug, "default threadstacksize: [%s] - %d",
0697                                         p, config->default_threadstacksize);
0698                 xmlFree(p);
0699             }
0700             else if (0==strcmp((char*)cur->name, "killseq"))
0701             {
0702                 p = (char *)xmlNodeGetContent(cur);
0703                 
0704                 if (EXSUCCEED!=ndrx_prase_killseq(config->default_killseq, p, last_line))
0705                 {
0706                     xmlFree(p);
0707                     EXFAIL_OUT(ret);
0708                 }
0709                 
0710                 xmlFree(p);
0711             }
0712         else if (0==strcmp((char*)cur->name, "procgrp"))
0713         {
0714             ndrx_procgroup_t *p_grp;
0715             p = (char *)xmlNodeGetContent(cur);
0716 
0717             p_grp=ndrx_ndrxconf_procgroups_resolvenm(config->procgroups, p);
0718 
0719             if (NULL==p_grp)
0720             {
0721                 NDRX_LOG(log_error, "Failed to resolve default procgrp: [%s]", p);
0722                 NDRXD_set_error_fmt(NDRXD_ENOENT, "(%s) Failed to resolve procgrp: [%s] "
0723                         "near line %d", 
0724                         G_sys_config.config_file_short, p,
0725                         (int)cur->line);
0726                 xmlFree(p);
0727                 EXFAIL_OUT(ret);
0728             }
0729 
0730             config->default_procgrp_no=p_grp->grpno;
0731 
0732             NDRX_LOG(log_debug, "default procgrp: [%s] no: %d",
0733                                     p, config->default_procgrp_no);
0734             xmlFree(p);
0735         }
0736         else if (0==strcmp((char*)cur->name, "procgrp_lp"))
0737         {
0738             ndrx_procgroup_t *p_grp;
0739             p = (char *)xmlNodeGetContent(cur);
0740 
0741             p_grp=ndrx_ndrxconf_procgroups_resolvenm(config->procgroups, p);
0742 
0743             if (NULL==p_grp)
0744             {
0745                 NDRX_LOG(log_error, "Failed to resolve default procgrp_lp: [%s]", p);
0746                 NDRXD_set_error_fmt(NDRXD_ENOENT, "(%s) Failed to resolve procgrp_lp: [%s] "
0747                         "near line %d", 
0748                         G_sys_config.config_file_short, p,
0749                         (int)cur->line);
0750                 xmlFree(p);
0751                 EXFAIL_OUT(ret);
0752             }
0753             
0754             config->default_procgrp_lp_no=p_grp->grpno;
0755 
0756             NDRX_LOG(log_debug, "default procgrp_lp: [%s] no: %d",
0757                                     p, config->default_procgrp_lp_no);
0758             xmlFree(p);
0759         }
0760             
0761 #if 0
0762             else
0763             {
0764                 NDRX_LOG(log_error, "Unknown element %s", cur->name);
0765             }
0766 #endif
0767             last_line=cur->line;
0768             cur = cur->next;
0769         } while (cur);
0770     }
0771     
0772     if (!config->default_start_max)
0773     {
0774         NDRX_LOG(log_debug, "(%s) `start_max' not set at defaults section near line %d!", 
0775                 G_sys_config.config_file_short, last_line);
0776         ret=EXFAIL;
0777         goto out;
0778     }/* - Optional param. Default 0. 
0779     else if (!config->default_pingtime)
0780     {
0781         NDRX_LOG(log_debug, "(ndrxconfig.xml) `pingtime' not set!");
0782         ret=FAIL;
0783         goto out;
0784     }
0785     */
0786     else if (config->default_pingtime && !config->default_ping_max)
0787     {
0788         NDRX_LOG(log_debug, "(%s) `pingtime' set but `ping_max' not "
0789                 "set at default section", G_sys_config.config_file_short);
0790         
0791         NDRXD_set_error_fmt(NDRXD_ECFGDEFAULTS, "(%s)`pingtime' set but `ping_max' not "
0792                 "set at default section near line %d", 
0793                 G_sys_config.config_file_short, last_line);
0794         
0795         ret=EXFAIL;
0796         goto out;
0797     }
0798     else if (!config->default_end_max)
0799     {
0800         NDRX_LOG(log_debug, "`end_max' not set!");
0801         
0802         NDRXD_set_error_fmt(NDRXD_ECFGDEFAULTS, "(%s) `end_max' not set "
0803                 "at default section near line %d!", 
0804                 G_sys_config.config_file_short, 
0805                 last_line);
0806         
0807         ret=EXFAIL;
0808         goto out;
0809     }
0810     
0811     if (!config->default_srvstartwait)
0812     {
0813         config->default_srvstartwait = DEF_SRV_STARTWAIT;
0814         config->default_srvstartwait*=1000;
0815         NDRX_LOG(log_debug, "Server start wait defaulted to %ld msec",
0816                     config->default_srvstartwait);
0817     }
0818     
0819     if (!config->default_srvstopwait)
0820     {
0821         config->default_srvstopwait = DEF_SRV_STARTWAIT;
0822         config->default_srvstopwait*=1000;
0823         NDRX_LOG(log_debug, "Server stop wait defaulted to %ld msec",
0824                     config->default_srvstopwait);
0825     }
0826     
0827 
0828 out:
0829     return ret;
0830 }
0831 
0832 /**
0833  * Parse kill sequence
0834  * @param killseq config where to unload the results
0835  * @param seq sequence in standard config string format
0836  * @param last_line last parsing line
0837  * @return EXSUCCEED/EXFAIL
0838  */
0839 exprivate int ndrx_prase_killseq(int *killseq, char *seq, int last_line)
0840 {
0841     int ret=EXSUCCEED;
0842     ndrx_stdcfgstr_t* parsed=NULL, *el;
0843     int i=0;
0844     int sig;
0845     
0846     if (EXSUCCEED!=ndrx_stdcfgstr_parse(seq, &parsed))
0847     {
0848         NDRX_LOG(log_error, "Failed to killseq [%s]", seq);
0849         EXFAIL_OUT(ret);
0850     }
0851     
0852     /* validate that only 3x numbers are used? */
0853     DL_FOREACH(parsed, el)
0854     {
0855         /* validate that it is a number ... */
0856         if (!ndrx_is_numberic(el->key))
0857         {
0858             NDRX_LOG(log_debug, "Invalid `killseq' not a number [%s]", el->key);
0859             
0860             NDRXD_set_error_fmt(NDRXD_ECFGAPPCONFIG, "(%s) `killseq' "
0861                     "not a number [%s] near line %d!", 
0862                     G_sys_config.config_file_short, el->key, last_line);
0863             EXFAIL_OUT(ret);
0864         }
0865         
0866         sig = abs(atoi(el->key));
0867         
0868         if (i>=NDRX_KILLSEQ_MAX)
0869         {
0870             NDRX_LOG(log_debug, "Invalid `killseq' expected %d arguments, but have more",
0871                     NDRX_KILLSEQ_MAX);
0872             NDRXD_set_error_fmt(NDRXD_ECFGAPPCONFIG, "(%s) `killseq' "
0873                     "expected %d arguments, but have more near line %d!", 
0874                     G_sys_config.config_file_short, NDRX_KILLSEQ_MAX, last_line);
0875             EXFAIL_OUT(ret);
0876         }
0877         
0878         killseq[i] = sig;
0879         i++;
0880     }
0881     
0882 out:
0883 
0884     if (NULL!=parsed)
0885     {
0886         ndrx_stdcfgstr_free(parsed);
0887     }
0888 
0889     return ret;
0890 }
0891 
0892 /**
0893  * Parse sysconfig section in config file
0894  * @param doc
0895  * @param cur
0896  * @return
0897  */
0898 exprivate int parse_appconfig(config_t *config, xmlDocPtr doc, xmlNodePtr cur)
0899 {
0900     int ret=EXSUCCEED;
0901     char *p;
0902     int last_line=0;
0903     
0904     if (NULL!=cur)
0905     {
0906         do
0907         {
0908             if (0==strcmp((char*)cur->name, "sanity"))
0909             {
0910                 p = (char *)xmlNodeGetContent(cur);
0911                 config->sanity = atoi(p);
0912                 NDRX_LOG(log_debug, "Sanity Check: [%s] - %d",
0913                                                   p, config->sanity);
0914                 xmlFree(p);
0915             }
0916             else if (0==strcmp((char*)cur->name, "restart_min"))
0917             {
0918                 p = (char *)xmlNodeGetContent(cur);
0919                 config->restart_min = atoi(p);
0920                 NDRX_LOG(log_debug, "restart_min: [%s] - %d",
0921                                                   p, config->restart_min);
0922                 xmlFree(p);
0923             }
0924             else if (0==strcmp((char*)cur->name, "restart_step"))
0925             {
0926                 p = (char *)xmlNodeGetContent(cur);
0927                 config->restart_step = atoi(p);
0928                 NDRX_LOG(log_debug, "restart_step: [%s] - %d",
0929                                                   p, config->restart_step);
0930                 xmlFree(p);
0931             }
0932             else if (0==strcmp((char*)cur->name, "restart_max"))
0933             {
0934                 p = (char *)xmlNodeGetContent(cur);
0935                 config->restart_max = atoi(p);
0936                 NDRX_LOG(log_debug, "restart_max: [%s] - %d",
0937                                                   p, config->restart_max);
0938                 xmlFree(p);
0939             }
0940             else if (0==strcmp((char*)cur->name, "brrefresh"))
0941             {
0942                 p = (char *)xmlNodeGetContent(cur);
0943                 config->brrefresh = atoi(p);
0944                 NDRX_LOG(log_debug, "brrefresh: [%s] - %d sty",
0945                                                   p, config->brrefresh);
0946                 xmlFree(p);
0947             }
0948             else if (0==strcmp((char*)cur->name, "restart_to_check"))
0949             {
0950                 p = (char *)xmlNodeGetContent(cur);
0951                 config->restart_to_check = atoi(p);
0952                 NDRX_LOG(log_debug, "restart_to_check: [%s] - %d sec",
0953                                                   p, config->restart_to_check);
0954                 xmlFree(p);
0955             }
0956             else if (0==strcmp((char*)cur->name, "checkpm"))
0957             {
0958                 p = (char *)xmlNodeGetContent(cur);
0959                 config->checkpm = atoi(p);
0960                 NDRX_LOG(log_debug, "checkpm: [%s] - %d sty",
0961                                                   p, config->checkpm);
0962                 xmlFree(p);
0963             }
0964             else if (0==strcmp((char*)cur->name, "gather_pq_stats"))
0965             {
0966                 p = (char *)xmlNodeGetContent(cur);
0967                 if ('Y' == *p || 'y' == *p)
0968                 {
0969                     config->gather_pq_stats = 1;
0970                 }
0971                 else
0972                 {
0973                     config->gather_pq_stats = 0;
0974                 }
0975                 NDRX_LOG(log_debug, "gather_pq_stats: %c",
0976                                                   config->gather_pq_stats?'Y':'N');
0977                 xmlFree(p);
0978             }
0979             /* this is used by system v only */
0980             else if (0==strcmp((char*)cur->name, "rqaddrttl"))
0981             {
0982                 p = (char *)xmlNodeGetContent(cur);
0983                 config->rqaddrttl = atoi(p);
0984                 NDRX_LOG(log_debug, "rqaddrttl: [%s] - %d sec",
0985                                                   p, config->rqaddrttl);
0986                 xmlFree(p);
0987             }
0988             else if (0==strcmp((char*)cur->name, "ddrreload"))
0989             {
0990                 p = (char *)xmlNodeGetContent(cur);
0991                 config->ddrreload = atoi(p);
0992                 NDRX_LOG(log_debug, "ddrreload: [%s] - %d sty",
0993                                                   p, config->ddrreload);
0994                 xmlFree(p);
0995             }
0996             
0997             last_line=cur->line;
0998             cur = cur->next;
0999         } while (cur);
1000     }
1001     
1002     /* Now validate configuration - all values should have not be zero! */
1003     if (!config->sanity || config->sanity < 0)
1004     {
1005         NDRX_LOG(log_debug, "`sanity' not set or has invalid value!");
1006         NDRXD_set_error_fmt(NDRXD_ECFGAPPCONFIG, "(%s) `sanity' not "
1007                 "set or has invalid value at <appconfig> section near line %d!", 
1008                 G_sys_config.config_file_short, last_line);
1009         ret=EXFAIL;
1010         goto out;
1011     } 
1012     else if (config->restart_min < 0)
1013     {
1014         NDRX_LOG(log_debug, "Invalid value %d for `restart_min'!",
1015             config->restart_min);
1016         NDRXD_set_error_fmt(NDRXD_ECFGAPPCONFIG, 
1017         "(%s) Invalid value %d for `restart_min' near line %d!", 
1018                 G_sys_config.config_file_short, last_line);
1019         ret=EXFAIL;
1020         goto out;
1021     }
1022     /* else if (!config->restart_step) - why  ? */
1023     else if (config->restart_step < 0)
1024     {
1025         NDRX_LOG(log_debug, "`restart_step' invalid value %d!", config->restart_step);
1026         NDRXD_set_error_fmt(NDRXD_ECFGAPPCONFIG, "(%s) `restart_step' "
1027                 "has invalid value %d in <appconfig> section near line %d!", 
1028                 G_sys_config.config_file_short, config->restart_step, last_line);
1029         ret=EXFAIL;
1030         goto out;
1031     }
1032     else if (config->restart_max < 0)
1033     {
1034         NDRX_LOG(log_debug, "Invalid value %d for `restart_max'!",
1035             config->restart_max);
1036         NDRXD_set_error_fmt(NDRXD_ECFGAPPCONFIG,
1037                 "(%s) Invalid value for `restart_max' near line %d!",
1038                 G_sys_config.config_file_short, last_line);
1039         ret=EXFAIL;
1040         goto out;
1041     }
1042     else if (!config->restart_to_check)
1043     {
1044         NDRX_LOG(log_debug, "`restart_to_check' not set!");
1045         NDRXD_set_error_fmt(NDRXD_ECFGAPPCONFIG, "(%s) "
1046                 "`restart_to_check' not set at <appconfig> section near line %d!", 
1047                 G_sys_config.config_file_short, last_line);
1048         ret=EXFAIL;
1049         goto out;
1050     }
1051     
1052     if (!config->brrefresh)
1053     {
1054         NDRX_LOG(log_warn, "`brrefresh' not set - "
1055                 "period refreshes will not be sent!");
1056     }
1057     
1058     if (!config->checkpm)
1059     {
1060         config->checkpm = CHECK_PM_DEFAULT;
1061         NDRX_LOG(log_debug, "`checkpm' not set using "
1062                 "default %d sty!", config->checkpm);
1063     }
1064     
1065     if (0 >= config->rqaddrttl)
1066     {
1067         config->rqaddrttl = DEF_RQADDRTTL;
1068         NDRX_LOG(log_debug, "`rqaddrtt' not set using "
1069                 "default %d sty!", config->rqaddrttl);
1070     }
1071     
1072     if (0>= config->ddrreload)
1073     {
1074         config->ddrreload = DDRREALOAD_DEFAULT;
1075         NDRX_LOG(log_debug, "`routereload' not set using "
1076                 "default %d sty!", config->ddrreload);
1077     }
1078     
1079 out:
1080     return ret;
1081 }
1082 
1083 /**
1084  * Parser server entry
1085  * @param doc
1086  * @param cur
1087  * @param srvnm - name of the server
1088  * @return 
1089  */
1090 exprivate int parse_server(config_t *config, xmlDocPtr doc, xmlNodePtr cur)
1091 {
1092     int ret=EXSUCCEED;
1093     xmlAttrPtr attr;
1094     char srvnm[MAXTIDENT+1]={EXEOS};
1095     char tmp[128];
1096     conf_server_node_t *p_srvnode=NULL;
1097     char *p;
1098     int last_line=EXFAIL;
1099     /* first of all, we need to get server name from attribs */
1100     
1101     p_srvnode = NDRX_CALLOC(1, sizeof(conf_server_node_t));
1102     if (NULL==p_srvnode)
1103     {
1104         NDRX_LOG(log_error, "malloc failed for srvnode!");
1105         NDRXD_set_error_fmt(NDRXD_EOS, "(%s) malloc failed for srvnode!", 
1106                 G_sys_config.config_file_short);
1107         EXFAIL_OUT(ret);
1108     }
1109     
1110     p_srvnode->srvid = EXFAIL;
1111     p_srvnode->min = EXFAIL;
1112     p_srvnode->max = EXFAIL;
1113     p_srvnode->autokill = EXFAIL;
1114     p_srvnode->start_max = EXFAIL;
1115                     
1116     p_srvnode->pingtime = EXFAIL;
1117     p_srvnode->ping_max = EXFAIL;
1118     p_srvnode->end_max = EXFAIL;
1119     p_srvnode->killtime = EXFAIL;
1120     p_srvnode->exportsvcs[0] = EXEOS;
1121     p_srvnode->isprotected = EXFAIL;
1122     p_srvnode->reloadonchange = EXFAIL;
1123     p_srvnode->respawn = EXFAIL;
1124     p_srvnode->procgrp_no = EXFAIL;
1125     p_srvnode->procgrp_lp_no = EXFAIL;
1126     
1127     memcpy(p_srvnode->killseq, config->default_killseq, sizeof(config->default_killseq));
1128     
1129     p_srvnode->rssmax = config->default_rssmax;
1130     p_srvnode->vszmax = config->default_vszmax;
1131     
1132     p_srvnode->mindispatchthreads = config->default_mindispatchthreads;
1133     p_srvnode->maxdispatchthreads = config->default_maxdispatchthreads;
1134     p_srvnode->threadstacksize= config->default_threadstacksize;
1135 
1136     for (attr=cur->properties; attr; attr = attr->next)
1137     {
1138         if (0==strcmp((char *)attr->name, "name"))
1139         {
1140             p = (char *)xmlNodeGetContent(attr->children);
1141             NDRX_STRCPY_SAFE(srvnm, p);
1142             xmlFree(p);
1143         }
1144     }
1145 
1146     if (EXEOS==srvnm[0])
1147     {
1148         NDRX_LOG(log_error, "No server name at line %hd", cur->line);
1149         ret=EXFAIL;
1150         goto out;
1151     }
1152 
1153     /* Now grab the all stuff for server */
1154     cur=cur->children;
1155 
1156     for (; cur; cur=cur->next)
1157     {
1158         if (0==strcmp("srvid", (char *)cur->name))
1159         {
1160             p = (char *)xmlNodeGetContent(cur);
1161             p_srvnode->srvid = atoi(p);
1162             xmlFree(p);
1163         }
1164         else if (0==strcmp("min", (char *)cur->name))
1165         {
1166             p = (char *)xmlNodeGetContent(cur);
1167             
1168             NDRX_QENV_SUBST(tmp, p);
1169 
1170             p_srvnode->min = atoi(tmp);
1171             xmlFree(p);
1172         }
1173         else if (0==strcmp("max", (char *)cur->name))
1174         {
1175             p = (char *)xmlNodeGetContent(cur);
1176             
1177             NDRX_QENV_SUBST(tmp, p);
1178             
1179             p_srvnode->max = atoi(tmp);
1180             xmlFree(p);
1181         }
1182         else if (0==strcmp("autokill", (char *)cur->name))
1183         {
1184             p = (char *)xmlNodeGetContent(cur);
1185             p_srvnode->autokill = atoi(p);
1186             xmlFree(p);
1187         }
1188         else if (0==strcmp("sleep_after", (char *)cur->name))
1189         {
1190             p = (char *)xmlNodeGetContent(cur);
1191             p_srvnode->sleep_after = atoi(p);
1192             xmlFree(p);
1193         }
1194         /* Startup control moved here...: */
1195         else if (0==strcmp((char*)cur->name, "start_max"))
1196         {
1197             p = (char *)xmlNodeGetContent(cur);
1198             p_srvnode->start_max = atoi(p);
1199             NDRX_LOG(log_debug, "start_max: [%s] - %d", p, p_srvnode->start_max);
1200             xmlFree(p);
1201         }
1202         else if (0==strcmp((char*)cur->name, "end_max"))
1203         {
1204             p = (char *)xmlNodeGetContent(cur);
1205             p_srvnode->end_max = atoi(p);
1206             NDRX_LOG(log_debug, "end_max: [%s] - %d", p, p_srvnode->end_max);
1207             xmlFree(p);
1208         }
1209         else if (0==strcmp((char*)cur->name, "pingtime"))
1210         {
1211             p = (char *)xmlNodeGetContent(cur);
1212             p_srvnode->pingtime = atoi(p);
1213             xmlFree(p);
1214         }
1215         else if (0==strcmp((char*)cur->name, "ping_max"))
1216         {
1217             p = (char *)xmlNodeGetContent(cur);
1218             p_srvnode->ping_max = atoi(p);
1219             xmlFree(p);
1220         }
1221         else if (0==strcmp((char*)cur->name, "killtime"))
1222         {
1223             p = (char *)xmlNodeGetContent(cur);
1224             p_srvnode->killtime = atoi(p);
1225             xmlFree(p);
1226         }
1227         else if (0==strcmp((char*)cur->name, "exportsvcs"))
1228         {
1229             p = (char *)xmlNodeGetContent(cur);
1230             ndrx_str_strip(p, " \t");
1231             if (strlen(p)>=sizeof(p_srvnode->exportsvcs)-3)
1232             {
1233                 NDRX_LOG(log_warn, "Trimming server exportsvcs");
1234                 p[sizeof(p_srvnode->exportsvcs)-3] = EXEOS;
1235             }
1236             snprintf(p_srvnode->exportsvcs, sizeof(p_srvnode->exportsvcs), 
1237                     ",%s,", p);
1238             NDRX_LOG(log_debug, "exportsvcs: [%s]", 
1239                     p_srvnode->exportsvcs);
1240             xmlFree(p);
1241         }
1242         else if (0==strcmp((char*)cur->name, "blacklistsvcs"))
1243         {
1244             p = (char *)xmlNodeGetContent(cur);
1245             ndrx_str_strip(p, " \t");
1246             if (strlen(p)>=sizeof(p_srvnode->blacklistsvcs)-3)
1247             {
1248                 NDRX_LOG(log_warn, "blacklistsvcs server blacklistsvcs");
1249                 p[sizeof(p_srvnode->exportsvcs)-3] = EXEOS;
1250             }
1251             snprintf(p_srvnode->blacklistsvcs, sizeof(p_srvnode->blacklistsvcs), 
1252                     ",%s,", p);
1253             NDRX_LOG(log_debug, "blacklistsvcs: [%s]", 
1254                     p_srvnode->blacklistsvcs);
1255             xmlFree(p);
1256         }
1257         else if (0==strcmp("sysopt", (char *)cur->name))
1258         {
1259             p = (char *)xmlNodeGetContent(cur);
1260             NDRX_STRCPY_SAFE(p_srvnode->SYSOPT, p);
1261             xmlFree(p);
1262         }
1263         else if (0==strcmp("appopt", (char *)cur->name))
1264         {
1265             p = (char *)xmlNodeGetContent(cur);
1266             NDRX_STRCPY_SAFE(p_srvnode->APPOPT, p);
1267             /* Feature #331
1268              * process env - do later when building model..
1269             ndrx_str_env_subs_len(p_srvnode->APPOPT, sizeof(p_srvnode->APPOPT));
1270              * */
1271             xmlFree(p);
1272         }
1273         else if (0==strcmp("env", (char *)cur->name))
1274         {
1275             p = (char *)xmlNodeGetContent(cur);
1276             NDRX_STRCPY_SAFE(p_srvnode->env, p);
1277 
1278             /* Ensure that we terminate... */
1279             p_srvnode->env[sizeof(p_srvnode->env)-1] = EXEOS;
1280 
1281             /* process env */
1282             ndrx_str_env_subs_len(p_srvnode->env, sizeof(p_srvnode->env));
1283 
1284             xmlFree(p);
1285         }
1286         else if (0==strcmp((char*)cur->name, "srvstartwait"))
1287         {
1288             p = (char *)xmlNodeGetContent(cur);
1289             p_srvnode->srvstartwait = atoi(p)*1000;
1290             NDRX_LOG(log_debug, "srvstartwait: [%s] - %d msec",
1291                                               p, p_srvnode->srvstartwait);
1292             xmlFree(p);
1293         }
1294         else if (0==strcmp((char*)cur->name, "srvstopwait"))
1295         {
1296             p = (char *)xmlNodeGetContent(cur);
1297             p_srvnode->srvstopwait = atoi(p)*1000;
1298             NDRX_LOG(log_debug, "srvstopwait: [%s] - %d msec",
1299                                               p, p_srvnode->srvstopwait);
1300             xmlFree(p);
1301         }
1302         else if (0==strcmp((char*)cur->name, "cctag"))
1303         {
1304             p = (char *)xmlNodeGetContent(cur);
1305             NDRX_STRCPY_SAFE(p_srvnode->cctag, p);
1306             /* process env */
1307             ndrx_str_env_subs_len(p_srvnode->cctag, sizeof(p_srvnode->cctag));
1308             xmlFree(p);
1309         }
1310         else if (0==strcmp((char*)cur->name, "protected"))
1311         {
1312             p = (char *)xmlNodeGetContent(cur);
1313             if ('Y' == *p || 'y' == *p)
1314             {
1315                 p_srvnode->isprotected = 1;
1316             }
1317             else
1318             {
1319                 p_srvnode->isprotected = 0;
1320             }
1321             NDRX_LOG(log_debug, "protected: %c",
1322                                               p_srvnode->isprotected?'Y':'N');
1323             xmlFree(p);
1324         }
1325         else if (0==strcmp((char*)cur->name, "reloadonchange"))
1326         {
1327             p = (char *)xmlNodeGetContent(cur);
1328             if ('Y' == *p || 'y' == *p)
1329             {
1330                 p_srvnode->reloadonchange = 1;
1331             }
1332             else
1333             {
1334                 p_srvnode->reloadonchange = 0;
1335             }
1336             NDRX_LOG(log_debug, "reloadonchange: %c",
1337                                               p_srvnode->reloadonchange?'Y':'N');
1338             xmlFree(p);
1339         }
1340     else if (0==strcmp((char*)cur->name, "respawn"))
1341         {
1342             p = (char *)xmlNodeGetContent(cur);
1343             if ('N' == *p || 'n' == *p || '0' == *p)
1344             {
1345                 p_srvnode->respawn = 0;
1346             }
1347             else
1348             {
1349                 p_srvnode->respawn = 1;
1350             }
1351             NDRX_LOG(log_debug, "respawn: %c",
1352                                               p_srvnode->respawn?'Y':'N');
1353             xmlFree(p);
1354         }
1355         else if (0==strcmp((char*)cur->name, "fullpath"))
1356         {
1357             p = (char *)xmlNodeGetContent(cur);
1358             NDRX_STRCPY_SAFE(p_srvnode->fullpath, p);
1359             /* process env */
1360             ndrx_str_env_subs_len(p_srvnode->fullpath, sizeof(p_srvnode->fullpath));
1361             xmlFree(p);
1362             
1363             NDRX_LOG(log_debug, "fullpath: [%s]", p_srvnode->fullpath);
1364         }
1365         else if (0==strcmp((char*)cur->name, "cmdline"))
1366         {
1367             p = (char *)xmlNodeGetContent(cur);
1368             NDRX_STRCPY_SAFE(p_srvnode->cmdline, p);
1369             xmlFree(p);
1370             NDRX_LOG(log_debug, "cmdline: [%s]", p_srvnode->cmdline);
1371         }
1372         else if (0==strcmp((char*)cur->name, "envs"))
1373         {
1374             
1375             if (EXSUCCEED!=ndrx_ndrxconf_envs_parse(doc, cur, 
1376                 &p_srvnode->envlist, config->envgrouphash, 
1377                         &p_srvnode->envgrouplist))
1378             {
1379                 NDRX_LOG(log_error, "Failed to load environment variables for server [%d]", 
1380                         p_srvnode->srvid);
1381                 NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to load <envs> tag "
1382                         "for server srvid=%d",
1383                         p_srvnode->srvid);
1384                 EXFAIL_OUT(ret);
1385             }
1386         }
1387         else if (0==strcmp((char*)cur->name, "rqaddr"))
1388         {
1389             char tmpbuf[64];
1390             p = (char *)xmlNodeGetContent(cur);
1391             NDRX_STRCPY_SAFE(p_srvnode->rqaddr, p);
1392             xmlFree(p);
1393             
1394             /* validate the request address - it must not start with @ 
1395              * also we need to strip down any tabs & spaces
1396              */
1397             snprintf(tmpbuf, sizeof(tmpbuf), "srvid=%d near line %d", 
1398                     p_srvnode->srvid, (int)cur->line);
1399             
1400             if (EXSUCCEED!=rqaddr_chk(p_srvnode->rqaddr, tmpbuf))
1401             {
1402                 EXFAIL_OUT(ret);
1403             }
1404             
1405             NDRX_LOG(log_debug, "rqaddr: [%s]", p_srvnode->rqaddr);
1406         }
1407         else if (0==strcmp((char*)cur->name, "rssmax"))
1408         {
1409             p = (char *)xmlNodeGetContent(cur);
1410 
1411             if (EXSUCCEED!=ndrx_storage_decode(p, &p_srvnode->rssmax))
1412             {
1413                 NDRX_LOG(log_error, "Failed to parse `rssmax', invalid value");
1414                 
1415                 NDRXD_set_error_fmt(NDRXD_EINVPARAM, "(%s) Invalid value `rssmax' "
1416                             "at srvid=%d near lines %d", 
1417                         G_sys_config.config_file_short, p_srvnode->srvid,
1418                         (int)cur->line);
1419                 
1420                 EXFAIL_OUT(ret);
1421             }
1422 
1423             NDRX_LOG(log_debug, "rssmax: %ld bytes", p_srvnode->rssmax);
1424             xmlFree(p);
1425         }
1426         else if (0==strcmp((char*)cur->name, "vszmax"))
1427         {
1428             p = (char *)xmlNodeGetContent(cur);
1429 
1430             if (EXSUCCEED!=ndrx_storage_decode(p, &p_srvnode->vszmax))
1431             {
1432                 NDRX_LOG(log_error, "Failed to parse `vszmax', invalid value");
1433                 
1434                 NDRXD_set_error_fmt(NDRXD_EINVPARAM, "(%s) Invalid value `vszmax' "
1435                             "at srvid=%d near line %d", 
1436                             G_sys_config.config_file_short, p_srvnode->srvid,
1437                             (int)cur->line);
1438                 
1439                 EXFAIL_OUT(ret);
1440             }
1441 
1442             NDRX_LOG(log_debug, "vszmax: %ld bytes", p_srvnode->vszmax);
1443             xmlFree(p);
1444         }
1445         else if (0==strcmp((char*)cur->name, "mindispatchthreads"))
1446         {
1447             p = (char *)xmlNodeGetContent(cur);
1448             p_srvnode->mindispatchthreads = atoi(p);
1449             NDRX_LOG(log_debug, "mindispatchthreads: [%s] - %d",
1450                                     p, p_srvnode->mindispatchthreads);
1451             xmlFree(p);
1452         }
1453         else if (0==strcmp((char*)cur->name, "maxdispatchthreads"))
1454         {
1455             p = (char *)xmlNodeGetContent(cur);
1456             p_srvnode->maxdispatchthreads = atoi(p);
1457             NDRX_LOG(log_debug, "maxdispatchthreads: [%s] - %d",
1458                                     p, p_srvnode->maxdispatchthreads);
1459             xmlFree(p);
1460         }
1461         else if (0==strcmp((char*)cur->name, "threadstacksize"))
1462         {
1463             p = (char *)xmlNodeGetContent(cur);
1464             p_srvnode->threadstacksize = atoi(p);
1465             NDRX_LOG(log_debug, "threadstacksize: [%s] - %d",
1466                                     p, p_srvnode->threadstacksize);
1467             xmlFree(p);
1468         }
1469         else if (0==strcmp((char*)cur->name, "killseq"))
1470         {
1471             p = (char *)xmlNodeGetContent(cur);
1472 
1473             if (EXSUCCEED!=ndrx_prase_killseq(p_srvnode->killseq, p, last_line))
1474             {
1475                 xmlFree(p);
1476                 EXFAIL_OUT(ret);
1477             }
1478 
1479             xmlFree(p);
1480         }
1481         else if (0==strcmp((char*)cur->name, "procgrp"))
1482         {
1483             ndrx_procgroup_t *p_grp;
1484             p = (char *)xmlNodeGetContent(cur);
1485 
1486             p_grp=ndrx_ndrxconf_procgroups_resolvenm(config->procgroups, p);
1487 
1488             if (NULL==p_grp)
1489             {
1490                 NDRX_LOG(log_error, "Failed to resolve procgrp: [%s]", p);
1491                 NDRXD_set_error_fmt(NDRXD_ENOENT, "(%s) Failed to resolve procgrp: [%s] "
1492                         "at srvid=%d near line %d", 
1493                         G_sys_config.config_file_short, p, p_srvnode->srvid,
1494                         (int)cur->line);
1495                 xmlFree(p);
1496                 EXFAIL_OUT(ret);
1497             }
1498 
1499             p_srvnode->procgrp_no=p_grp->grpno;
1500 
1501             NDRX_LOG(log_debug, "procgrp: [%s] no: %d",
1502                                     p, p_srvnode->procgrp_no);
1503             xmlFree(p);
1504         }
1505         else if (0==strcmp((char*)cur->name, "procgrp_lp"))
1506         {
1507             ndrx_procgroup_t *p_grp;
1508             p = (char *)xmlNodeGetContent(cur);
1509 
1510             p_grp=ndrx_ndrxconf_procgroups_resolvenm(config->procgroups, p);
1511 
1512             if (NULL==p_grp)
1513             {
1514                 NDRX_LOG(log_error, "Failed to resolve procgrp_lp: [%s]", p);
1515                 NDRXD_set_error_fmt(NDRXD_ENOENT, "(%s) Failed to resolve procgrp_lp: [%s] "
1516                         "at srvid=%d near line %d", 
1517                         G_sys_config.config_file_short, p, p_srvnode->srvid,
1518                         (int)cur->line);
1519                 xmlFree(p);
1520                 EXFAIL_OUT(ret);
1521             }
1522             
1523             p_srvnode->procgrp_lp_no=p_grp->grpno;
1524 
1525             NDRX_LOG(log_debug, "procgrp_lp: [%s] no: %d",
1526                                     p, p_srvnode->procgrp_lp_no);
1527             xmlFree(p);
1528         }
1529         
1530         last_line = cur->line;
1531     }
1532     
1533     /* get rqaddr defaults */
1534     
1535     if (EXEOS==p_srvnode->rqaddr[0])
1536     {
1537         NDRX_STRCPY_SAFE(p_srvnode->rqaddr, config->default_rqaddr);
1538     }
1539     
1540     if (EXEOS!=p_srvnode->rqaddr[0])
1541     {
1542         snprintf(p_srvnode->clopt, sizeof(p_srvnode->clopt),
1543                 "%s -R %s -- %s", p_srvnode->SYSOPT, 
1544                 p_srvnode->rqaddr, p_srvnode->APPOPT);
1545     }
1546     else
1547     {
1548         snprintf(p_srvnode->clopt, sizeof(p_srvnode->clopt),
1549                 "%s -- %s", p_srvnode->SYSOPT, p_srvnode->APPOPT);
1550     }
1551     
1552     NDRX_STRCPY_SAFE(p_srvnode->binary_name, srvnm);
1553     
1554     if (EXFAIL==p_srvnode->max)
1555         p_srvnode->max=config->default_max;
1556 
1557     if (EXFAIL==p_srvnode->min)
1558         p_srvnode->min=config->default_min;
1559     
1560     if (EXFAIL==p_srvnode->autokill)
1561         p_srvnode->autokill=config->default_autokill;
1562     
1563     /* Process control params: */
1564     if (EXFAIL==p_srvnode->start_max)
1565         p_srvnode->start_max=config->default_start_max;
1566     
1567     if (EXFAIL==p_srvnode->end_max)
1568         p_srvnode->end_max=config->default_end_max;
1569     
1570     if (EXFAIL==p_srvnode->pingtime)
1571         p_srvnode->pingtime=config->default_pingtime;
1572     
1573     if (EXFAIL==p_srvnode->ping_max)
1574         p_srvnode->ping_max=config->default_ping_max;
1575     
1576     /* Copy default env override */
1577     if (EXEOS==p_srvnode->env[0] && EXEOS!=config->default_env[0])
1578         NDRX_STRCPY_SAFE(p_srvnode->env, config->default_env);
1579     
1580     if (EXFAIL==p_srvnode->killtime)
1581         p_srvnode->killtime=config->default_killtime;
1582     
1583     /* it could be empty for defaults too - then no problem.  */
1584     if (EXEOS==p_srvnode->exportsvcs[0])
1585         NDRX_STRCPY_SAFE(p_srvnode->exportsvcs, config->default_exportsvcs);
1586     
1587     if (EXEOS==p_srvnode->blacklistsvcs[0])
1588         NDRX_STRCPY_SAFE(p_srvnode->blacklistsvcs, config->default_blacklistsvcs);
1589     
1590     if (!p_srvnode->srvstartwait)
1591         p_srvnode->srvstartwait=config->default_srvstartwait;
1592     
1593     if (!p_srvnode->srvstopwait)
1594         p_srvnode->srvstopwait=config->default_srvstopwait;
1595     
1596     if (EXEOS==p_srvnode->cctag[0])
1597         NDRX_STRCPY_SAFE(p_srvnode->cctag, config->default_cctag);
1598     
1599     if (EXFAIL==p_srvnode->isprotected)
1600         p_srvnode->isprotected = config->default_isprotected;
1601     
1602     if (EXFAIL==p_srvnode->reloadonchange)
1603         p_srvnode->reloadonchange = config->default_reloadonchange;
1604     
1605     if (EXFAIL==p_srvnode->respawn)
1606         p_srvnode->respawn = config->default_respawn;
1607 
1608     if (EXFAIL==p_srvnode->procgrp_no)
1609         p_srvnode->procgrp_no = config->default_procgrp_no;
1610 
1611     if (EXFAIL==p_srvnode->procgrp_lp_no)
1612         p_srvnode->procgrp_lp_no = config->default_procgrp_lp_no;
1613     
1614     if (p_srvnode->ping_max && !p_srvnode->ping_max)
1615     {
1616         NDRX_LOG(log_error, "`ping_max' not set for server! srvid=%hd", 
1617                 p_srvnode->srvid);
1618         
1619         NDRXD_set_error_fmt(NDRXD_ECFGSERVER, "(%s) `ping_max' not set for server! "
1620                 "srvid=%hd near %d line", G_sys_config.config_file_short, 
1621                 p_srvnode->srvid, last_line);
1622         
1623         ret=EXFAIL;
1624         goto out;
1625     }
1626     
1627     /* check the config.. */
1628     if (p_srvnode->maxdispatchthreads< p_srvnode->mindispatchthreads)
1629     {
1630         NDRX_LOG(log_error, "maxdispatchthreads (%d) < mindispatchthreads (%d) "
1631                 "srvid=%hd near line %d", 
1632                 p_srvnode->maxdispatchthreads, p_srvnode->mindispatchthreads, 
1633                 p_srvnode->srvid, last_line);
1634         
1635         NDRXD_set_error_fmt(NDRXD_ECFGSERVER, "(%s) maxdispatchthreads "
1636                 "(%d) < mindispatchthreads (%d) "
1637                 "srvid=%hd near line %d", 
1638                 G_sys_config.config_file_short,
1639                 p_srvnode->maxdispatchthreads, p_srvnode->mindispatchthreads, 
1640                 p_srvnode->srvid, last_line);
1641         
1642         ret=EXFAIL;
1643         goto out;
1644     }
1645     
1646     if (EXFAIL==p_srvnode->srvid)
1647     {
1648         NDRX_LOG(log_error, "No <srvid> near of line %d", last_line);
1649         NDRXD_set_error_fmt(NDRXD_ECFGSERVER, "(%s) No <srvid> for "
1650                 "server block near of line %d", G_sys_config.config_file_short,
1651                 last_line);
1652         ret=EXFAIL;
1653         goto out;
1654     }
1655 
1656     NDRX_LOG(log_debug, "Adding: %s SRVID=%d MIN=%d MAX=%d "
1657             "CLOPT=\"%s\" ENV=\"%s\" START_MAX=%d END_MAX=%d PINGTIME=%d PING_MAX=%d "
1658             "EXPORTSVCS=\"%s\" START_WAIT=%d STOP_WAIT=%d CCTAG=\"%s\" RELOADONCHANGE=\"%c\""
1659         "RESPAWN=\"%c\" FULLPATH=\"%s\" CMDLINE=\"%s\" RSSMAX=%ld VSZMAX=%ld "
1660             "MINDISPATCHTHREADS=%d MAXDISPATCHTHREADS=%d THREADSTACKSIZE=%d PROCGRP(no)=%d PROCGRP_LP(no)=%d",
1661                     p_srvnode->binary_name, p_srvnode->srvid, p_srvnode->min,
1662                     p_srvnode->max, p_srvnode->clopt, p_srvnode->env,
1663                     p_srvnode->start_max, p_srvnode->end_max, p_srvnode->pingtime, 
1664                     p_srvnode->ping_max,
1665                     p_srvnode->exportsvcs,
1666                     p_srvnode->srvstartwait,
1667                     p_srvnode->srvstopwait,
1668                     p_srvnode->cctag,
1669                     p_srvnode->reloadonchange?'Y':'N',
1670                     p_srvnode->respawn?'Y':'N',
1671                     p_srvnode->fullpath,
1672                     p_srvnode->cmdline,
1673                     p_srvnode->rssmax,
1674                     p_srvnode->vszmax,
1675                     p_srvnode->mindispatchthreads,
1676                     p_srvnode->maxdispatchthreads,
1677                     p_srvnode->threadstacksize,
1678                     p_srvnode->procgrp_no,
1679                     p_srvnode->procgrp_lp_no
1680                     );
1681     DL_APPEND(config->monitor_config, p_srvnode);
1682 
1683 out:
1684     if (EXFAIL==ret && p_srvnode)
1685     {
1686         NDRX_FREE(p_srvnode);
1687     }
1688 
1689     return ret;
1690 }
1691 /**
1692  * parse server entries
1693  * @param doc
1694  * @param cur
1695  * @return
1696  */
1697 exprivate int parse_servers(config_t *config, xmlDocPtr doc, xmlNodePtr cur)
1698 {
1699     int ret=EXSUCCEED;
1700     char *p;
1701     
1702     for (; cur ; cur=cur->next)
1703     {
1704         if (0==strcmp((char*)cur->name, "server"))
1705         {
1706             /* Get the server name */
1707             if (EXSUCCEED!=parse_server(config, doc, cur))
1708             {
1709                 NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to "
1710                         "parse <server> section", G_sys_config.config_file_short);
1711                 ret=EXFAIL;
1712                 goto out;
1713             }
1714         }
1715     }
1716 out:
1717     return ret;
1718 }
1719 
1720 /**
1721  * parse client/exec entries, validate <procgrp>
1722  * @param doc
1723  * @param cur
1724  * @return
1725  */
1726 exprivate int parse_client_exec(config_t *config, xmlDocPtr doc, xmlNodePtr cur)
1727 {
1728     int ret=EXSUCCEED;
1729     char *p;
1730     xmlAttrPtr attr;
1731     
1732     for (attr=cur->properties; attr; attr = attr->next)
1733     {
1734         if (0==strcmp((char *)attr->name, "procgrp"))
1735         {
1736             p = (char *)xmlNodeGetContent(attr->children);
1737 
1738             if (NULL==ndrx_ndrxconf_procgroups_resolvenm(config->procgroups, p))
1739             {
1740                 NDRX_LOG(log_error, "(%s) Invalid `procgrp' attribute value [%s] "
1741                     "for <exec> section near line %d: group not found", 
1742                     G_sys_config.config_file_short, p, cur->line);
1743                 NDRXD_set_error_fmt(NDRXD_ENOENT, "(%s) Invalid `procgrp' attribute value [%s] "
1744                     "for <exec> section near line %d: group not found", 
1745                     G_sys_config.config_file_short, p, cur->line);
1746                 xmlFree(p);
1747                 EXFAIL_OUT(ret);
1748             }
1749             xmlFree(p);
1750             break;
1751         }
1752     }
1753 
1754 out:
1755     return ret;
1756 }
1757 
1758 /**
1759  * parse client entries. Validate <procgrp>
1760  * @param doc
1761  * @param cur
1762  * @return
1763  */
1764 exprivate int parse_client(config_t *config, xmlDocPtr doc, xmlNodePtr cur)
1765 {
1766     int ret=EXSUCCEED;
1767     char *p;
1768     xmlAttrPtr attr;
1769     
1770     /* validate attribs.. */
1771     for (attr=cur->properties; attr; attr = attr->next)
1772     {
1773         if (0==strcmp((char *)attr->name, "procgrp"))
1774         {
1775             p = (char *)xmlNodeGetContent(attr->children);
1776 
1777             if (NULL==ndrx_ndrxconf_procgroups_resolvenm(config->procgroups, p))
1778             {
1779                 NDRX_LOG(log_error, "(%s) Invalid `procgrp' attribute value [%s] "
1780                     "for <client> section near line %d: group not found", 
1781                     G_sys_config.config_file_short, p, cur->line);
1782                 NDRXD_set_error_fmt(NDRXD_ENOENT, "(%s) Invalid `procgrp' attribute value [%s] "
1783                     "for <client> section near line %d: group not found", 
1784                     G_sys_config.config_file_short, p, cur->line);
1785 
1786                 xmlFree(p);
1787                 EXFAIL_OUT(ret);
1788             }
1789 
1790             xmlFree(p);
1791             break;
1792         }
1793     }
1794 
1795     for (; cur ; cur=cur->next)
1796     {
1797         if (0==strcmp((char*)cur->name, "client"))
1798         {
1799             /* Get the server name */
1800             if (EXSUCCEED!=parse_client_exec(config, doc, cur))
1801             {
1802                 NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to "
1803                         "parse <exec> section", G_sys_config.config_file_short);
1804 
1805                 EXFAIL_OUT(ret);
1806             }
1807         }
1808     }
1809 out:
1810     return ret;
1811 }
1812 
1813 /**
1814  * parse client entries
1815  * @param doc
1816  * @param cur
1817  * @return
1818  */
1819 exprivate int parse_clients(config_t *config, xmlDocPtr doc, xmlNodePtr cur)
1820 {
1821     int ret=EXSUCCEED;
1822     char *p;
1823     
1824     for (; cur ; cur=cur->next)
1825     {
1826         if (0==strcmp((char*)cur->name, "client"))
1827         {
1828             /* Get the server name */
1829             if (EXSUCCEED!=parse_client(config, doc, cur))
1830             {
1831                 NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to "
1832                         "parse <client> section", G_sys_config.config_file_short);
1833                 ret=EXFAIL;
1834                 goto out;
1835             }
1836         }
1837     }
1838 out:
1839     return ret;
1840 }
1841 
1842 /**
1843  * Parse config out...
1844  * @param doc
1845  * @return
1846  */
1847 exprivate int parse_config(config_t *config, xmlDocPtr doc, xmlNodePtr cur)
1848 {
1849     int ret=EXSUCCEED;
1850     int appconfig_found=EXFALSE;
1851     ndrx_ndrxconf_err_t err;
1852 
1853     G_sys_config.last_line = 0;
1854     if (NULL==cur)
1855     {
1856         NDRX_LOG(log_error, "Empty config?");
1857         NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Emtpy config?",
1858                 G_sys_config.config_file_short);
1859         ret=EXFAIL;
1860         goto out;
1861     }
1862 
1863     config->ctl_had_defaults = EXFALSE;
1864     /* Loop over root elements */
1865     do
1866     {
1867         if (0==strcmp((char*)cur->name, "defaults")
1868                 && EXSUCCEED!=parse_defaults(config, doc, cur->children))
1869         {
1870             NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to "
1871                     "parse <defaults>", G_sys_config.config_file_short);
1872             ret=EXFAIL;
1873             goto out;
1874         }
1875         else if (0==strcmp((char*)cur->name, "servers")
1876                 && EXSUCCEED!=parse_servers(config, doc, cur->children))
1877         {
1878             NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to "
1879                     "parse <servers>", G_sys_config.config_file_short);
1880             ret=EXFAIL;
1881             goto out;
1882         }
1883         else if (0==strcmp((char*)cur->name, "services")
1884                 && EXSUCCEED!=ndrx_services_parse(config, doc, cur->children))
1885         {
1886             NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to "
1887                     "parse <services>", G_sys_config.config_file_short);
1888             ret=EXFAIL;
1889             goto out;
1890         }
1891         else if (0==strcmp((char*)cur->name, "routing")
1892                 && EXSUCCEED!=ndrx_routing_parse(config, doc, cur->children))
1893         {
1894             NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to "
1895                     "parse <routing>", G_sys_config.config_file_short);
1896             ret=EXFAIL;
1897             goto out;
1898         }
1899         else if (0==strcmp((char*)cur->name, "appconfig")
1900                 && (appconfig_found=EXTRUE)
1901                 && EXSUCCEED!=parse_appconfig(config, doc, cur->children))
1902         {
1903             NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to parse <appconfig>",
1904                     G_sys_config.config_file_short);
1905             ret=EXFAIL;
1906             goto out;
1907         }
1908         else if (0==strcmp((char*)cur->name, "procgroups")
1909                 && EXSUCCEED!=ndrx_ndrxconf_procgroups_parse(&config->procgroups, doc, cur->children, 
1910                     G_sys_config.config_file_short, &err))
1911         {
1912             NDRXD_set_error_fmt(err.error_code, err.error_msg);
1913             ret=EXFAIL;
1914             goto out;
1915         } 
1916         /* parse clients to validate procgrp attrib in <client> and <client>/<exec> sections */
1917         else if (0==strcmp((char*)cur->name, "clients")
1918                 && EXSUCCEED!=parse_clients(config, doc, cur->children))
1919         {
1920             NDRXD_set_error_fmt(err.error_code, err.error_msg);
1921             ret=EXFAIL;
1922             goto out;
1923         }
1924 #if 0
1925         else
1926         {
1927             NDRX_LOG(log_error, "Unknown element %s!");
1928         }
1929 #endif
1930         cur=cur->next;
1931     } while (cur);
1932 
1933     /* Check for appconfig presence */
1934     if (!appconfig_found)
1935     {
1936         NDRX_LOG(log_error, "<appconfig> section not found in config!");
1937         NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) <appconfig> "
1938                 "section not found in config!", G_sys_config.config_file_short);
1939         ret=EXFAIL;
1940         goto out;
1941     }
1942     
1943     /* gen routing blocks */
1944     if (EXSUCCEED!=ndrx_ddr_gen_blocks(config))
1945     {
1946         NDRX_LOG(log_error, "Failed to generate routing blocks");
1947         NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Failed to generate routing blocks",
1948                 G_sys_config.config_file_short);
1949         ret=EXFAIL;
1950         goto out;
1951     }
1952 
1953 out:
1954     return ret;
1955 }
1956 
1957 /**
1958  * Set error from xml data
1959  * @param userData
1960  * @param error
1961  */
1962 void ndrx_xmlStructuredErrorFunc(void *userData, xmlErrorPtr error)
1963 {
1964     char tmp[512];
1965     int len;
1966 
1967     NDRX_STRCPY_SAFE(tmp, error->message);
1968 
1969     ndrx_str_rstrip(tmp, "\r\n");
1970 
1971     if (NULL==error->file)
1972     {
1973         NDRXD_set_error_fmt(NDRXD_EACCES, "(%s) Failed to open config file: %s", 
1974             G_sys_config.config_file_short, tmp);
1975     }
1976     else
1977     {
1978         NDRXD_set_error_fmt(NDRXD_ESYNTAX, "(%s) Parsing XML failed, near line %d: %s", 
1979             G_sys_config.config_file_short, error->line, tmp);
1980     }
1981     
1982     NDRX_LOG(log_error, "Parsing XML %s failed on line %d: %s", 
1983             error->file?error->file:"N/A", error->line, tmp);
1984 }
1985 
1986 /**
1987  * Parses & Loads the platform configuration file.
1988  *
1989  * This initially loads the configuration int internal represtation of the
1990  * configuration file. After that from this info we will build work structures.
1991  */
1992 expublic int load_config(config_t *config, char *config_file)
1993 {
1994     int ret=EXSUCCEED;
1995     xmlDocPtr doc;
1996     xmlNodePtr root;
1997     
1998     xmlSetStructuredErrorFunc   (NULL, ndrx_xmlStructuredErrorFunc);
1999     
2000     doc = xmlReadFile(config_file, NULL, XML_PARSE_NOENT);
2001 
2002     if (!doc)
2003     {
2004         NDRX_LOG(log_error, "Failed to open or parse %s", config_file);
2005         NDRXD_set_error_fmt(NDRXD_EACCES, "(%s) Failed to open or parse XML", 
2006                 G_sys_config.config_file_short);
2007         ret=EXFAIL;
2008         goto out;
2009     }
2010 
2011     /* Get root element */
2012     if (!(root = xmlDocGetRootElement(doc)))
2013     {
2014         NDRX_LOG(log_error, "Failed to get root XML element");
2015         NDRXD_set_error_fmt(NDRXD_ECFGINVLD, "(%s) Invalid XML config: "
2016                 "Failed to get root XML element", G_sys_config.config_file_short);
2017         ret=EXFAIL;
2018         goto out;
2019     }
2020 
2021     /* Step into first children */
2022     ret=parse_config(config, doc, root->children);
2023     
2024 out:
2025 
2026     if (NULL!=doc)
2027     {
2028         /*free the document */
2029         xmlFreeDoc(doc);
2030         /*
2031          *Free the global variables that may
2032          *have been allocated by the parser.
2033          */
2034         xmlCleanupParser();
2035     }
2036 
2037     return ret;
2038 }
2039 
2040 
2041 /**
2042  * This function does test the config. If active config is loaded, then process
2043  * model is being checked. If something removed from active config or collides with running
2044  * processes, then error is returned.
2045  * So basic rules is:
2046  * - If config does not changes, then process can be in any state
2047  * - If config changes, then:
2048  * --If new process is added, and srvid is free, then no prob
2049  * --If new process is added, but srvid is taken, then
2050  * ---Check if taken process is shutdown. If not shutdown, then raise error
2051  * --If in processess model there is srvid which is not present in new config, then
2052  * ---It will be removed from pmodel, but it must be shutdown, otherwise it is error.
2053  * @return
2054  */
2055 expublic int test_config(int reload, command_call_t * call, 
2056         void (*p_reload_error)(command_call_t * call, int srvid, 
2057         char *old_bin, char *new_bin, int error, char *msg))
2058 {
2059     int ret=EXSUCCEED;
2060     int i;
2061     int new_error=EXFALSE;
2062     int old_error=EXFALSE;
2063     int do_free = EXFALSE;
2064 
2065     /*
2066      * Active monitor configuration
2067      */
2068     config_t *t_app_config=NULL;
2069     config_t *old_app_config=NULL;
2070 
2071     /*
2072      * Active process model handler - linked list
2073      */
2074     pm_node_t *t_process_model = NULL;
2075     pm_node_t *old_process_model = NULL;
2076 
2077     /*
2078      * Active Hash list by service IDs
2079      */
2080     pm_node_t **t_process_model_hash = NULL;
2081     pm_node_t **old_process_model_hash = NULL;
2082 
2083     /*
2084      * PID Hash table
2085      */
2086     pm_pidhash_t **t_process_model_pid_hash = NULL;
2087     pm_pidhash_t **old_process_model_pid_hash = NULL;
2088 
2089 
2090     pm_node_t *old, *new;
2091 
2092     if (EXSUCCEED!=load_active_config(&t_app_config, &t_process_model,
2093                 &t_process_model_hash, &t_process_model_pid_hash))
2094     {
2095         NDRX_LOG(log_error, "Failed to load new configuration & build pmodel!");
2096         
2097         /* p_reload_error -> try to load config */
2098         if (NULL!=p_reload_error)
2099         {
2100             /* return config error */
2101             p_reload_error(call, 0, "", "", ndrxd_errno, 
2102                     ndrxd_strerror(ndrxd_errno));
2103         }
2104         
2105         ret=EXFAIL;
2106         goto out;
2107     }
2108     /* If not active config present, then we have nothing to do */
2109     if (NULL==G_app_config)
2110     {
2111         NDRX_LOG(log_debug, "Active config not loaded, nothing to do.");
2112         do_free=EXTRUE;
2113         /* free up the config otherwise we get leak.. */
2114         goto out;
2115     }
2116 
2117     /* I think we need two loops:
2118      * 1. loop
2119      * If first we go over all new configs PM, and check Old srv hash.
2120      * If server names & id the same, then OK
2121      * If server names differ for id, then old must be shut down
2122      * If server name not taken, then all, this is new binary
2123      * TODO: If server is lock provider, check that lp group in new config matches actual group
2124      *   (that's in case if binary is running)
2125      * --------------------------
2126      * 2. loop
2127      * We go over the old PM, and check new hash.
2128      * If server names & id not the same, then current must be shutdown
2129      * If server id not present in hash, then this must be shutdown
2130      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2131      * We will loop over all details, so that in log we could lookup for full
2132      * error details.
2133      */
2134     DL_FOREACH(t_process_model, new)
2135     {
2136         /* check boundary! */
2137         old = G_process_model_hash[new->srvid];
2138         if (NULL==old)
2139         {
2140             NDRX_LOG(log_debug, "New server id=%d", new->srvid);
2141         }
2142         else if (0!=strcmp(old->binary_name, new->binary_name))
2143         {
2144             if (NDRXD_PM_EXIT!=old->state)
2145             {
2146                 NDRX_LOG(log_error, "Renamed binary [%s] for "
2147                         "serverid=%d is in non shutdown state (%d)! New binary for this id is [%s]",
2148                         old->binary_name, new->srvid, old->state, new->binary_name);
2149 
2150                 /* Give some feedback to console */
2151                 if (NULL!=p_reload_error)
2152                     p_reload_error(call, new->srvid, old->binary_name,
2153                                 new->binary_name, NDRXD_EREBBINARYRUN, "");
2154                 
2155                 if (!new_error)
2156                 {
2157                     /* This is error case */
2158                     NDRXD_set_error_fmt(NDRXD_EREBBINARYRUN, "(%s) Renamed binary [%s] for "
2159                             "serverid=%d is in non shutdown state (%d)! New binary for this id is [%s]",
2160                             G_sys_config.config_file_short, 
2161                             old->binary_name, new->srvid, old->state, new->binary_name);
2162                 }
2163                 new_error=EXTRUE;
2164             }
2165             else
2166             {
2167                 NDRX_LOG(log_debug, "Server id=%d renamed (from [%s] "
2168                                 "to [%s]) and binary is shutdown",
2169                                 new->srvid, old->binary_name, new->binary_name);
2170             }
2171         }
2172         else if (PM_RUNNING(old->state) 
2173                 && old->procgrp_lp_no > 0 
2174                 && old->procgrp_lp_no != new->conf->procgrp_lp_no)
2175         {
2176             NDRXD_set_error_fmt(NDRXD_EREBBINARYRUN, "(%s) Lock provider [%s]/%d must be shutdown prior "
2177                             "changing locking group (from %d to %d)",
2178                             G_sys_config.config_file_short, 
2179                             old->binary_name, old->srvid, old->procgrp_lp_no, new->conf->procgrp_lp_no);
2180             new_error=EXTRUE;
2181         }
2182         else
2183         {
2184 
2185             NDRX_LOG(log_debug, "Binary name [%s] not "
2186                             "changed for server id=%d",
2187                             old->binary_name, new->srvid);
2188         }
2189     }
2190     /*
2191      * In this case we just test, that there are no binaries which are not found in
2192      * old config. If so then they must be shutdown.
2193      */
2194     DL_FOREACH(G_process_model, old)
2195     {
2196         /* check boundary! */
2197         new = t_process_model_hash[old->srvid];
2198         if (NULL==new)
2199         {
2200             if (!(PM_NOT_RUNNING(old->state)))
2201             {
2202                 NDRX_LOG(log_error,"Removed binary [%s] for "
2203                         "serverid=%d is in non shutdown state (%d)!",
2204                         old->binary_name, old->srvid, old->state);
2205 
2206                 /* Give some feedback to console */
2207                 if (NULL!=p_reload_error)
2208                     p_reload_error(call, old->srvid, old->binary_name,
2209                                 NULL, NDRXD_EBINARYRUN, "");
2210 
2211                 if (!old_error)
2212                 {
2213                     /* This is error case */
2214                     NDRXD_set_error_fmt(NDRXD_EBINARYRUN, "(%s) Removed "
2215                             "binary [%s] for srvid=%d is in non shutdown state (%d)!",
2216                             G_sys_config.config_file_short, 
2217                             old->binary_name, old->srvid, old->state);
2218                 }
2219                 old_error=EXTRUE;
2220             }
2221             else
2222             {
2223                 NDRX_LOG(log_debug,"Binary [%s] for "
2224                         "serverid=%d is removed and is shutdown!",
2225                         old->binary_name, old->srvid);
2226             }
2227         }
2228     }
2229 
2230     if (old_error || new_error)
2231     {
2232         ret=EXFAIL;
2233         goto out;
2234     }
2235 
2236     if (reload)
2237     {
2238         /* If all ok, then we are about to replace config, we just need to merge pids */
2239         DL_FOREACH(t_process_model, new)
2240         {
2241             /* check boundary! */
2242             old = G_process_model_hash[new->srvid];
2243             if (NULL!=old && 0==strcmp(new->binary_name, old->binary_name))
2244             {
2245                 NDRX_LOG(log_debug, "Saving pid %d in new config", old->pid);
2246                 new->pid = old->pid;
2247                 new->resid = old->resid;
2248                 new->svpid = old->svpid;
2249                 NDRX_STRCPY_SAFE(new->binary_name_real, old->binary_name_real);
2250                 NDRX_STRCPY_SAFE(new->rqaddress, old->rqaddress);
2251                 new->state = old->state;
2252                 /* Link existing service info to new PM! */
2253                 new->svcs = old->svcs;
2254                 new->reqstate = old->reqstate;
2255                 new->num_term_sigs = old->num_term_sigs;
2256                 new->last_sig = old->last_sig;
2257                 new->rspstwatch = old->rspstwatch;
2258                 new->pingstwatch = old->pingstwatch;
2259                 new->killreq = old->killreq;
2260                 /* Flags were missing after reload! */
2261                 new->flags = old->flags;
2262                 new->pingtimer = old->pingtimer;
2263                 new->pingseq = old->pingseq;
2264                 new->pingroundtrip = old->pingroundtrip;
2265                 new->procgrp_lp_no = old->procgrp_lp_no;
2266                 
2267                 /* So that we do not unlink the list later when old pm is freed */
2268                 old->svcs = NULL;
2269                 /* Add stuff to new pidhash! */
2270                 if (EXSUCCEED!=add_to_pid_hash(t_process_model_pid_hash, new))
2271                 {
2272                     NDRX_LOG(log_error, "Failed to register "
2273                                                 "process in new pidhash!");
2274                     ret=EXFAIL;
2275                     goto out;
2276                 }
2277             }
2278         }
2279 
2280         /* save current config */
2281         old_app_config=G_app_config;
2282         old_process_model=G_process_model;
2283         old_process_model_hash=G_process_model_hash;
2284         old_process_model_pid_hash=G_process_model_pid_hash;
2285         /* Update master config */
2286         G_app_config=t_app_config;
2287         G_process_model = t_process_model;
2288         G_process_model_hash = t_process_model_hash;
2289         G_process_model_pid_hash = t_process_model_pid_hash;
2290         
2291         ndrx_ddr_apply();
2292         ndrx_ndrxconf_procgroups_apply_singlegrp(G_app_config->procgroups);
2293 
2294         /* so that in case of error we do not destroy already master config. */
2295         t_app_config = NULL;
2296         t_process_model = NULL;
2297         t_process_model_hash = NULL;
2298         t_process_model_pid_hash = NULL;
2299 
2300         /* free up old config */
2301         config_free(&old_app_config, &old_process_model, &old_process_model_hash, 
2302                 &old_process_model_pid_hash);
2303 
2304         NDRX_LOG(log_debug, "Configuration successfully reloaded!");
2305     }
2306     else
2307     {
2308         /* free up test config */
2309         config_free(&t_app_config, &t_process_model, &t_process_model_hash, 
2310                 &t_process_model_pid_hash);
2311     }
2312 
2313 out:
2314 
2315     if (EXSUCCEED!=ret || do_free)
2316     {
2317         config_free(&t_app_config, &t_process_model, &t_process_model_hash, 
2318                 &t_process_model_pid_hash);
2319     }
2320 
2321     return ret;
2322 }
2323 
2324 /* vim: set ts=4 sw=4 et smartindent: */