Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Library initialization & configuration.
0003  *   This also serves as init for client part (may be called via atmi.c)
0004  *   We will support simple threading. Support for tpgetctx() and tpsetctx()
0005  *   will not be supported.
0006  *
0007  * @file init.c
0008  */
0009 /* -----------------------------------------------------------------------------
0010  * Enduro/X Middleware Platform for Distributed Transaction Processing
0011  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0012  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0013  * This software is released under one of the following licenses:
0014  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0015  * See LICENSE file for full text.
0016  * -----------------------------------------------------------------------------
0017  * AGPL license:
0018  *
0019  * This program is free software; you can redistribute it and/or modify it under
0020  * the terms of the GNU Affero General Public License, version 3 as published
0021  * by the Free Software Foundation;
0022  *
0023  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0024  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0025  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0026  * for more details.
0027  *
0028  * You should have received a copy of the GNU Affero General Public License along 
0029  * with this program; if not, write to the Free Software Foundation, Inc.,
0030  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0031  *
0032  * -----------------------------------------------------------------------------
0033  * A commercial use license is available from Mavimax, Ltd
0034  * contact@mavimax.com
0035  * -----------------------------------------------------------------------------
0036  */
0037 #include <string.h>
0038 #include <stdio.h>
0039 #include <stdlib.h>
0040 #include <semaphore.h>
0041 #include <memory.h>
0042 #include <unistd.h>
0043 #include <sys_mqueue.h>
0044 #include <errno.h>
0045 #include <fcntl.h>           /* For O_* constants */
0046 #include <sys/stat.h>        /* For mode constants */
0047 
0048 #include <ndrstandard.h>
0049 #include <ndebug.h>
0050 #include <atmi.h>
0051 #include <atmi_int.h>
0052 #include <sys_mqueue.h>
0053 #include <userlog.h>
0054 #include <tperror.h>
0055 #include <xa_cmn.h>
0056 #include <atmi_shm.h>
0057 #include <sys_unix.h>
0058 #include <atmi_tls.h>
0059 #include <cconfig.h>
0060 #include <typed_view.h>
0061 #include <atmi_cache.h>
0062 #include <nstd_int.h>
0063 #include <lcfint.h>
0064 /*---------------------------Externs------------------------------------*/
0065 /*---------------------------Macros-------------------------------------*/
0066 #define MAX_CONTEXTS                1000
0067 #define SGLOCKINC_DFLT              3600 /**< upper limit singleton group txn to reach commit, 1h */
0068 /*---------------------------Enums--------------------------------------*/
0069 /*---------------------------Typedefs-----------------------------------*/
0070 /*---------------------------Globals------------------------------------*/
0071 
0072 expublic int G_srv_id = EXFAIL; /* If we are server, then this will be server ID */
0073 expublic volatile int G_is_env_loaded = 0; /* Is environment initialised */
0074 /* NOTE: THIS BELLOW ONE IS NOT INITIALIZED FOR NDRXD! */
0075 expublic atmi_lib_env_t G_atmi_env={
0076     /* must follow first otherwise we override lcf commands at startup */
0077     .test_qdisk_write_fail=EXFALSE, 
0078     .test_tmsrv_write_fail=EXFALSE,
0079     .test_advertise_crash=NULL,
0080     .test_tmsrv_commit_crash=EXFALSE,
0081     .xa_sw = NULL,
0082     .time_out=EXFAIL}; /* ATMI library environmental configuration */
0083 expublic int _tmbuilt_with_thread_option = EXFALSE; /**< by default not MT */
0084 /*---------------------------Statics------------------------------------*/
0085 /* List of context slots... */
0086 exprivate long M_contexts[MAX_CONTEXTS];
0087 exprivate MUTEX_LOCKDECL(M_env_lock);
0088 exprivate int M_init_first = EXTRUE;
0089 /*---------------------------Prototypes---------------------------------*/
0090 
0091 /**
0092  * Return free context id...
0093  * We should have linked list of contexts...
0094  * @return 
0095  */
0096 expublic long ndrx_ctxid_op(int make_free, long ctxid)
0097 {
0098     MUTEX_LOCK;
0099     {
0100         static int first = EXTRUE;
0101         long ret=EXFAIL;
0102         long i;
0103         
0104         if (first)
0105         {
0106             /* Invalidate context slots */
0107             /*memset(M_contexts, EXFAIL, sizeof(M_contexts));*/
0108             for (i=0; i<MAX_CONTEXTS; i++)
0109             {
0110                 M_contexts[i]=EXFAIL;
0111             }
0112             first = EXFALSE;
0113         }
0114         
0115         /* TODO: Check for boundary!? */
0116         if (make_free)
0117         {
0118             if ((ctxid-1)<0 || (ctxid-1)>=MAX_CONTEXTS)
0119             {
0120                 NDRX_LOG(log_error, "Invalid ctxid=%ld, cannot make_free", ctxid);
0121                 userlog("Invalid ctxid=%ld, cannot make_free", ctxid);
0122             }
0123             else
0124             {
0125                 NDRX_LOG(log_debug, "Marking context %ld as free", ctxid);
0126                 M_contexts[ctxid-1] = EXFAIL;
0127             }
0128         }
0129         else
0130         {
0131             for (i=0; i<MAX_CONTEXTS; i++)
0132             {
0133                 if (EXFAIL==M_contexts[i])
0134                 {
0135                     NDRX_LOG(log_debug, "Got free context id=%ld (0 base)", i);
0136                     M_contexts[i] = i;
0137                     ret = i;
0138                     break;
0139                 }
0140             }
0141         }
0142         
0143         /* so at return we get 0 in case of failure... */
0144         ret+=1;
0145 out:     
0146         NDRX_LOG(log_debug, "Returning context id=%ld", ret);
0147         MUTEX_UNLOCK;
0148         return ret;
0149     }
0150 }
0151 
0152 
0153 /**
0154  * One time system init
0155  * @return 
0156  */
0157 exprivate int ndrx_init_once(void)
0158 {
0159     int ret = EXSUCCEED;
0160     /* reset callstates to default */
0161     /* memset(&G_call_state, 0, sizeof(G_call_state)); */
0162     
0163 out:
0164     return ret;
0165 }
0166 /**
0167  * This function loads common environment variables.
0168  * This should be called by any binary which uses atmi library!
0169  * If this fails, then binary should fail too!
0170  * @return 
0171  */
0172 expublic int ndrx_load_common_env(void)
0173 {
0174     int ret=EXSUCCEED;
0175     char *p;
0176     
0177     MUTEX_LOCK_V(M_env_lock);
0178     
0179     if (G_is_env_loaded)
0180     {
0181         NDRX_LOG(log_debug, "env already loaded...");
0182         goto out;
0183     }
0184     
0185     if (EXSUCCEED!=ndrx_init_once())
0186     {
0187         NDRX_LOG(log_error, "Init once failed");
0188         EXFAIL_OUT(ret);
0189     }
0190     
0191     /*
0192      * Here is the main entry point for common-confg
0193      * everything start with debug, thus read the system-wide config here.
0194      * NDRX_CCONF - optional, if set use CCONF, if not set fallback to old-style
0195      * NDRX_CCTAG - optional, if set use as sub-section
0196      */
0197      
0198     if (EXSUCCEED!=ndrx_cconfig_load())
0199     {
0200         fprintf(stderr, "GENERAL CONFIGURATION ERROR\n");
0201         exit(EXFAIL);
0202     }
0203     
0204     memset(&G_atmi_env.integpriv, 0, sizeof(G_atmi_env.integpriv));
0205 
0206     /* Read MAX servers */
0207     p = getenv(CONF_NDRX_SRVMAX);
0208     
0209     if (NULL==p)
0210     {
0211         ndrx_init_fail_banner(); /* NOTE ! this termiantes the binary */
0212     }
0213     
0214     if (NULL==p)
0215     {
0216         /* Write to ULOG? */
0217         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_SRVMAX);
0218         userlog("Missing config key %s - FAIL", CONF_NDRX_SRVMAX);
0219         ret=EXFAIL;
0220         goto out;
0221     }
0222     else
0223     {
0224         G_atmi_env.max_servers = atoi(p);
0225         NDRX_LOG(log_debug, "Max servers set to %d", G_atmi_env.max_servers);
0226     }
0227 
0228     /* Read MAX SVCs per server */
0229     p = getenv(CONF_NDRX_SVCMAX);
0230     if (NULL==p)
0231     {
0232         /* Write to ULOG? */
0233         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_SVCMAX);
0234         userlog("Missing config key %s - FAIL", CONF_NDRX_SVCMAX);
0235         ret=EXFAIL;
0236         goto out;
0237     }
0238     else
0239     {
0240         G_atmi_env.max_svcs = atoi(p);
0241         NDRX_LOG(log_debug, "Max services set to %d", G_atmi_env.max_servers);
0242     }
0243     
0244     /* Read MAX SVCs per server */
0245     p = getenv(CONF_NDRX_CLTMAX);
0246     if (NULL==p)
0247     {
0248         G_atmi_env.max_clts = 20000;
0249     }
0250     else
0251     {
0252         G_atmi_env.max_clts = atoi(p);
0253     }
0254     
0255     NDRX_LOG(log_debug, "Max services set to %d", G_atmi_env.max_clts);
0256 
0257 
0258     p = getenv(CONF_NDRX_RNDK);
0259     if (NULL==p)
0260     {
0261         /* Write to ULOG? */
0262         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_RNDK);
0263         userlog("Missing config key %s - FAIL", CONF_NDRX_RNDK);
0264         ret=EXFAIL;
0265         goto out;
0266     }
0267     else
0268     {
0269         NDRX_STRCPY_SAFE(G_atmi_env.rnd_key, p);
0270         NDRX_LOG(log_debug, "Random key set to: [%s]", G_atmi_env.rnd_key);
0271     }
0272 
0273     p = getenv(CONF_NDRX_MSGMAX);
0274     if (NULL==p)
0275     {
0276         /* Write to ULOG? */
0277         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_MSGMAX);
0278         userlog("Missing config key %s - FAIL", CONF_NDRX_MSGMAX);
0279         ret=EXFAIL;
0280         goto out;
0281     }
0282     else
0283     {
0284         G_atmi_env.msg_max = atoi(p);
0285         NDRX_LOG(log_debug, "Posix queue msg_max set to: [%d]",
0286                             G_atmi_env.msg_max);
0287     }
0288 
0289     p = getenv(CONF_NDRX_MSGSIZEMAX);
0290     if (NULL==p)
0291     {
0292         /* Write to ULOG? */
0293         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_MSGSIZEMAX);
0294         userlog("Missing config key %s - FAIL", CONF_NDRX_MSGSIZEMAX);
0295         ret=EXFAIL;
0296         goto out;
0297     }
0298     else
0299     {
0300         G_atmi_env.msgsize_max = atoi(p);
0301         NDRX_LOG(log_debug, "Posix queue msgsize_max set to: [%d]",
0302                             G_atmi_env.msgsize_max);
0303     }    
0304     p = getenv(CONF_NDRX_QPREFIX);
0305     if (NULL==p)
0306     {
0307         /* Write to ULOG? */
0308         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_QPREFIX);
0309         userlog("Missing config key %s - FAIL", CONF_NDRX_QPREFIX);
0310         EXFAIL_OUT(ret);
0311     }
0312     else
0313     {
0314         NDRX_STRCPY_SAFE(G_atmi_env.qprefix, p);
0315         
0316         snprintf(G_atmi_env.qprefix_match, sizeof(G_atmi_env.qprefix_match),
0317                 "%s%c", G_atmi_env.qprefix, NDRX_FMT_SEP);
0318         
0319         G_atmi_env.qprefix_match_len = strlen(G_atmi_env.qprefix_match);
0320         
0321         NDRX_LOG(log_debug, "Posix queue prefix set to: [%s], "
0322                             "match string: [%s] (len: %d)",
0323                             G_atmi_env.qprefix, G_atmi_env.qprefix_match,
0324                             G_atmi_env.qprefix_match_len);
0325     }
0326     
0327     p = getenv(CONF_NDRX_QPATH);
0328     if (NULL==p)
0329     {
0330         /* Write to ULOG? */
0331         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_QPATH);
0332         userlog("Missing config key %s - FAIL", CONF_NDRX_QPATH);
0333         ret=EXFAIL;
0334         goto out;
0335     }
0336     else
0337     {
0338         NDRX_STRCPY_SAFE(G_atmi_env.qpath, p);
0339         
0340         NDRX_LOG(log_debug, "Posix queue queue path set to: [%s]",
0341                             G_atmi_env.qpath);
0342     }
0343     
0344     p = getenv(CONF_NDRX_IPCKEY);
0345     if (NULL==p)
0346     {
0347         /* Write to ULOG? */
0348         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_IPCKEY);
0349         userlog("Missing config key %s - FAIL", CONF_NDRX_IPCKEY);
0350         ret=EXFAIL;
0351         goto out;
0352     }
0353     else
0354     {
0355         int tmpkey;
0356 
0357         /* bsd warning of long: */
0358         sscanf(p, "%x", &tmpkey);
0359         G_atmi_env.ipckey = tmpkey;
0360 
0361         NDRX_LOG(log_debug, "SystemV SEM IPC Key set to: [%x]",
0362                             G_atmi_env.ipckey);
0363     }
0364     
0365     /* Get timeout */
0366     if (NULL!=(p=getenv(CONF_NDRX_TOUT)))
0367     {
0368         G_atmi_env.time_out = atoi(p);
0369         NDRX_LOG(log_debug, "Using comms timeout: %d", G_atmi_env.time_out);
0370     }
0371     
0372     /* Get node id */
0373     if (NULL!=(p=getenv(CONF_NDRX_NODEID)))
0374     {
0375         G_atmi_env.our_nodeid = atoi(p);
0376         
0377         if (G_atmi_env.our_nodeid<CONF_NDRX_NODEID_MIN || 
0378                 G_atmi_env.our_nodeid>CONF_NDRX_NODEID_MAX)
0379         {
0380             NDRX_LOG(log_error, "Invalid [%s] setting! Min: %d, Max %d, got: %hd",
0381                     CONF_NDRX_NODEID, CONF_NDRX_NODEID_MIN, CONF_NDRX_NODEID_MAX,
0382                     G_atmi_env.our_nodeid);
0383             ret=EXFAIL;
0384             goto out;
0385         }
0386         NDRX_LOG(log_debug, "Cluster node id=%hd", G_atmi_env.our_nodeid);
0387     }
0388     
0389     /* Get load balance settings */
0390     
0391     if (NULL!=(p=getenv(CONF_NDRX_LDBAL)))
0392     {
0393         G_atmi_env.ldbal = atoi(p);
0394         
0395         if (G_atmi_env.ldbal<0 || 
0396                 G_atmi_env.ldbal>100)
0397         {
0398             NDRX_LOG(log_error, "%s - invalid: min 0, max 100, got: %d",
0399                     CONF_NDRX_LDBAL, G_atmi_env.ldbal);
0400             ret=EXFAIL;
0401             goto out;
0402         }
0403         NDRX_LOG(log_debug, "%s set to %d", 
0404                 CONF_NDRX_LDBAL, G_atmi_env.ldbal);
0405     }
0406     
0407     /* CONF_NDRX_CLUSTERISED */
0408     if (NULL!=(p=getenv(CONF_NDRX_CLUSTERISED)))
0409     {
0410         G_atmi_env.is_clustered = atoi(p);
0411         
0412         NDRX_LOG(log_debug, "[%s] says: We run in %s mode", 
0413                 CONF_NDRX_CLUSTERISED,
0414                 G_atmi_env.is_clustered?"cluster":"non cluster/single node");
0415     }
0416     
0417     p = getenv(CONF_NDRX_DPID);
0418     if (NULL==p)
0419     {
0420         NDRX_LOG(log_error, "Missing config key %s - FAIL", CONF_NDRX_DPID);
0421         userlog("Missing config key %s - FAIL", CONF_NDRX_DPID);
0422         ret=EXFAIL;
0423         goto out;
0424     }
0425     else
0426     {
0427         NDRX_STRCPY_SAFE(G_atmi_env.ndrxd_pidfile, p);
0428         
0429         NDRX_LOG(log_debug, "`ndrxd' pid file set to: [%s]",
0430                             G_atmi_env.ndrxd_pidfile);
0431     }
0432     
0433     /* wait for ndrxd to enter in normal context... */
0434     p = getenv(CONF_NDRX_NORMWAITMAX);
0435     
0436     if (NULL!=p)
0437     {
0438         G_atmi_env.max_normwait = atoi(p);
0439     }
0440     else
0441     {
0442         G_atmi_env.max_normwait = CONF_NDRX_NORMWAITMAX_DLFT;
0443     }
0444     
0445     NDRX_LOG(log_debug, "ndrxd normal wait set to: %d attempts", 
0446                 G_atmi_env.max_normwait);
0447 
0448     p = getenv(CONF_NDRX_PROCGRP_NO);
0449 
0450     if (NULL!=p)
0451     {
0452         G_atmi_env.procgrp_no = atoi(p);
0453 
0454         /* validate the value */
0455         if (G_atmi_env.procgrp_no<1 || G_atmi_env.procgrp_no>ndrx_G_libnstd_cfg.pgmax)
0456         {
0457             NDRX_LOG(log_error, "ERROR: config key %s value %d out of range 1..%d", 
0458                 CONF_NDRX_PROCGRP_NO, G_atmi_env.procgrp_no, ndrx_G_libnstd_cfg.pgmax);
0459             userlog("ERROR: config key %s value %d out of range 1..%d", 
0460                 CONF_NDRX_PROCGRP_NO, G_atmi_env.procgrp_no, ndrx_G_libnstd_cfg.pgmax);
0461             ret=EXFAIL;
0462             goto out;
0463         }
0464     }
0465     else
0466     {
0467         /* no group */
0468         G_atmi_env.procgrp_no = 0;
0469     }
0470 
0471     p = getenv(CONF_NDRX_SGLOCKINC);
0472 
0473     if (NULL!=p)
0474     {
0475         G_atmi_env.sglockinc = atol(p);
0476     }
0477     else
0478     {
0479         G_atmi_env.sglockinc = SGLOCKINC_DFLT;
0480     }
0481 
0482     NDRX_LOG(log_debug, "%s set to %ld",
0483                 CONF_NDRX_SGLOCKINC, G_atmi_env.sglockinc);
0484     
0485     /* <XA Protocol configuration - currently optional...> */
0486     
0487     /* resource id: */
0488     if (NULL!=(p=getenv(CONF_NDRX_XA_RES_ID)))
0489     {
0490         G_atmi_env.xa_rmid = atoi(p);
0491         NDRX_LOG(log_debug, "[%s]: XA Resource ID: %d", 
0492                 CONF_NDRX_XA_RES_ID,
0493                 G_atmi_env.xa_rmid);
0494     }
0495     
0496     /* Open string: */
0497     if (NULL!=(p=getenv(CONF_NDRX_XA_OPEN_STR)))
0498     {
0499         NDRX_STRCPY_SAFE(G_atmi_env.xa_open_str, p);
0500         NDRX_LOG(log_debug, "[%s]: XA Open String: [%s]", 
0501                 CONF_NDRX_XA_OPEN_STR,
0502                 G_atmi_env.xa_open_str);
0503     }
0504     
0505     /* Close string: */
0506     if (NULL!=(p=getenv(CONF_NDRX_XA_CLOSE_STR)))
0507     {
0508         NDRX_STRCPY_SAFE(G_atmi_env.xa_close_str, p);
0509         NDRX_LOG(log_debug, "[%s]: XA Close String: [%s]", 
0510                 CONF_NDRX_XA_CLOSE_STR,
0511                 G_atmi_env.xa_close_str);
0512     }
0513     else
0514     {
0515         NDRX_STRCPY_SAFE(G_atmi_env.xa_close_str, G_atmi_env.xa_open_str);
0516         NDRX_LOG(log_debug, "[%s]: XA Close String defaulted to: [%s]", 
0517                 CONF_NDRX_XA_CLOSE_STR,
0518                 G_atmi_env.xa_close_str);
0519     }
0520     
0521     /* Driver lib: */
0522     if (NULL!=(p=getenv(CONF_NDRX_XA_DRIVERLIB)))
0523     {
0524         NDRX_STRCPY_SAFE(G_atmi_env.xa_driverlib, p);
0525         NDRX_LOG(log_debug, "[%s]: Enduro/X XA Driver lib (.so): [%s]", 
0526                 CONF_NDRX_XA_DRIVERLIB,
0527                 G_atmi_env.xa_driverlib);
0528     }
0529     
0530     /* Resource manager lib: */
0531     if (NULL!=(p=getenv(CONF_NDRX_XA_RMLIB)))
0532     {
0533         NDRX_STRCPY_SAFE(G_atmi_env.xa_rmlib, p);
0534         NDRX_LOG(log_debug, "[%s]: Resource manager lib (.so): [%s]", 
0535                 CONF_NDRX_XA_RMLIB,
0536                 G_atmi_env.xa_rmlib);
0537     }
0538     
0539     if (NULL!=(p=getenv(CONF_NDRX_XA_FLAGS)))
0540     {
0541         NDRX_STRCPY_SAFE(G_atmi_env.xa_flags, p);
0542         NDRX_LOG(log_debug, "[%s]: XA Enduro/X specific flags: [%s]", 
0543                 CONF_NDRX_XA_FLAGS, G_atmi_env.xa_flags);
0544     }
0545     else
0546     {
0547         G_atmi_env.xa_flags[0] = EXEOS;
0548     }
0549     
0550     if (NULL!=(p=getenv(CONF_NDRX_XA_LAZY_INIT)))
0551     {
0552         G_atmi_env.xa_lazy_init = atoi(p);
0553     }
0554     
0555     /* no flags set */
0556     G_atmi_env.xa_flags_sys = 0;
0557     
0558     NDRX_LOG(log_debug, "[%s]: Lazy XA Init: %s", 
0559                 CONF_NDRX_XA_LAZY_INIT,
0560                 G_atmi_env.xa_lazy_init?"TRUE":"FALSE");
0561     
0562     /* If enabled, then validate the config */
0563     if (G_atmi_env.xa_rmid)
0564     {
0565         if (
0566             EXEOS==G_atmi_env.xa_open_str[0] ||
0567             EXEOS==G_atmi_env.xa_close_str[0] ||
0568             EXEOS==G_atmi_env.xa_driverlib[0] ||
0569             EXEOS==G_atmi_env.xa_rmlib[0])
0570         {
0571             NDRX_LOG(log_error, "Invalid XA configuration, missing "
0572                     "%s or %s or %s or %s keys...",
0573                     CONF_NDRX_XA_OPEN_STR,
0574                     CONF_NDRX_XA_CLOSE_STR,
0575                     CONF_NDRX_XA_DRIVERLIB,
0576                     CONF_NDRX_XA_RMLIB);
0577             EXFAIL_OUT(ret);
0578         }
0579         else
0580         {
0581             NDRX_LOG(log_debug, "XA config ok");
0582         }
0583         
0584         if (!G_atmi_env.xa_lazy_init)
0585         {
0586             NDRX_LOG(log_debug, "Loading XA driver...");
0587             if (EXSUCCEED!=atmi_xa_init())
0588             {
0589                 NDRX_LOG(log_error, "Failed to load XA driver!!!");
0590                 EXFAIL_OUT(ret);
0591             }
0592         }
0593     }
0594     
0595     /* </XA Protocol configuration> */
0596     
0597     /* <poll() mode configuration> */
0598     
0599     /* Number of semaphores used for shared memory protection: 
0600      * - for epoll() mode only 1 needed
0601      * - for poll() more is better as it will be balanced for every
0602      *   service/shared memory access (due to round robin sending to service)
0603      */
0604     if (NULL!=(p=getenv(CONF_NDRX_NRSEMS)))
0605     {
0606         G_atmi_env.nrsems = atoi(p);
0607         
0608         if (!G_atmi_env.nrsems)
0609         {
0610             G_atmi_env.nrsems = CONF_NDRX_NRSEMS_DFLT;
0611         }
0612         
0613     }
0614     else
0615     {
0616         G_atmi_env.nrsems = CONF_NDRX_NRSEMS_DFLT;
0617     }
0618     
0619     if (G_atmi_env.nrsems < 2)
0620     {
0621         G_atmi_env.nrsems = 2;
0622     }
0623     
0624     NDRX_LOG(log_debug, "[%s]: Number of services shared memory semaphores "
0625                 "set to: %d (used only for poll() mode) (default: %d)", 
0626                 CONF_NDRX_NRSEMS, G_atmi_env.nrsems, CONF_NDRX_NRSEMS_DFLT);
0627     
0628     /* Max servers per service: */
0629     if (NULL!=(p=getenv(CONF_NDRX_MAXSVCSRVS)))
0630     {
0631         G_atmi_env.maxsvcsrvs = atoi(p);
0632         
0633         if (!G_atmi_env.maxsvcsrvs)
0634         {
0635             G_atmi_env.maxsvcsrvs = CONF_NDRX_MAXSVCSRVS_DFLT;
0636         }
0637         
0638     }
0639     else
0640     {
0641         G_atmi_env.maxsvcsrvs = CONF_NDRX_MAXSVCSRVS_DFLT;
0642     }
0643     
0644     
0645     NDRX_LOG(log_debug, "[%s]: Max number of local servers per service "
0646                 "set to: %d (used only for poll() mode) (default: %d)", 
0647                 CONF_NDRX_MAXSVCSRVS, G_atmi_env.maxsvcsrvs, CONF_NDRX_MAXSVCSRVS_DFLT);
0648     
0649     /* </poll() mode configuration> */
0650     
0651     /* setup routing data */
0652     
0653     if (NULL!=(p=getenv(CONF_NDRX_RTCRTMAX)))
0654     {
0655         G_atmi_env.rtcrtmax = atoi(p);
0656         
0657         if (G_atmi_env.rtcrtmax<1)
0658         {
0659             G_atmi_env.rtcrtmax = CONF_NDRX_RTCRTMAX_DFLT;
0660         }
0661         
0662     }
0663     else
0664     {
0665         G_atmi_env.rtcrtmax = CONF_NDRX_RTCRTMAX_DFLT;
0666     }
0667     
0668     if (NULL!=(p=getenv(CONF_NDRX_RTSVCMAX)))
0669     {
0670         G_atmi_env.rtsvcmax = atoi(p);
0671         
0672         if (G_atmi_env.rtsvcmax<1)
0673         {
0674             G_atmi_env.rtsvcmax = CONF_NDRX_RTSVCMAX_DFLT;
0675         }
0676         
0677     }
0678     else
0679     {
0680         G_atmi_env.rtsvcmax = CONF_NDRX_RTSVCMAX_DFLT;
0681     }
0682     
0683     NDRX_LOG(log_debug, "routing criterion space: %d bytes, max services: %d", 
0684             G_atmi_env.rtcrtmax, G_atmi_env.rtsvcmax);
0685     
0686     if (NULL!=(p=getenv(CONF_NDRX_RTGRP)))
0687     {
0688         
0689         if (strlen(p)>NDRX_DDR_GRP_MAX)
0690         {
0691             NDRX_LOG(log_error, "ERROR ! Too long routing group [%s] max %d",
0692                     p, NDRX_DDR_GRP_MAX);
0693             userlog("ERROR ! Too long routing group [%s] max %d",
0694                     p, NDRX_DDR_GRP_MAX);
0695             ret=EXFAIL;
0696             goto out;
0697         }
0698         
0699         NDRX_STRCPY_SAFE(G_atmi_env.rtgrp, p);
0700         NDRX_LOG(log_debug, "Routing group set to [%s]", 
0701                 G_atmi_env.rtgrp);
0702     }
0703     else
0704     {
0705         G_atmi_env.rtgrp[0]=EXEOS;
0706         NDRX_LOG(log_debug, "Routing group not used");
0707     }
0708 
0709     /* Init the util lib.. */ 
0710     if (EXSUCCEED!=ndrx_atmiutil_init())
0711     {
0712        NDRX_LOG(log_error, "ndrx_atmiutil_init() failed");
0713        EXFAIL_OUT(ret);
0714     }
0715 
0716     /**
0717      * LIB ATMI must work with SHMCFG - thus ensures that it is open
0718      */
0719     if (!ndrx_lcf_supported_int())
0720     {
0721         NDRX_LOG(log_error, "ATMI processes must have LCF/SHMCFG configured - "
0722                 "check in previous logs why %s did not open", NDRX_SHM_LCF_SFX);
0723         EXFAIL_OUT(ret);
0724     }
0725     
0726     NDRX_LOG(log_debug, "env loaded ok");
0727     G_is_env_loaded = EXTRUE;
0728 out:
0729     MUTEX_UNLOCK_V(M_env_lock);
0730     return ret;
0731 }
0732 /**
0733  * Close open client session
0734  * @return
0735  */
0736 expublic int ndrx_tpterm (void)
0737 {
0738     int ret=EXSUCCEED;
0739     char fn[] = "_tpterm";
0740     
0741     ATMI_TLS_ENTRY;
0742     
0743     NDRX_LOG(log_debug, "%s called", fn);
0744 
0745     if (!G_atmi_tls->G_atmi_is_init)
0746     {
0747         NDRX_LOG(log_debug, "%s ATMI is not initialized - "
0748                 "nothing to do.", fn);
0749         goto out;
0750     }
0751     
0752     if (!G_atmi_tls->G_atmi_conf.is_client)
0753     {
0754         ret=EXFAIL;
0755         ndrx_TPset_error_msg(TPEPROTO, "tpterm called from server!");
0756         goto out;
0757     }
0758     
0759     /* Close client connections */
0760     if (EXSUCCEED!=close_open_client_connections())
0761     {
0762         ret=EXFAIL;
0763         ndrx_TPset_error_msg(TPESYSTEM, "Failed to close conversations!");
0764         goto out;
0765     }
0766     
0767     /* Close XA  */
0768     atmi_xa_uninit();
0769 
0770     /* Shutdown client queues */
0771     if (0!=G_atmi_tls->G_atmi_conf.reply_q)
0772     {
0773         if (EXFAIL==ndrx_mq_close(G_atmi_tls->G_atmi_conf.reply_q))
0774         {
0775             NDRX_LOG(log_warn, "Failed to close [%s]: %s",
0776                                 G_atmi_tls->G_atmi_conf.reply_q_str, strerror(errno));
0777             /* nothing to do with this error!
0778             _TPset_error_fmt(TPEOS, "Failed to close [%s]: %s",
0779                                 G_atmi_conf.reply_q_str, strerror(errno));
0780             ret=FAIL;
0781             goto out;
0782              */
0783         }
0784     }
0785 
0786     if (EXEOS!=G_atmi_tls->G_atmi_conf.reply_q_str[0])
0787     {
0788         NDRX_LOG(log_debug, "Unlinking [%s]", G_atmi_tls->G_atmi_conf.reply_q_str);
0789         if (EXFAIL==ndrx_mq_unlink(G_atmi_tls->G_atmi_conf.reply_q_str))
0790         {
0791             NDRX_LOG(log_warn, "Failed to unlink [%s]: %s",
0792                                 G_atmi_tls->G_atmi_conf.reply_q_str, strerror(errno));
0793     
0794             /* really no error!
0795             _TPset_error_fmt(TPEOS, "Failed to unlink [%s]: %s",
0796                                 G_atmi_conf.reply_q_str, strerror(errno));
0797             ret=FAIL;
0798             goto out;
0799             */
0800         }
0801     }
0802 
0803     /* Fee up context, should be last otherwise we might unlink other thread's
0804      * opened queue in this context!!! */
0805     ndrx_ctxid_op(EXTRUE, G_atmi_tls->G_atmi_conf.contextid);
0806     
0807     /* Un init the library */
0808     G_atmi_tls->G_atmi_is_init = EXFALSE;
0809     NDRX_LOG(log_debug, "%s: ATMI library un-initialized", fn);
0810     
0811 
0812 out:
0813     NDRX_LOG(log_debug, "%s returns %d", fn, ret);
0814     return ret;
0815 }
0816 
0817 /**
0818  * Do updates for reply Q init.
0819  * @param qd
0820  * @return 
0821  */
0822 expublic int tp_internal_init_upd_replyq(mqd_t reply_q, char *reply_q_str)
0823 {
0824     int ret=EXSUCCEED;
0825     char fn[]="tp_internal_init";
0826     ATMI_TLS_ENTRY;
0827     
0828     G_atmi_tls->G_atmi_conf.reply_q = reply_q;
0829     NDRX_STRCPY_SAFE(G_atmi_tls->G_atmi_conf.reply_q_str, reply_q_str);
0830     if (EXFAIL==ndrx_mq_getattr(reply_q, &G_atmi_tls->G_atmi_conf.reply_q_attr))
0831     {
0832         ndrx_TPset_error_fmt(TPEOS, "%s: Failed to read attributes for queue fd %d: %s",
0833                             fn, reply_q, strerror(errno));
0834         ret=EXFAIL;
0835         goto out;
0836     }
0837     
0838 out:
0839     return ret;
0840 }
0841  
0842 /**
0843  * Roll in ATMI library configuration.
0844  * NOTE! We need to open shared (create) shared mems just by clients too
0845  * the thing is that for System-V there is no way for clients to detect the
0846  * server queues with out the shared mem infos.
0847  * @param init_data
0848  * @return SUCCEED/FAIL
0849  */
0850 expublic int tp_internal_init(atmi_lib_conf_t *init_data)
0851 {
0852     int ret=EXSUCCEED;
0853     char fn[]="tp_internal_init";
0854     static int cl_shm = EXFALSE;
0855     static int sv_shm = EXFALSE;
0856     static int sem_fail = EXFALSE;
0857     ATMI_TLS_ENTRY;
0858     /* we connect to semaphore  */
0859     /* Check that if we are client (in server staging, then close current queues) */
0860     if (G_atmi_tls->G_atmi_is_init && G_atmi_tls->G_atmi_conf.is_client)
0861     {
0862         if (!init_data->is_client)
0863         {
0864             NDRX_LOG(log_debug, "Staged to server - "
0865                                 "shutting down client session");
0866             
0867             /*  attach to server shm segment. */
0868             ndrx_shm_open_all(NDRX_SHM_LEV_SRV, EXTRUE);
0869         }
0870         else
0871         {
0872             NDRX_LOG(log_debug, "Client re-initialisation - "
0873                                 "shutting down old session");
0874         }
0875 
0876         if (EXFAIL==ndrx_mq_close(G_atmi_tls->G_atmi_conf.reply_q))
0877         {
0878             NDRX_LOG(log_warn, "Failed to close [%s]: %s",
0879                                 G_atmi_tls->G_atmi_conf.reply_q_str, strerror(errno));
0880         }
0881 
0882         NDRX_LOG(log_debug, "Unlinking [%s]", G_atmi_tls->G_atmi_conf.reply_q_str);
0883         
0884         if (EXFAIL==ndrx_mq_unlink(G_atmi_tls->G_atmi_conf.reply_q_str))
0885         {
0886             NDRX_LOG(log_warn, "Failed to unlink [%s]: %s",
0887                                 G_atmi_tls->G_atmi_conf.reply_q_str, strerror(errno));
0888         }
0889     }
0890 
0891     /* Copy the configuration here */
0892     G_atmi_tls->G_atmi_conf = *init_data;
0893     G_atmi_tls->G_atmi_is_init = 1;
0894     
0895     /* reset last call (server side stuff) */
0896     memset(&G_atmi_tls->G_last_call, 0, sizeof(G_atmi_tls->G_last_call));
0897     
0898     /* reset conversation info */
0899     memset(&G_atmi_tls->G_tp_conversation_status, 0, 
0900             sizeof(G_atmi_tls->G_tp_conversation_status));
0901 
0902     /* reset our acceptance info */
0903     memset(&G_atmi_tls->G_accepted_connection, 0, 
0904             sizeof(G_atmi_tls->G_accepted_connection));
0905 
0906     /* read queue attributes -  only if Q was open...*/
0907     if (init_data->reply_q && EXFAIL==ndrx_mq_getattr(init_data->reply_q, 
0908             &G_atmi_tls->G_atmi_conf.reply_q_attr))
0909     {
0910         ndrx_TPset_error_fmt(TPEOS, "%s: Failed to read attributes for queue [%s] fd %d: %s",
0911                             fn, init_data->reply_q_str, init_data->reply_q, strerror(errno));
0912         ret=EXFAIL;
0913         goto out;
0914     }
0915 
0916     /* format the name of ndrxd queue: */
0917     snprintf(G_atmi_tls->G_atmi_conf.ndrxd_q_str, 
0918             sizeof(G_atmi_tls->G_atmi_conf.ndrxd_q_str), NDRX_NDRXD, 
0919             G_atmi_tls->G_atmi_conf.q_prefix);
0920     NDRX_LOG(log_debug, "NDRXD queue: [%s]", G_atmi_tls->G_atmi_conf.ndrxd_q_str);
0921     
0922     /* we attach to shared mem & semaphores only once. */
0923     MUTEX_LOCK;
0924     {
0925         if (M_init_first)
0926         {
0927             /* Init semaphores first. */
0928             ndrxd_sem_init(G_atmi_tls->G_atmi_conf.q_prefix);
0929             
0930             /* Try to attach to semaphore array */
0931             if (EXSUCCEED!=ndrx_sem_open_all(EXTRUE))
0932             {
0933                 NDRX_LOG(log_error, "Failed to attach to semaphores!");
0934                 sem_fail = EXTRUE;
0935                 /*ret=FAIL;
0936                 goto out;*/
0937             }
0938             
0939             /* Attach to client shared memory? */
0940             if (EXSUCCEED==ndrx_shm_init(G_atmi_tls->G_atmi_conf.q_prefix, 
0941                         G_atmi_env.max_servers, G_atmi_env.max_svcs, G_atmi_env.rtcrtmax,
0942                         G_atmi_env.rtsvcmax))
0943             {
0944                 if (init_data->is_client)
0945                 {
0946                     if (EXSUCCEED==ndrx_shm_open_all(NDRX_SHM_LEV_SVC | NDRX_SHM_LEV_BR, EXTRUE) && 
0947                             sem_fail)
0948                     {
0949                         NDRX_LOG(log_error, "SHM ok, but sem fail -"
0950                                 " cannot operate in this mode!");
0951                         MUTEX_UNLOCK;
0952                         EXFAIL_OUT(ret);
0953                     }
0954                     
0955                     cl_shm=EXTRUE;
0956                 }
0957                 else
0958                 {
0959                     /* In case of server we attach to both shared memory blocks */
0960                     /* TODO: if there was tpinit() before server booted, the  NDRX_SHM_LEV_SRV is
0961                      * not mounted.
0962                      */
0963                     if (EXSUCCEED==ndrx_shm_open_all(NDRX_SHM_LEV_SVC | 
0964                                         NDRX_SHM_LEV_SRV | NDRX_SHM_LEV_BR, EXTRUE) &&
0965                             sem_fail)
0966                     
0967                     {
0968                         NDRX_LOG(log_error, "SHM ok, but sem fail -"
0969                                 " cannot operate in this mode!");
0970                         MUTEX_UNLOCK;
0971                         EXFAIL_OUT(ret);
0972                     }
0973                     
0974                     sv_shm=EXTRUE;
0975                 }
0976             }
0977 
0978 
0979             /* Read the init cache */
0980             if (EXSUCCEED!=ndrx_cache_init(NDRX_TPCACH_INIT_NORMAL))
0981             {
0982                 NDRX_LOG(log_error, "Cache init failed");
0983                 MUTEX_UNLOCK;
0984                 EXFAIL_OUT(ret);
0985             }
0986             
0987             M_init_first = EXFALSE;
0988         }
0989         else if (!sv_shm && !init_data->is_client)
0990         {
0991             NDRX_LOG(log_debug, "Client shm init was first, init server SHM");
0992             
0993             if (EXSUCCEED==ndrx_shm_open_all(NDRX_SHM_LEV_SRV, EXTRUE) &&
0994                             sem_fail)
0995                     
0996             {
0997                 NDRX_LOG(log_error, "SHM ok, but sem fail -"
0998                         " cannot operate in this mode!");
0999                 MUTEX_UNLOCK;
1000                 EXFAIL_OUT(ret);
1001             }
1002             
1003             sv_shm=EXTRUE;
1004         }
1005         MUTEX_UNLOCK;
1006     }
1007     
1008 out:
1009     return ret;
1010 }
1011 
1012 /**
1013  * Initialize client. Not sure should this be called by server process?
1014  * Maybe... or we will create separate part for server to initialize with monitor
1015  * @return SUCCEED/FAIL
1016  */
1017 expublic int tpinit (TPINIT * init_data)
1018 {
1019     int ret=EXSUCCEED;
1020     atmi_lib_conf_t conf;
1021     char reply_q[NDRX_MAX_Q_SIZE+1];
1022     char my_id[NDRX_MAX_ID_SIZE+1];
1023     char *p;
1024     char read_clt_name[MAXTIDENT+1]={EXEOS};
1025     static pid_t pid;
1026     ATMI_TLS_ENTRY;
1027     
1028     if (G_atmi_tls->G_atmi_is_init)
1029     {
1030         NDRX_LOG(log_info, "ATMI already initialized...");
1031         goto out;
1032     }
1033 
1034     memset(&conf, 0, sizeof(conf));
1035     /* assume that client only can call this */
1036     conf.is_client = 1;
1037     
1038     /* Load common environment for client - this should be synced...*/
1039     if (EXSUCCEED!=ndrx_load_common_env())
1040     {
1041         NDRX_LOG(log_error, "Failed to load common env");
1042         ndrx_TPset_error_msg(TPEINVAL, "Failed to load common env");
1043         ret=EXFAIL;
1044         goto out;
1045     }
1046     
1047     /* Load the queue prefix */
1048     if (NULL==(p=getenv(CONF_NDRX_QPREFIX)))
1049     {
1050         ndrx_TPset_error_msg(TPEINVAL, "Env NDRX_QPREFIX not set");
1051         ret=EXFAIL;
1052         goto out;
1053     }
1054     else
1055     {
1056         NDRX_STRCPY_SAFE(conf.q_prefix, p);
1057         NDRX_LOG(log_debug, "Got prefix [%s]", conf.q_prefix);
1058         
1059     }
1060 
1061     /* Get the PID of the process */
1062     pid = getpid();
1063     
1064     NDRX_STRCPY_SAFE(read_clt_name, EX_PROGNAME);
1065     NDRX_LOG(log_debug, "Got PROGNAME [%s]", read_clt_name);
1066     
1067     /* Get new context id. Threading support only for clients... */
1068     conf.contextid = ndrx_ctxid_op(EXFALSE, EXFAIL);
1069     if (!conf.contextid)
1070     {
1071         ndrx_TPset_error_msg(TPESYSTEM, "Cannot get ATMI context -> max exceeded?");
1072         ret=EXFAIL;
1073         goto out;
1074     }
1075     NDRX_DBG_SETTHREAD(conf.contextid);
1076     
1077     /* Format my ID */
1078     if (EXFAIL==G_srv_id)
1079     {
1080         snprintf(my_id, sizeof(my_id), NDRX_MY_ID_CLT, 
1081                 /* we always assume that name is process name...!
1082                  * This is how enduro/x is built.
1083                  */
1084                 /*init_data!=NULL?init_data->cltname:*/read_clt_name, 
1085                 pid, 
1086                 conf.contextid, 
1087                 G_atmi_env.our_nodeid);
1088         
1089         NDRX_STRCPY_SAFE(conf.my_id, my_id);
1090     }
1091     else
1092     {
1093         snprintf(my_id, sizeof(my_id), NDRX_MY_ID_SRV, 
1094                 /*init_data!=NULL?init_data->cltname:*/read_clt_name, 
1095                 G_srv_id, 
1096                 pid,
1097                 conf.contextid, /* Bug #119 server multicontext fixes... */
1098                 G_atmi_env.our_nodeid);
1099         NDRX_STRCPY_SAFE(conf.my_id, my_id);
1100     }
1101 
1102     NDRX_LOG(log_debug, "my_id=[%s]", conf.my_id);
1103 
1104     snprintf(reply_q, sizeof(reply_q), NDRX_CLT_QREPLY, conf.q_prefix,
1105                 read_clt_name, pid, conf.contextid); /* no client name if no provided */
1106 
1107     /* at first try to un-link existing queue */
1108     ndrx_mq_unlink(reply_q);
1109 
1110     NDRX_STRCPY_SAFE(conf.reply_q_str, reply_q);
1111     /* now try to open the queue, by default we will have blocked access */
1112     NDRX_LOG(log_debug, "About to open client queue [%s]", reply_q);
1113     conf.reply_q = ndrx_mq_open_at(reply_q, O_RDONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL);
1114     NDRX_LOG(log_debug, "After client Q open: %d", conf.reply_q);
1115     if ((mqd_t)EXFAIL==conf.reply_q)
1116     {
1117         ndrx_TPset_error_fmt(TPEOS, "Failed to open queue [%s] errno: %s", 
1118                     conf.reply_q_str, strerror(errno));
1119         EXFAIL_OUT(ret);
1120     }
1121 
1122     NDRX_LOG(log_debug, "Client queue [%s] opened mqd_t=%d.",
1123         conf.reply_q_str, conf.reply_q);
1124 
1125     if (NULL!=init_data)
1126     {
1127         memcpy(&G_atmi_tls->client_init_data, init_data, sizeof(*init_data));
1128     }
1129     /* do the library initialisation */
1130     if (EXSUCCEED!=tp_internal_init(&conf))
1131     {
1132         ndrx_TPset_error_msg(TPESYSTEM, "Failed to configure internals (caches, etc..), see logs");
1133         EXFAIL_OUT(ret);
1134     }
1135     
1136 out:
1137     return ret;
1138 }
1139 
1140 /**
1141  * Shutdown the thread
1142  * @param arg
1143  * @param p_finish_off
1144  */
1145 expublic void tp_thread_shutdown(void *ptr, int *p_finish_off)
1146 {
1147     tpterm();
1148     
1149     *p_finish_off = EXTRUE;
1150 }
1151 
1152 /**
1153  * Return ENV data pointer
1154  * @return pointer to private env storage
1155  */
1156 expublic ndrx_env_priv_t* ndrx_env_priv_get(void)
1157 {
1158     return &G_atmi_env.integpriv;
1159 }
1160 
1161 /**
1162  * This is not thread safe
1163  * thus only needs to be used from single threaded
1164  * apps such as xadmin.
1165  */
1166 expublic void ndrx_libatmi_deinit(void)
1167 {
1168     ndrxd_shm_close_all();
1169     M_init_first=EXTRUE;
1170 }
1171 
1172 
1173 /* vim: set ts=4 sw=4 et smartindent: */