Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Main Entry for EnduroX Daemon process
0003  *
0004  * @file ndrxd.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 #include <ndrx_config.h>
0035 #include <string.h>
0036 #include <stdio.h>
0037 #include <stdlib.h>
0038 #include <signal.h>
0039 #include <errno.h>
0040 #include <memory.h>
0041 #include <unistd.h>
0042 
0043 #include <ndrstandard.h>
0044 #include <ndrxd.h>
0045 #include <atmi_int.h>
0046 #include <atmi_shm.h>
0047 
0048 #include <ndebug.h>
0049 #include <cmd_processor.h>
0050 #include <signal.h>
0051 
0052 #include "userlog.h"
0053 #include "atmi_cache.h"
0054 
0055 /*---------------------------Externs------------------------------------*/
0056 /*---------------------------Macros-------------------------------------*/
0057 #define NDRX_Q_TRYLOCK_TIME 10  /* time in which we must get the q lock */
0058 #define NDRX_SVQ_SCANUNIT_NDRXD 200  /*< Scan unit used for System V Q  */
0059 /*---------------------------Enums--------------------------------------*/
0060 /*---------------------------Typedefs-----------------------------------*/
0061 /*---------------------------Globals------------------------------------*/
0062 expublic sigset_t ndrx_G_org_mask;
0063 /*---------------------------Statics------------------------------------*/
0064 sys_config_t        G_sys_config;           /**< Deamon configuration       */
0065 exprivate int       M_scanunit=250;         /**< Scan unit for SystemV poll */
0066 /*---------------------------Prototypes---------------------------------*/
0067 
0068 /**
0069  * Open PID file...
0070  * @return 
0071  */
0072 exprivate int open_pid_file(void)
0073 {
0074     int ret=EXSUCCEED;
0075     FILE *f = NULL;
0076     
0077     if (NULL==(f=NDRX_FOPEN(G_sys_config.pidfile, "w")))
0078     {
0079         NDRX_LOG(log_error, "Failed to open PID file %s for write: %s",
0080                     G_sys_config.pidfile, strerror(errno));
0081         userlog("Failed to open PID file %s for write: %s",
0082                     G_sys_config.pidfile, strerror(errno));
0083         ret=EXFAIL;
0084         goto out;
0085     }
0086 
0087     if (fprintf(f, "%d", getpid()) < 0)
0088     {
0089         NDRX_LOG(log_error, "Failed to write to PID file %s: %s",
0090                     G_sys_config.pidfile, strerror(errno));
0091         userlog("Failed to write to PID file %s: %s",
0092                     G_sys_config.pidfile, strerror(errno));
0093     }
0094 
0095     NDRX_FCLOSE(f);
0096     f=NULL;
0097 out:
0098     return ret;
0099 }
0100 
0101 /**
0102  * Remove pid file
0103  * @param [in] second_call general call at the main() flow (not after shutdown)
0104  * @return SUCCEED/FAIL
0105  */
0106 expublic int ndrxd_unlink_pid_file(int second_call)
0107 {
0108     /* second time no error checking... */
0109     if (second_call && !ndrx_file_exists(G_sys_config.pidfile))
0110     {
0111         return EXSUCCEED;
0112     }
0113     
0114     if (EXSUCCEED!=unlink(G_sys_config.pidfile))
0115     {
0116         NDRX_LOG(log_error, "Failed to unlink to PID file %s: %s",
0117                     G_sys_config.pidfile, strerror(errno));
0118         return EXFAIL;
0119     }
0120 
0121     return EXSUCCEED;
0122 }
0123 
0124 /**
0125  * Enter into main loop of the deamon
0126  * Do receive command.
0127  * @return
0128  */
0129 int main_loop()
0130 {
0131     int finished = EXFALSE;
0132     int ret=EXSUCCEED;
0133 
0134     if (EXSUCCEED!=open_pid_file())
0135     {
0136         ret=EXFAIL;
0137         goto out;
0138     }
0139     /* Open queue & receive command */
0140     while (!finished && EXSUCCEED==ret && 
0141             /* stop processing if shutdown requested! */
0142             !(G_sys_config.stat_flags & NDRXD_STATE_SHUTDOWN && is_srvs_down()))
0143     {
0144         /* Process command */
0145         if (EXFAIL==command_wait_and_run(&finished, NDRXD_CTX_ZERO))
0146         {
0147             ret=EXFAIL;
0148             goto out;
0149         }
0150         
0151     }
0152 
0153 out:
0154     return ret;
0155 }
0156 
0157 /**
0158  * NDRXD process got sigterm.
0159  * @return 
0160  */
0161 void clean_shutdown(int sig)
0162 {
0163     NDRX_LOG(log_warn, "Initiating ndrxd shutdown, signal: %d", sig);
0164     G_sys_config.stat_flags |= NDRXD_STATE_SHUTDOWN;
0165 }
0166 
0167 /**
0168  * print help for the command
0169  * @param name name of the program, argv[0]
0170  */
0171 exprivate void print_help(char *name)
0172 {
0173     fprintf(stderr, "Usage: %s [options] -k key \n", name);
0174     fprintf(stderr, "Options:\n");
0175     fprintf(stderr, "  -k <key>         Random key value\n");
0176     fprintf(stderr, "  -r               Start in recovery mode\n");
0177     fprintf(stderr, "  -h               Print this help\n");   
0178 }
0179 
0180 /**
0181  * Process command line options
0182  * @param argc
0183  * @param argv
0184  * @return 
0185  */
0186 expublic int init_cmdline_opts(int argc, char **argv)
0187 {
0188     int ret=EXSUCCEED;
0189     int c;
0190     extern char *optarg;
0191     int have_key = EXFALSE;
0192     int do_print_help = EXFALSE;
0193     
0194     /* Parse command line */
0195     while ((c = getopt(argc, argv, "h?rk:")) != -1)
0196     {
0197         switch(c)
0198         {
0199             case 'r':
0200                 fprintf(stderr, "Entering in restart mode\n");
0201                 G_sys_config.restarting  = EXTRUE;
0202                 break;
0203             case 'k':
0204                 /* No need for random key parsing yet */
0205                 have_key = EXTRUE;
0206                 break;
0207             case 'h': case '?':
0208                 do_print_help = EXTRUE;
0209                 break;
0210         }
0211     }
0212 
0213     if (!have_key || do_print_help)
0214     {
0215         print_help(argv[0]);
0216         return EXFAIL;
0217     }
0218     
0219 out:
0220     return ret;
0221 }
0222 
0223 /**
0224  * Standard initialization
0225  * @param argc
0226  * @param argv
0227  * @return
0228  */
0229 int main_init(int argc, char** argv)
0230 {
0231     int ret=EXSUCCEED;
0232     char *p;
0233 /*    struct sigaction oldact;*/
0234     pid_t ndrxd_pid;
0235 /*    sigaction(SIGINT, NULL, &oldact);*/
0236 
0237     /* common env loader will init the debug lib
0238      * which might call `ps' for process name
0239      * by popen(). which causes problems with
0240      * SIGCHLD handlers. Thus handle them after libinit
0241      */
0242     if (EXSUCCEED!=ndrx_load_common_env())
0243     {
0244         NDRX_LOG(log_error, "Failed to load common env");
0245         EXFAIL_OUT(ret);
0246     }
0247     
0248     /* Bug #375 check the ndrxd process existence by pid file */
0249     ndrxd_pid = ndrx_ndrxd_pid_get();
0250     
0251     if (EXFAIL!=ndrxd_pid && EXSUCCEED==kill(ndrxd_pid, 0))
0252     {
0253         fprintf(stderr, "ERROR ! Duplicate startup, ndrxd with PID %d "
0254                 "already exists\n", ndrxd_pid);
0255         NDRX_LOG(log_error, "ERROR ! Duplicate startup, ndrxd with PID %d "
0256                 "already exists", ndrxd_pid);
0257         userlog("ERROR ! Duplicate startup, ndrxd with PID %d "
0258                 "already exists", ndrxd_pid);
0259         exit(EXFAIL);
0260     }
0261     
0262     /* We will ignore all stuff requesting shutdown! 
0263     sigaction(SIGSEGV, NULL, &oldact);
0264     sigaction(SIGPIPE, &oldact, NULL);
0265     why?
0266     */
0267 
0268     signal(SIGHUP, SIG_IGN);
0269     signal(SIGTERM, SIG_IGN);
0270     signal(SIGINT, SIG_IGN);
0271 
0272     /********* Grab the configuration params  *********/
0273     G_sys_config.qprefix = getenv(CONF_NDRX_QPREFIX);
0274     if (NULL==G_sys_config.qprefix)
0275     {
0276         /* Write to ULOG? */
0277         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_QPREFIX);
0278         userlog("Missing config key %s - FAIL", CONF_NDRX_QPREFIX);
0279         ret=EXFAIL;
0280         goto out;
0281     }
0282 
0283     G_sys_config.config_file = getenv(CONF_NDRX_CONFIG);
0284     if (NULL==G_sys_config.config_file)
0285     {
0286         /* Write to ULOG? */
0287         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_CONFIG);
0288         userlog("Missing config key %s - FAIL", CONF_NDRX_CONFIG);
0289         ret=EXFAIL;
0290         goto out;
0291     }
0292     
0293     G_sys_config.config_file_short = strrchr(G_sys_config.config_file, '/');
0294     
0295     if (NULL==G_sys_config.config_file_short)
0296     {
0297         G_sys_config.config_file_short = G_sys_config.config_file;
0298     }
0299     else
0300     {
0301         G_sys_config.config_file_short++;
0302     }
0303     
0304     /* Override Q sizes */
0305     p = getenv(CONF_NDRX_DQMAX);
0306     if (NULL!=p)
0307     {
0308         /* Override MAX Q size */
0309         ndrx_get_G_atmi_env()->msg_max = atol(p);
0310         NDRX_LOG(log_debug, "NDRXD Max Q size to: %d (override)",
0311                             ndrx_get_G_atmi_env()->msg_max);
0312     }
0313     else
0314     {
0315         NDRX_LOG(log_debug, "NDRXD Max Q size to: %d (default)",
0316                             ndrx_get_G_atmi_env()->msg_max);
0317     }
0318 
0319     /* Command wait param */
0320     p = getenv(CONF_NDRX_CMDWAIT);
0321     if (NULL==p)
0322     {
0323         /* use default */
0324         G_sys_config.cmd_wait_time = COMMAND_WAIT_DEFAULT;
0325         NDRX_LOG(log_debug, "Command wait time defaulted to %ld sec",
0326                             G_sys_config.cmd_wait_time);
0327     }
0328     else
0329     {
0330         G_sys_config.cmd_wait_time = atol(p);
0331         NDRX_LOG(log_debug, "Command wait time set to %ld sec",
0332                             G_sys_config.cmd_wait_time);
0333     }
0334     
0335     if (EXSUCCEED!=cmd_processor_init())
0336     {
0337         /* Write to ULOG? */
0338         NDRX_LOG(log_error, "Failed to initialize command processor!");
0339         userlog("Failed to initailize command processor!");
0340         ret=EXFAIL;
0341         goto out;
0342     }
0343     
0344     /* Read PID file... */
0345     G_sys_config.pidfile = getenv(CONF_NDRX_DPID);
0346 
0347     if (NULL==G_sys_config.pidfile)
0348     {
0349         /* Write to ULOG? */
0350         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_DPID);
0351         userlog("Missing config key %s - FAIL", CONF_NDRX_DPID);
0352         ret=EXFAIL;
0353         goto out;
0354     }
0355     else
0356     {
0357         NDRX_LOG(log_error, "Using PID file [%s]", G_sys_config.pidfile);
0358     }
0359     
0360     G_sys_config.qpath = getenv(CONF_NDRX_QPATH);
0361     
0362     if (NULL==G_sys_config.qpath)
0363     {
0364         /* Write to ULOG? */
0365         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_QPATH);
0366         userlog("Missing config key %s - FAIL", CONF_NDRX_QPATH);
0367         ret=EXFAIL;
0368         goto out;
0369     }
0370     else
0371     {
0372         NDRX_LOG(log_error, "Using QPath [%s]", G_sys_config.qpath);
0373     }
0374 
0375     
0376     /* semaphores must go first!: */
0377     if (EXSUCCEED!=ndrxd_sem_init(G_sys_config.qprefix))
0378     {
0379         ret=EXFAIL;
0380         NDRX_LOG(log_error, "Failed to initialise share memory lib");
0381         goto out;
0382     }
0383     /* and then shm: initialise shared memory */
0384     if (EXSUCCEED!=ndrx_shm_init(G_sys_config.qprefix,
0385                             ndrx_get_G_atmi_env()->max_servers,
0386                             ndrx_get_G_atmi_env()->max_svcs,
0387                             ndrx_get_G_atmi_env()->rtcrtmax,
0388                             ndrx_get_G_atmi_env()->rtsvcmax))
0389     {
0390         ret=EXFAIL;
0391         NDRX_LOG(log_error, "Failed to initialise share memory lib");
0392         goto out;
0393     }
0394     
0395     if (EXSUCCEED!=ndrx_sem_open_all(EXTRUE))
0396     {
0397         ret=EXFAIL;
0398         NDRX_LOG(log_error, "Failed to create/attach to Semaphores");
0399         goto out;
0400     }
0401     else
0402     {
0403         NDRX_LOG(log_error, "Create/attached to semaphores OK");
0404     }
0405 
0406     if (EXSUCCEED!=ndrx_shm_open_all(NDRX_SHM_LEV_SVC | NDRX_SHM_LEV_SRV | NDRX_SHM_LEV_BR, EXTRUE))
0407     {
0408         ret=EXFAIL;
0409         NDRX_LOG(log_error, "Failed to create/attach to shared memory segments");
0410         goto out;
0411     }
0412     else
0413     {
0414         NDRX_LOG(log_error, "create/attached to shared memory OK");
0415     }
0416     
0417     if (EXSUCCEED!=ndrxd_sigchld_init())
0418     {
0419         NDRX_LOG(log_error, "Failed to init signal handler thread!");
0420         EXFAIL_OUT(ret);
0421     }
0422     
0423 out:
0424     return ret;
0425 }
0426 
0427 /**
0428  * Uninit app.
0429  * @return
0430  */
0431 int main_uninit(void)
0432 {
0433     /* Remove signal handling thread */
0434     ndrxd_sigchld_uninit();
0435     
0436     /* final sanity check... */
0437     ndrxd_sanity_finally();
0438     
0439     /* TODO: For System V we want to flush the
0440      * any timed queues. Thus 
0441      * we might want to call ndrxd_sanity_finish()
0442      * which for System V would call remove all
0443      * request addresses with out the servers
0444      * and with out TTL check.
0445      */
0446     /* Remove semaphores */
0447     ndrxd_sem_close_all();
0448     
0449     /* Remove semaphores */
0450     ndrxd_sem_delete();
0451     
0452     /* close shm */
0453     ndrxd_shm_close_all();
0454 
0455     /* Remove any shared memory segments (even if was not open!) */
0456     ndrxd_shm_delete();
0457 
0458     /* close & unlink message queue */
0459     cmd_close_queue();
0460     
0461     /* terminate polling sub-system */
0462     ndrx_epoll_down(EXFALSE);
0463 
0464     /* Remove pid file */
0465     ndrxd_unlink_pid_file(EXTRUE);
0466     
0467     return EXSUCCEED;
0468 }
0469 
0470 /* dummy, otherwise sigwait() does not return anything... */
0471 exprivate void sig_hand(int sig) {}
0472 
0473 /*
0474  * Program main entry
0475  */
0476 int main(int argc, char** argv)
0477 {
0478 
0479     int ret=EXSUCCEED;
0480     struct sigaction sa; /* Seem on AIX signal might slip.. */
0481     sigset_t blockMask;
0482 
0483     /* block sigchld first as some IPC mechanisms like systemv start
0484      * threads very early...
0485      */
0486     sigemptyset(&blockMask);
0487     sigaddset(&blockMask, SIGCHLD);
0488     
0489     /*
0490     if (pthread_sigmask(SIG_BLOCK, &blockMask, NULL) == -1)
0491         */
0492     if (sigprocmask(SIG_BLOCK, &blockMask, &ndrx_G_org_mask) == -1)
0493     {
0494         NDRX_LOG(log_always, "%s: sigprocmask failed: %s", __func__, 
0495                 strerror(errno));
0496         EXFAIL_OUT(ret);
0497     }
0498     
0499     /* if handler is not set, the sigwait() does not return any results.. */
0500     sa.sa_handler = sig_hand;
0501     sigemptyset (&sa.sa_mask);
0502     sa.sa_flags = SA_RESTART; /* restart system calls please... */
0503     sigaction (SIGCHLD, &sa, 0);
0504     
0505     /* have short scan-unit to have more precise sanity timings when
0506      * sleeping on command queue
0507      */
0508 #ifdef EX_USE_SYSVQ
0509     ndrx_svq_scanunit_set(NDRX_SVQ_SCANUNIT_NDRXD);
0510 #endif
0511     /* Do some init */
0512     memset(&G_sys_config, 0, sizeof(G_sys_config));
0513     
0514     if (EXSUCCEED!=init_cmdline_opts(argc, argv))
0515     {
0516         NDRX_LOG(log_error, "ndrxd - command line args failed");
0517         ret=EXFAIL;
0518         goto out;
0519     }
0520     else if (EXSUCCEED!=main_init(argc, argv))
0521     {
0522         NDRX_LOG(log_error, "ndrxd - INIT FAILED!");
0523         ret=EXFAIL;
0524         goto out;
0525     }
0526     /* If we are doing restart, the do actions needed for restart! */
0527     if (G_sys_config.restarting && EXSUCCEED!=do_restart_actions())
0528     {
0529         ret=EXFAIL;
0530         goto out;
0531     }
0532 
0533     ret=main_loop();
0534 
0535 out:
0536 
0537     main_uninit();
0538 
0539     NDRX_LOG(log_error, "exiting %d", ret);
0540 
0541     return ret;
0542 }
0543 /* vim: set ts=4 sw=4 et smartindent: */