Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Common shared memory routines for EnduroX. - ATMI level..
0003  *   Generally we do not use any global vars because this stuff should
0004  *   generic one.
0005  *   SHM Example see here:
0006  *   http://mij.oltrelinux.com/devel/unixprg/
0007  *   General rule regarding the SVCINFO shared memory area is, that we do not
0008  *   Delete any services out from that area. That ensures that we can alwasy search
0009  *   The data up!
0010  *
0011  * @file shm.c
0012  */
0013 /* -----------------------------------------------------------------------------
0014  * Enduro/X Middleware Platform for Distributed Transaction Processing
0015  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0016  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0017  * This software is released under one of the following licenses:
0018  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0019  * See LICENSE file for full text.
0020  * -----------------------------------------------------------------------------
0021  * AGPL license:
0022  *
0023  * This program is free software; you can redistribute it and/or modify it under
0024  * the terms of the GNU Affero General Public License, version 3 as published
0025  * by the Free Software Foundation;
0026  *
0027  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0028  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0029  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0030  * for more details.
0031  *
0032  * You should have received a copy of the GNU Affero General Public License along 
0033  * with this program; if not, write to the Free Software Foundation, Inc.,
0034  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0035  *
0036  * -----------------------------------------------------------------------------
0037  * A commercial use license is available from Mavimax, Ltd
0038  * contact@mavimax.com
0039  * -----------------------------------------------------------------------------
0040  */
0041 #include <ndrx_config.h>
0042 #include <string.h>
0043 #include <stdio.h>
0044 #include <stdlib.h>
0045 #include <memory.h>
0046 #include <errno.h>
0047 
0048 /* shm_* stuff, and mmap() */
0049 #include <sys/mman.h>
0050 #include <sys/types.h>
0051 /* exit() etc */
0052 #include <unistd.h>
0053 #include <fcntl.h>
0054 #include <sys/stat.h>
0055 
0056 #include <ndrx_config.h>
0057 #include <ndrstandard.h>
0058 #include <sys_unix.h>
0059 #include <atmi.h>
0060 #include <atmi_shm.h>
0061 #include <atmi_tls.h>
0062 #include <ndebug.h>
0063 #include <ndrx_ddr.h>
0064 #include <ndrxdcmn.h>
0065 #include <userlog.h>
0066 #include <exatomic.h>
0067 
0068 /*---------------------------Externs------------------------------------*/
0069 /*---------------------------Macros-------------------------------------*/
0070 /*---------------------------Enums--------------------------------------*/
0071 /*---------------------------Typedefs-----------------------------------*/
0072 /*---------------------------Globals------------------------------------*/
0073 expublic ndrx_shm_t G_srvinfo;
0074 expublic ndrx_shm_t G_svcinfo;
0075 expublic ndrx_shm_t G_brinfo;     /**< Info about bridges */
0076 
0077 expublic ndrx_shm_t ndrx_G_routcrit;    /**< Routing criterions */
0078 expublic ndrx_shm_t ndrx_G_routsvc;     /**< Routing services   */
0079 
0080 expublic int G_max_servers   = EXFAIL;         /* max servers         */
0081 expublic int G_max_svcs      = EXFAIL;         /* max svcs per server */
0082 
0083 int M_init = EXFALSE;                 /* no init yet done */
0084 /*---------------------------Statics------------------------------------*/
0085 /*---------------------------Prototypes---------------------------------*/
0086 
0087 /**
0088  * Initialise prefix part, that is needed for shm...
0089  * WARNING ! Not thread safe.
0090  * MT protected by:
0091  * - called by ndrxd (single thread)
0092  * - called by tp_internal_init(), locked protected
0093  * @param ndrx_prefix
0094  * @return 
0095  */
0096 expublic int ndrx_shm_init(char *q_prefix, int max_servers, int max_svcs,
0097         int rtcrtmax, int rtsvcmax)
0098 {
0099     memset(&G_srvinfo, 0, sizeof(G_srvinfo));
0100     memset(&G_svcinfo, 0, sizeof(G_svcinfo));
0101     memset(&G_brinfo, 0, sizeof(G_brinfo));
0102     
0103     memset(&ndrx_G_routcrit, 0, sizeof(G_brinfo));
0104     memset(&ndrx_G_routsvc, 0, sizeof(G_brinfo));
0105 
0106     G_svcinfo.fd = EXFAIL;
0107     G_svcinfo.key = G_atmi_env.ipckey + NDRX_SHM_SVCINFO_KEYOFSZ;
0108     
0109     G_srvinfo.fd = EXFAIL;
0110     G_srvinfo.key = G_atmi_env.ipckey + NDRX_SHM_SRVINFO_KEYOFSZ;
0111     
0112     G_brinfo.fd = EXFAIL;
0113     G_brinfo.key = G_atmi_env.ipckey + NDRX_SHM_BRINFO_KEYOFSZ;
0114     
0115     ndrx_G_routcrit.fd = EXFAIL;
0116     ndrx_G_routcrit.key = G_atmi_env.ipckey + NDRX_SHM_ROUTCRIT_KEYOFSZ;
0117     
0118     
0119     ndrx_G_routsvc.fd = EXFAIL;
0120     ndrx_G_routsvc.key = G_atmi_env.ipckey + NDRX_SHM_ROUTSVC_KEYOFSZ;
0121     
0122     
0123     snprintf(G_srvinfo.path, sizeof(G_srvinfo.path), NDRX_SHM_SRVINFO, q_prefix);
0124     snprintf(G_svcinfo.path, sizeof(G_svcinfo.path), NDRX_SHM_SVCINFO, q_prefix);
0125     snprintf(G_brinfo.path,  sizeof(G_brinfo.path), NDRX_SHM_BRINFO,  q_prefix);
0126     
0127     snprintf(ndrx_G_routcrit.path,  sizeof(G_brinfo.path), NDRX_SHM_ROUTCRIT,  q_prefix);
0128     snprintf(ndrx_G_routsvc.path,  sizeof(G_brinfo.path), NDRX_SHM_ROUTSVC,  q_prefix);
0129     
0130     G_max_servers = max_servers;
0131     G_max_svcs = max_svcs;
0132 
0133     /* Initialise sizes */
0134 
0135     G_srvinfo.size = sizeof(shm_srvinfo_t)*max_servers;
0136     NDRX_LOG(log_debug, "G_srvinfo.size = %d (%d * %d)",
0137                     G_srvinfo.size, sizeof(shm_srvinfo_t), max_servers);
0138     
0139     G_svcinfo.size = SHM_SVCINFO_SIZEOF *max_svcs;
0140     NDRX_LOG(log_debug, "G_svcinfo.size = %d (%d * %d)",
0141                     G_svcinfo.size, SHM_SVCINFO_SIZEOF, max_svcs);
0142    
0143     G_brinfo.size = sizeof(int)*CONF_NDRX_NODEID_COUNT;
0144     NDRX_LOG(log_debug, "G_brinfo.size = %d (%d * %d)",
0145                     G_svcinfo.size, sizeof(int), CONF_NDRX_NODEID_COUNT);
0146     
0147     ndrx_G_routcrit.size = rtcrtmax*2;
0148     NDRX_LOG(log_debug, "ndrx_G_routcrit.size = %d bytes (%d * 2)",
0149                     ndrx_G_routcrit.size, rtcrtmax);
0150     
0151     ndrx_G_routsvc.size = rtsvcmax * sizeof(ndrx_services_t) * 2;
0152     NDRX_LOG(log_debug, "ndrx_G_routsvc.size = %d (%d * %d * 2)",
0153                     ndrx_G_routsvc.size, rtsvcmax, sizeof(ndrx_services_t));
0154     
0155     M_init = EXTRUE;
0156     return EXSUCCEED;
0157 }
0158 
0159 
0160 /**
0161  * Set server exec status after forked exec failed
0162  * This will temporary open shared memory.
0163  * @param srvid server id
0164  * @param execerr error code
0165  */
0166 expublic void ndrxd_shm_srv_fork_status(int srvid, unsigned execerr)
0167 {
0168     if (EXSUCCEED==ndrx_shm_open(&G_srvinfo, EXTRUE))
0169     {
0170         shm_srvinfo_t* srv = ndrxd_shm_getsrv(srvid);
0171         
0172         if (NULL!=srv)
0173         {
0174             srv->execerr=execerr;
0175         }
0176         
0177         ndrx_shm_close(&G_srvinfo);
0178     }
0179 }
0180 
0181 /**
0182  * Closes all shared memory resources, generally ignores errors.
0183  * WARNING ! Not thread safe.
0184  * MT protected by: 
0185  *  - called by ndrxd after fork (main thread only)
0186  *  - called by ndrxd on exit
0187  *  - called by atmi server un-init
0188  * @return FAIL if something failed.
0189  */
0190 expublic int ndrxd_shm_close_all(void)
0191 {
0192     int ret=EXSUCCEED;
0193 
0194     /**
0195      * Library not initialized
0196      */
0197     if (!M_init)
0198     {
0199         NDRX_LOG(log_error, "ndrx shm library not initialized");
0200         ret=EXFAIL;
0201         goto out;
0202     }
0203     
0204     ret=ndrx_shm_close(&G_srvinfo);
0205 
0206     if (EXFAIL==ndrx_shm_close(&G_svcinfo))
0207         ret=EXFAIL;
0208 
0209     if (EXFAIL==ndrx_shm_close(&G_brinfo))
0210         ret=EXFAIL;
0211     
0212     if (EXFAIL==ndrx_shm_close(&ndrx_G_routcrit))
0213         ret=EXFAIL;
0214     
0215     if (EXFAIL==ndrx_shm_close(&ndrx_G_routsvc))
0216         ret=EXFAIL;
0217 out:
0218     return ret;
0219 }
0220 
0221 /**
0222  * Does delete all shared memory blocks.
0223  * WARNING ! Not thread safe.
0224  * MT protected by: called by ndrxd only (single thread)
0225  */
0226 expublic int ndrxd_shm_delete(void)
0227 {
0228     if (M_init)
0229     {
0230         ndrx_shm_remove(&G_srvinfo);
0231         ndrx_shm_remove(&G_svcinfo);
0232         ndrx_shm_remove(&G_brinfo);
0233         
0234         ndrx_shm_remove(&ndrx_G_routcrit);
0235         ndrx_shm_remove(&ndrx_G_routsvc);
0236     }
0237     else
0238     {
0239         NDRX_LOG(log_error, "SHM library not initialized!");
0240         return EXFAIL;
0241     }
0242 
0243     return EXSUCCEED;
0244 }
0245 
0246 /**
0247  * Attach to shared memory block.
0248  * WARNING ! Not thread safe.
0249  * MT protected by:
0250  * - Server does init first in single thread
0251  * - For clients tp_internal_init() does the thread safe call internally
0252  * @param lev indicates the attach level (should it be service array only)?
0253  * @param create shall we also create instead of attaching?
0254  * @return EXSUCCEED/
0255  */
0256 expublic int ndrx_shm_open_all(int lev, int create)
0257 {
0258    int ret=EXSUCCEED;
0259    
0260    struct {
0261        int lev;
0262        ndrx_shm_t *shm;
0263    } map [] = {
0264        
0265        {NDRX_SHM_LEV_SVC, &G_svcinfo}
0266        ,{NDRX_SHM_LEV_SVC, &ndrx_G_routcrit}
0267        ,{NDRX_SHM_LEV_SVC, &ndrx_G_routsvc}
0268        ,{NDRX_SHM_LEV_SRV, &G_srvinfo}
0269        ,{NDRX_SHM_LEV_BR, &G_brinfo}  
0270    };
0271    int i;
0272    
0273    /**
0274      * Library not initialised
0275      */
0276     if (!M_init)
0277     {
0278         NDRX_LOG(log_error, "ndrx shm library not initialised!");
0279         EXFAIL_OUT(ret);
0280     }
0281    
0282    for (i=0; i<N_DIM(map); i++)
0283    {
0284        if (map[i].lev & lev)
0285        {
0286            if (create)
0287            {
0288                
0289                 if (EXSUCCEED!=ndrx_shm_open(map[i].shm, EXTRUE))
0290                 {
0291                     EXFAIL_OUT(ret);
0292                 }
0293            }
0294            else
0295            {
0296                 if (EXSUCCEED!=ndrx_shm_attach(map[i].shm))
0297                 {
0298                     EXFAIL_OUT(ret);
0299                 }
0300            }
0301        }
0302    }
0303    
0304 out:
0305    return ret;
0306 }
0307 
0308 /**
0309  * Returns true if service is available.
0310  * @param svc
0311  * @param have_shm set to EXTRUE, if shared memory is attached.
0312  * @return TRUE/FALSE/FAIL (on fail proceed because no SHM)
0313  */
0314 expublic int ndrx_shm_get_svc(char *svc, char *send_q, int *is_bridge, int *have_shm)
0315 {
0316     int ret=EXSUCCEED;
0317     int pos=EXFAIL;
0318     shm_svcinfo_t *svcinfo = (shm_svcinfo_t *) G_svcinfo.mem;
0319     int use_cluster = EXFAIL;
0320     shm_svcinfo_t *psvcinfo = NULL;
0321     int chosen_node = EXFAIL;
0322     int csrvs;
0323     int srvs;
0324     ATMI_TLS_ENTRY;
0325     
0326     *is_bridge=EXFALSE;
0327     
0328     /* Initialy we stick to the local service */
0329     sprintf(send_q, NDRX_SVC_QFMT, G_atmi_tls->G_atmi_conf.q_prefix, svc);
0330     
0331     if (!ndrx_shm_is_attached(&G_svcinfo))
0332     {
0333 #ifdef EX_USE_POLL
0334         /* lookup first service in cache: 
0335          * probably not relevant any more as SHM is already open
0336          */
0337         ret = ndrx_get_cached_svc_q(send_q);
0338 #endif
0339         goto out; /* do not fail, try locally */
0340     }
0341     if (NULL!=have_shm)
0342     {
0343         *have_shm = EXTRUE;
0344     }
0345     
0346     /* Get the service entry */
0347     if (!_ndrx_shm_get_svc(svc, &pos, NDRX_SVCINSTALL_NOT, NULL))
0348     {
0349         NDRX_LOG(log_error, "Service %s not found in shm", svc);
0350         EXFAIL_OUT(ret);
0351     }
0352     
0353     psvcinfo = SHM_SVCINFO_INDEX(svcinfo, pos);
0354             
0355     if (psvcinfo->srvs<=0)
0356     {
0357         NDRX_LOG(log_error, "Service %s not available, count of servers: %d",
0358                                   svc, psvcinfo->srvs);
0359         EXFAIL_OUT(ret);
0360     }
0361     
0362     /* read it here, as bellow at modulus %, it can be updated
0363      * to 0 by ndrxd, and SIGFPE may be generated
0364      */
0365     csrvs = psvcinfo->csrvs;
0366     srvs = psvcinfo->srvs;
0367 
0368     /* Now use the random to chose the service to send to */
0369     if (srvs==csrvs && srvs>0)
0370     {
0371         use_cluster=EXTRUE;
0372     }
0373     else if (0==csrvs)
0374     {
0375         use_cluster=EXFALSE;
0376     }
0377     
0378     NDRX_LOG(log_debug, "use_cluster=%d srvs=%d csrvs=%d", 
0379             use_cluster, srvs, csrvs);
0380     
0381     if (EXFAIL==use_cluster)
0382     {
0383         if (0==G_atmi_env.ldbal)
0384         {
0385             /* Run locally */
0386             use_cluster=EXFALSE;
0387         }
0388         else if (100==G_atmi_env.ldbal)
0389         {
0390             /* Run in cluster */
0391             use_cluster=EXTRUE;
0392         }
0393         else
0394         {
0395             /* Use random */
0396             int n = ndrx_rand()%100+1;
0397             if (n<=G_atmi_env.ldbal)
0398             {
0399                 use_cluster = EXTRUE;
0400             }
0401             else
0402             {
0403                 use_cluster = EXFALSE;
0404             }
0405         }
0406     }
0407  
0408     NDRX_LOG(log_debug, "use_cluster=%d srvs=%d csrvs=%d", 
0409         use_cluster, srvs, csrvs);
0410 
0411 
0412     /* So we are using cluster, */
0413     if (EXTRUE==use_cluster)
0414     {
0415         int cluster_node;
0416         int i;
0417         int got_node = 0;
0418         int try = 0;
0419         
0420         /* TODO: Can be removed in case if we use read/write semaphore!!!
0421          * Just ensure that due to race condition csrv does not get corrupted.
0422          * if it will be 0, modulus will cause core dump. 
0423          */
0424         if (csrvs<0 || csrvs>CONF_NDRX_NODEID_COUNT)
0425         {
0426             NDRX_LOG(log_error, "Fixed csrvs to 0");
0427             csrvs=1;
0428         }
0429         
0430         cluster_node = ndrx_rand()%csrvs+1;
0431         NDRX_LOG(log_debug, "rnd: cluster_node=%d, cnode_max_id=%d", 
0432                 cluster_node, psvcinfo->cnodes_max_id);
0433         
0434         /* If cluster was modified (while we do not create read/write semaphores...!) */
0435         while (try<2)
0436         {
0437             /* First try, search the random server */
0438             for (i=0; i<psvcinfo->cnodes_max_id; i++)
0439             {
0440                 if (psvcinfo->cnodes[i].srvs)
0441                 {
0442                     got_node++;
0443                     if (1==try)
0444                     {
0445                         /*use first one we get at second try*/
0446                         chosen_node=i+1; /* cluster node numbers starts from 1 */
0447                         NDRX_LOG(log_debug, "try 1, use %d", chosen_node);       
0448                         break;
0449                     }
0450                 }
0451 
0452                 if (got_node==cluster_node)
0453                 {
0454                     chosen_node=i+1;
0455                     NDRX_LOG(log_debug, "one shot: use %d", chosen_node);
0456                     break;
0457                 }
0458             }
0459             
0460             /* Break out if node is chosen. */
0461             if (EXFAIL!=chosen_node)
0462             {
0463                 break; 
0464             }
0465             
0466             try++;
0467         }
0468         
0469         if (EXFAIL!=chosen_node)
0470         {
0471 /* 
0472  * only for epoll/fdpoll/kqueue(). For poll we do recursive call for service selection 
0473  * System V mode uses the same approach as for 
0474  */
0475 #if defined(EX_USE_EPOLL) || defined(EX_USE_FDPOLL) || defined(EX_USE_KQUEUE) || defined(EX_USE_SVAPOLL)
0476             sprintf(send_q, NDRX_SVC_QBRDIGE, 
0477                     G_atmi_tls->G_atmi_conf.q_prefix, chosen_node);
0478 #endif
0479             *is_bridge=EXTRUE;
0480         }
0481         else
0482         {
0483             NDRX_LOG(log_error, "Service [%s] not in cluster!",
0484                             svc);
0485             ret=EXFAIL;
0486         }
0487     }
0488 #if defined(EX_USE_POLL) || defined(EX_USE_SYSVQ)
0489     else
0490     {
0491         int resid;
0492         int resrr;
0493         int svc_ok = EXTRUE;
0494         int resnr;
0495         
0496         /* ###################### CRITICAL SECTION ############################### */
0497         /* lock for round-robin... */
0498 
0499         /* TODO: add RW lock functionality here and use CAS for round robin increment
0500          * Probably we could move to c11 and use atomic_fetch_add() % resnr
0501          */
0502         if (EXSUCCEED!=ndrx_lock_svc_nm(svc, __func__, NDRX_SEM_TYP_READ))
0503         {
0504             NDRX_LOG(log_error, "Failed to sem-lock service: %s", svc);
0505             EXFAIL_OUT(ret);
0506         }
0507         
0508         /* if have atomic header, use it... */
0509         
0510         NDRX_ATOMIC_ADD(&psvcinfo->resrr, 1);
0511         
0512         /* just chose the one  */
0513         
0514         /* well if we were getting here and resnr was reset to 0
0515          * due to dead servers, we might get SIGFPE
0516          * Thus if resnr is 0, then no servers are available.
0517          * Also verify that service name matches, not?
0518          * maybe something else already installed?
0519          */
0520         resnr = psvcinfo->resnr;
0521         
0522         if (resnr<=0)
0523         {
0524             NDRX_LOG(log_error, "svc [%s] resnr=%d", svc, resnr);
0525             svc_ok=EXFALSE;
0526         }
0527         else if (0!=strcmp(psvcinfo->service, svc))
0528         {
0529             /* check service */
0530             NDRX_LOG(log_error, "shm reset: [%s] vs [%s]", 
0531                     psvcinfo->service, svc);
0532             svc_ok=EXFALSE;
0533         }
0534         
0535         if (svc_ok)
0536         {
0537             resrr = psvcinfo->resrr % resnr;
0538             resid = psvcinfo->resids[resrr].resid;
0539         }
0540         
0541         if (EXSUCCEED!=ndrx_unlock_svc_nm(svc, __func__, NDRX_SEM_TYP_READ))
0542         {
0543             NDRX_LOG(log_error, "Failed to sem-unlock service: %s", svc);
0544             EXFAIL_OUT(ret);
0545         }
0546         
0547         /* ###################### CRITICAL SECTION, END ########################## */
0548         
0549         if (!svc_ok)
0550         {
0551             NDRX_LOG(log_error, "Service [%s] was removed during lookup", svc);
0552             EXFAIL_OUT(ret);
0553         }
0554         
0555         /* OK we got an resource id, lets translate it to actual queue */
0556         
0557         /* lets have an actual callback to backend for providing the queue
0558          * for service
0559          */
0560         
0561         sprintf(send_q, NDRX_SVC_QFMT_SRVID, G_atmi_tls->G_atmi_conf.q_prefix, 
0562                 svc, resid);
0563         
0564         if (EXSUCCEED!=ndrx_epoll_service_translate(send_q, 
0565                 G_atmi_tls->G_atmi_conf.q_prefix, svc, resid))
0566         {
0567             NDRX_LOG(log_error, "Failed to translate svc [%s] resid=%d to "
0568                     "queue resrr=%d", 
0569                     svc, resid, resrr);
0570             userlog("Failed to translate svc [%s] resid=%d resrr=%d to queue", 
0571                     svc, resid, resrr);
0572             EXFAIL_OUT(ret);
0573         }
0574         
0575         NDRX_LOG(log_debug, "Choosing local service by round-robin mode, "
0576                 "rr: %d, srvid: %d, q: [%s]", resrr, resid, send_q);
0577     }
0578     
0579     if (*is_bridge && 0!=strncmp(svc, NDRX_SVC_BRIDGE, NDRX_SVC_BRIDGE_STATLEN))
0580     {
0581         char tmpsvc[MAXTIDENT+1];
0582         
0583         snprintf(tmpsvc, sizeof(tmpsvc), NDRX_SVC_BRIDGE, chosen_node);
0584         
0585         NDRX_LOG(log_debug, "Recursive service lookup: [%s] ret %d", tmpsvc, ret);
0586         ret = ndrx_shm_get_svc(tmpsvc, send_q, is_bridge, NULL);
0587         *is_bridge = EXTRUE;
0588     }
0589     
0590 #endif
0591     
0592 out:
0593     NDRX_LOG(log_debug, "ndrx_shm_get_svc returns %d", ret);
0594 
0595     return ret;
0596 }
0597 
0598 
0599 /**
0600  * Returns list of servers providing the service (it does the malloc)
0601  * for poll() mode only.
0602  * @param svc
0603  * @param srvlist list of servers/resource id (mqd for system v)
0604  * @return 
0605  */
0606 expublic int ndrx_shm_get_srvs(char *svc, ndrx_shm_resid_t **srvlist, int *len)
0607 {
0608     int ret=EXSUCCEED;
0609     int pos=EXFAIL;
0610     shm_svcinfo_t *svcinfo = (shm_svcinfo_t *) G_svcinfo.mem;
0611     shm_svcinfo_t *psvcinfo = NULL;
0612     int local_count;
0613     
0614     *len = 0;
0615     
0616     if (!ndrx_shm_is_attached(&G_svcinfo))
0617     {
0618         ret=EXFAIL;
0619         goto out; /* do not fail, try locally */
0620     }
0621     
0622     if (EXSUCCEED!=ndrx_lock_svc_nm(svc, __func__, NDRX_SEM_TYP_READ))
0623     {
0624         NDRX_LOG(log_error, "Failed to sem-lock service: %s", svc);
0625         EXFAIL_OUT(ret);
0626     }
0627     
0628     /* Get the service entry */
0629     if (!_ndrx_shm_get_svc(svc, &pos, NDRX_SVCINSTALL_NOT, NULL))
0630     {
0631         NDRX_LOG(log_error, "Service %s not found in shm", svc);
0632         EXFAIL_OUT(ret);
0633     }
0634     
0635     psvcinfo = SHM_SVCINFO_INDEX(svcinfo, pos);
0636             
0637     
0638     local_count = psvcinfo->resnr;
0639     
0640     if (local_count<=0)
0641     {
0642         NDRX_LOG(log_error, "Service %s not available, count of servers: %d",
0643                                   svc, psvcinfo->srvs);
0644         EXFAIL_OUT(ret);
0645     }
0646     
0647     if (NULL==(*srvlist = NDRX_MALLOC(sizeof(ndrx_shm_resid_t) *local_count )))
0648     {
0649         NDRX_LOG(log_error, "malloc fail: %s", strerror(errno));
0650         EXFAIL_OUT(ret);
0651     }
0652     
0653     memcpy(*srvlist, &(psvcinfo->resids[0]), sizeof(ndrx_shm_resid_t) *local_count);
0654 
0655     *len = local_count;
0656     
0657 out:
0658 
0659     if (EXSUCCEED!=ndrx_unlock_svc_nm(svc, __func__, NDRX_SEM_TYP_READ))
0660     {
0661         NDRX_LOG(log_error, "Failed to sem-unlock service: %s", svc);
0662     }
0663 
0664 not_locked:
0665     
0666     NDRX_LOG(log_debug, "ndrx_shm_get_srvs: srvlist %p, ret %d, len %d",
0667         *srvlist, ret, *len);
0668 
0669     return ret;
0670 }
0671 
0672 /**
0673  * return number of service active in system
0674  * @return nr_services / EXFAIL
0675  */
0676 expublic int ndrx_shm_get_svc_count(void)
0677 {
0678     int ret = 0;
0679     shm_svcinfo_t *svcinfo = (shm_svcinfo_t *) G_svcinfo.mem;
0680     int i;
0681     
0682     if (!ndrx_shm_is_attached(&G_svcinfo))
0683     {
0684         /* no SHM infos */
0685         NDRX_LOG(log_debug, "SHM not attached -> no service count");
0686         ret=EXFAIL;
0687         goto out;
0688     }
0689         
0690     for (i=0; i< G_max_svcs; i++)
0691     {
0692         shm_svcinfo_t* ent = SHM_SVCINFO_INDEX(svcinfo, i);
0693         
0694         if (ent->flags & NDRXD_SVCINFO_INIT 
0695                 && ent->srvs > 0)
0696         {
0697             ret++;
0698         }
0699     }
0700 out:
0701     return ret;
0702 }
0703 
0704 /**
0705  * Search over the memory for service.
0706  * This is internal version and not meant be used outside of this file.
0707  * @param svc - service name
0708  * @param pos - store the last position
0709  * @param doing_install - we are doing service install, 
0710  *  thus we can return empty positions.
0711  *      In value: NDRX_SVCINSTALL_NOT
0712  *      In value: NDRX_SVCINSTALL_DO
0713  * @param p_install_cmd - Return command of installation process
0714  *  see values of _NDRX_SVCINSTALL_*
0715  *      Out value: NDRX_SVCINSTALL_OVERWRITE -> we got position for write (may be old or new)
0716  *      the caller is responsible for resetting to 0 this param value before call
0717  * @return TRUE/FALSE found existing value
0718  */
0719 expublic int _ndrx_shm_get_svc(char *svc, int *pos, int doing_install, int *p_install_cmd)
0720 {
0721     int ret=EXFALSE;
0722     int try = EXFAIL;
0723     int start = try;
0724     int overflow = EXFALSE;
0725     int iterations = 0;
0726     
0727     shm_svcinfo_t *svcinfo = (shm_svcinfo_t *) G_svcinfo.mem;
0728     
0729     /* Bug #349 20/10/2018
0730      * If doing write, we have to ensure that some stale service
0731      * does not block the our existing service at next position
0732      * thus firstly for writes we need to perform recursive read only lookup
0733      * and maybe we could re-use that existing index!
0734      */
0735     if (NDRX_SVCINSTALL_DO==doing_install)
0736     {
0737         int try_read = EXFAIL;
0738         
0739         if (_ndrx_shm_get_svc(svc, &try_read, NDRX_SVCINSTALL_NOT, NULL))
0740         {
0741             try = try_read;
0742         }
0743     }
0744     
0745     if (EXFAIL==try)
0746     {
0747         try = ndrx_hash_fn(svc) % G_max_svcs;
0748     }
0749     else
0750     {
0751         NDRX_LOG(log_debug, "Read only existing service [%s] found at [%d]", 
0752                 svc, try);
0753     }
0754     
0755     /* Bug #475 Fix */
0756     start = try;
0757     *pos=EXFAIL;
0758     
0759     NDRX_LOG(log_debug, "Key for [%s] is %d, shm is: %p", 
0760                                         svc, try, svcinfo);
0761     
0762     /*
0763      * So we loop over filled entries until we found empty one or
0764      * one which have been initialised by this service.
0765      *
0766      * So if there was overflow, then loop until the start item.
0767      */
0768     while ((SHM_SVCINFO_INDEX(svcinfo, try)->flags & NDRXD_SVCINFO_INIT)
0769             && (!overflow || (overflow && try < start)))
0770     {
0771         if (0==strcmp(SHM_SVCINFO_INDEX(svcinfo, try)->service, svc))
0772         {
0773             ret=EXTRUE;
0774             *pos=try;
0775             break;  /* <<< Break! */
0776         }
0777         
0778         /* Feature #139 mvitolin, 09/05/2017 
0779          * Allow to reuse services... As we know we do not remove them from SHM
0780          * so that if we have some service with the same hash number, but different
0781          * name than existing. Thus if we remove existing and put empty space there
0782          * then our service search algorithm will identify service as not present.
0783          * 
0784          * But to save the space and we install new service and the cell was used
0785          * but is serving 0 services, then we write off new service here.
0786          */
0787         if (NDRX_SVCINSTALL_DO==doing_install)
0788         {
0789             if (SHM_SVCINFO_INDEX(svcinfo, try)->srvs == 0)
0790             {
0791                 *p_install_cmd=NDRX_SVCINSTALL_OVERWRITE;
0792                 break; /* <<< break! */
0793             }
0794         }
0795 
0796         try++;
0797         
0798         /* we loop over... 
0799          * Feature #139 mvitolin, 09/05/2017
0800          * Fix potential overflow issues at the border... of SHM...
0801          */
0802         if (try>=G_max_svcs)
0803         {
0804             try = 0;
0805             overflow=EXTRUE;
0806             NDRX_LOG(log_debug, "Overflow reached for search of [%s]", svc);
0807         }
0808         iterations++;
0809         
0810         NDRX_LOG(log_debug, "Trying %d for [%s]", try, svc);
0811     }
0812     
0813     /* 
0814      * In case if doing install 
0815      * and memory cell found is not initialized
0816      * then we can use it.
0817      */
0818     if (NDRX_SVCINSTALL_DO==doing_install &&
0819             *p_install_cmd!=NDRX_SVCINSTALL_OVERWRITE &&
0820             !(SHM_SVCINFO_INDEX(svcinfo, try)->flags & NDRXD_SVCINFO_INIT))
0821     {
0822         *p_install_cmd=NDRX_SVCINSTALL_OVERWRITE;
0823     }
0824     
0825     *pos=try;
0826     NDRX_LOG(log_debug, "ndrx_shm_get_svc [%s] - result: %d, "
0827                             "iterations: %d, pos: %d, install: %d",
0828                              svc, ret, iterations, *pos, 
0829                              (doing_install?*p_install_cmd:NDRX_SVCINSTALL_NOT));
0830     return ret;
0831 }
0832 
0833 /**
0834  * Install service data into shared memory.
0835  * If service already found, then just update the flags.
0836  * If service is not found the add details to shm.
0837  * !!! Must be run from semaphore locked area!
0838  * @param svc
0839  * @param flags
0840  * @return SUCCEED/FAIL
0841  */
0842 expublic int ndrx_shm_install_svc_br(char *svc, int flags, 
0843                 int is_bridge, int nodeid, int count, char mode, int resid)
0844 {
0845     int ret=EXSUCCEED;
0846     int pos = EXFAIL;
0847     shm_svcinfo_t *svcinfo = (shm_svcinfo_t *) G_svcinfo.mem;
0848     int i;
0849     int is_new;
0850     int shm_install_cmd = NDRX_SVCINSTALL_NOT;
0851     shm_svcinfo_t* el;
0852     
0853 #if defined(EX_USE_POLL) || defined(EX_USE_SYSVQ)
0854     if (EXSUCCEED!=ndrx_lock_svc_nm(svc, __func__, NDRX_SEM_TYP_WRITE))
0855     {
0856         NDRX_LOG(log_error, "Failed to sem-lock service: %s", svc);
0857         ret=EXFAIL;
0858         goto lock_fail;
0859     }
0860 #endif
0861     
0862     if (_ndrx_shm_get_svc(svc, &pos, NDRX_SVCINSTALL_DO, &shm_install_cmd))
0863     {
0864         NDRX_LOG(log_debug, "Updating flags for [%s] from %d to %d",
0865                 svc, SHM_SVCINFO_INDEX(svcinfo, pos)->flags, flags);
0866         el = SHM_SVCINFO_INDEX(svcinfo, pos);
0867         /* service have been found at position, update flags */
0868         el->flags = flags | NDRXD_SVCINFO_INIT;
0869         
0870         /* If this is cluster & entry exits or count<=0, then do not increment. */
0871         if (!is_bridge || 
0872                 (0==el->cnodes[nodeid-1].srvs && count>0))
0873         {
0874 
0875 #if defined(EX_USE_POLL) || defined(EX_USE_SYSVQ)
0876                     
0877             if (!is_bridge && (el->resnr+1 > G_atmi_env.maxsvcsrvs))
0878             {
0879                 NDRX_LOG(log_error, "Shared mem for svc [%s] is full - "
0880                         "max space for servers per service: %d! Currently: "
0881                         "srvs: %d csrvs:%d resnr:%hd",
0882                         svc, G_atmi_env.maxsvcsrvs, 
0883                         el->srvs,
0884                         el->csrvs,
0885                         el->resnr
0886                         );
0887                 userlog("Shared mem for svc [%s] is full - "
0888                         "max space for servers per service: %d! Currently: "
0889                         "srvs: %d csrvs:%d resnr:%hd",
0890                         svc, G_atmi_env.maxsvcsrvs, 
0891                         el->srvs,
0892                         el->csrvs,
0893                         el->resnr);
0894                 EXFAIL_OUT(ret);
0895             }
0896             else if (!is_bridge)
0897             {
0898                 /* Add it to the array... */
0899                 /* so we use the next number */
0900                 int idx = EXFAIL;
0901                 
0902                 for (i=0; i < el->resnr; i++)
0903                 {
0904                     if (el->resids[i].resid==resid)
0905                     {
0906                         idx = i;
0907 #ifdef EX_USE_POLL
0908                         /* this may happen in case if housekeep did
0909                          * not remove the process and new was started...
0910                          */
0911                         NDRX_LOG(log_debug, "resource resid/srvid %d at %d "
0912                                 "already exists", resid, idx);
0913 #else
0914                         el->resids[i].cnt++;
0915                         NDRX_LOG(log_debug, "installed resid/srvid %d at %d "
0916                                 "increased to %hd", 
0917                                 resid, idx, el->resids[i].cnt);
0918 #endif
0919                     }
0920                 }
0921                 
0922                 if (EXFAIL==idx)
0923                 {
0924                     el->resids[el->resnr].resid = resid;
0925                     el->resids[el->resnr].cnt = 1;
0926                     NDRX_LOG(log_debug, "installed resid/srvid %d at %d", 
0927                             resid, el->resnr);
0928                     el->resnr++;
0929                 }
0930             }
0931 #endif
0932             el->srvs++;
0933             
0934             if (is_bridge)
0935             {
0936                 el->csrvs++;
0937             }
0938             
0939         }
0940     }
0941     /* It is OK, if there is no entry, we just start from scratch! */
0942     else if (NDRX_SVCINSTALL_OVERWRITE==shm_install_cmd)
0943     {
0944         el = SHM_SVCINFO_INDEX(svcinfo, pos);
0945         is_new=EXTRUE;
0946         if (is_bridge && 0==count)
0947         {
0948             NDRX_LOG(log_debug, "Svc [%s] not found in shm, "
0949                     "and will not install bridged 0", svc);
0950             goto out;
0951         }
0952         else
0953         {
0954             NDRX_STRCPY_SAFE(el->service, svc);
0955             /* Basically just override the init flag */
0956             el->flags = flags | NDRXD_SVCINFO_INIT;
0957             NDRX_LOG(log_debug, "Svc [%s] not found in shm, "
0958                         "installed with flags %d",
0959                         el->service, 
0960                         el->flags);
0961             
0962             el->srvs++;
0963             
0964             if (is_bridge)
0965             {
0966                 el->csrvs++;
0967             }
0968             else
0969             {
0970 #if defined(EX_USE_POLL) || defined(EX_USE_SYSVQ)
0971                 int idx = 0;
0972                 el->resids[idx].resid = resid;
0973                 el->resids[idx].cnt = 1;
0974                 NDRX_LOG(log_debug, "installed resid/srvid %d at idx %d", 
0975                         resid, idx);
0976                 el->resnr++;
0977 #endif
0978             }
0979         }
0980     }
0981     else
0982     {
0983         NDRX_LOG(log_debug, "Cannot install [%s]!! There is no "
0984                 "space in SHM! Try to increase %s",
0985                  svc, CONF_NDRX_SVCMAX);
0986         userlog("Cannot install [%s]!! There is no "
0987                 "space in SHM! Try to increase %s",
0988                  svc, CONF_NDRX_SVCMAX);
0989         EXFAIL_OUT(ret);
0990     }
0991     
0992     /* we are ok & extra bridge processing */
0993     if (is_bridge)
0994     {
0995         int was_installed;
0996         el = SHM_SVCINFO_INDEX(svcinfo, pos);
0997         was_installed = (el->cnodes[nodeid-1].srvs > 0);
0998         /* our index starts with 0 */
0999         if (BRIDGE_REFRESH_MODE_FULL==mode)
1000         {
1001             /* Install fresh stuff */
1002             el->cnodes[nodeid-1].srvs = count;
1003             /* Add real count */
1004             NDRX_LOG(log_debug, "SHM Service refresh: [%s] Bridge: [%d]"
1005                     " Count: [%d]",
1006                     svc, nodeid, count);
1007         }
1008         else
1009         {
1010             el->cnodes[nodeid-1].srvs+=count;
1011             
1012             /* If there was dropped update..! */
1013             if (el->cnodes[nodeid-1].srvs<0)
1014             {
1015                 el->cnodes[nodeid-1].srvs=0;
1016             }
1017             NDRX_LOG(log_debug, "SHM Service update: [%s] Bridge: "
1018                     "[%d] Diff: %d final count: [%d], cluster nodes: [%d]",
1019                     svc, nodeid, count, el->cnodes[nodeid-1].srvs, 
1020                     el->csrvs);
1021         }
1022         
1023         /* Note is being removed. */
1024         if (el->cnodes[nodeid-1].srvs<=0 && was_installed)
1025         {
1026             /* Reduce cluster nodes */
1027             el->csrvs--;
1028             el->srvs--;
1029         }
1030         
1031         /* Might want to install due to bridge updates */
1032         if (0==el->csrvs && 
1033                 0==el->srvs)
1034         {
1035             NDRX_LOG(log_debug, 
1036                     "Bridge %d caused to remove svc [%s] from shm",
1037                     nodeid, svc);
1038             /* Clean up memory block. 
1039             memset(&svcinfo[pos], 0, sizeof(svcinfo[pos]));
1040              * but we cannot clean it all. Because during shutdown
1041              * removal of some svc can cause svc with same hash code to target
1042              * first cell not second one.
1043              * 
1044              * So we will just reset key fields, but flags & svc stays the same.  
1045              */
1046             
1047             memset(&el->cnodes, 0, 
1048                     sizeof(el->cnodes));
1049             el->totclustered = 0;
1050             
1051             goto out;
1052         }
1053         
1054         /*Get the max node id so that client can scan the stuff!
1055          * If service is removed, we might want to re-scan the list
1056          * and rebuild cnodes_max_id for better hint to clients.
1057          */
1058         if (nodeid > el->cnodes_max_id)
1059         {
1060             el->cnodes_max_id = nodeid;
1061         }
1062         
1063         /* Rebuild totals of cluster... */
1064         el->totclustered = 0;
1065         for (i=0; i<el->cnodes_max_id; i++)
1066         {
1067             el->totclustered+=
1068                         el->cnodes[i].srvs;
1069         }
1070         NDRX_LOG(log_debug, "Total clustered services: %d", 
1071                 SHM_SVCINFO_INDEX(svcinfo, pos)->totclustered);
1072     }
1073 out:
1074 
1075 #if defined(EX_USE_POLL) || defined(EX_USE_SYSVQ)
1076     if (EXSUCCEED!=ndrx_unlock_svc_nm(svc, __func__, NDRX_SEM_TYP_WRITE))
1077     {
1078         NDRX_LOG(log_error, "Failed to sem-unlock service: %s", svc);
1079     }
1080 #endif
1081     
1082 lock_fail:
1083 
1084     return ret;
1085 }
1086 
1087 /**
1088  * Wrapper for bridged version
1089  * !!! Must be run from semaphore locked area!
1090  * @param svc service name to install to shared memory
1091  * @param flags install flags
1092  * @param resid fo POLL mode it is server id, for SYSV mode it is QID
1093  * @return EXSUCCEED/EXFAIL
1094  */
1095 expublic int ndrx_shm_install_svc(char *svc, int flags, int resid)
1096 {
1097     return ndrx_shm_install_svc_br(svc, flags, EXFALSE, 0, 0, 0, resid);
1098 }
1099 
1100 /**
1101  * Uninstall service from shared mem.
1102  * TODO: We should have similar function with counter for shutdown requested binaries
1103  * so that if shutdown was requested, service is no more called by other participans.
1104  * (if shutdown request was made to last available instance).
1105  * 
1106  * TOOD: Yep, counter is needed for shutdown requests. If requested count == srvs, then
1107  * We set up flag, that service is no more available, and this should be checked by tpcall!
1108  * 
1109  * TODO: We will want to compact the SHM when some service which have next one with same
1110  * hash is removed. so basically in reverse order we check, that service have some hash
1111  * but position is already taken by different service. The we chech the count of that different
1112  * position. If count == 0, then we can move service there, if not 0, then move to next pos.
1113  * But hmm.. this might require to have a readlock while doing write??? As service data is moved around :S
1114  * but if we have big svcmax, then probably this is not a problem (while we have fixed list of services).
1115  * 
1116  * @param svc
1117  * @param flags
1118  * @return SUCCEED/FAIL
1119  */
1120 expublic void ndrxd_shm_uninstall_svc(char *svc, int *last, int resid)
1121 {
1122     int pos = EXFAIL;
1123     int i;
1124     shm_svcinfo_t *svcinfo = (shm_svcinfo_t *) G_svcinfo.mem;
1125     int lpos;
1126     shm_svcinfo_t* el;
1127     
1128 #if defined(EX_USE_POLL) || defined(EX_USE_SYSVQ)
1129     if (EXSUCCEED!=ndrx_lock_svc_nm(svc, __func__, NDRX_SEM_TYP_WRITE))
1130     {
1131         NDRX_LOG(log_error, "Failed to sem-lock service: %s", svc);
1132         return;
1133     }
1134 #endif
1135     
1136     *last=EXFALSE;
1137     if (_ndrx_shm_get_svc(svc, &pos, NDRX_SVCINSTALL_NOT, NULL))
1138     {
1139         el = SHM_SVCINFO_INDEX(svcinfo, pos);
1140         if (el->srvs>1)
1141         {
1142             NDRX_LOG(log_debug, "Decreasing count of servers for "
1143                                 "[%s] from %d to %d (resnr=%d)",
1144                                 svc, el->srvs, 
1145                                 el->srvs-1, el->resnr);
1146 
1147 #if defined(EX_USE_POLL) || defined(EX_USE_SYSVQ)
1148 
1149             /*
1150             tot_local_srvs = el->srvs - 
1151                     el->csrvs;
1152               */          
1153             lpos = EXFAIL;
1154             for (i=0; i<el->resnr; i++)
1155             {
1156                 if (el->resids[i].resid==resid)
1157                 {
1158                     lpos = i;
1159                     break;
1160                 }
1161             }
1162             
1163             if (EXFAIL!=lpos)
1164             {
1165                 NDRX_LOG(log_debug, "Local count: %hd", el->resids[lpos].cnt);
1166                 
1167                 if (el->resids[lpos].cnt>1)
1168                 {
1169                     el->resids[lpos].cnt--;
1170                     NDRX_LOG(log_debug, "Resource %d decrement to %hd",
1171                             el->resids[lpos].resid, el->resids[lpos].cnt);
1172                 }
1173                 else if (lpos==el->resnr-1)
1174                 {
1175                     el->resnr--;
1176                     NDRX_LOG(log_debug, "Server was at last position, "
1177                             "just shrink the numbers...");
1178                 }
1179                 else
1180                 {
1181                     NDRX_LOG(log_debug, "Reducing the local server array...");
1182                     memmove(&(el->resids[lpos]),
1183                             &(el->resids[lpos+1]),
1184                             (el->resnr - lpos -1)*sizeof(el->resids[0]));
1185                     el->resnr--;
1186                 }
1187             }
1188             
1189 #endif
1190             el->srvs--;
1191             
1192             if (el->csrvs==el->srvs)
1193             {
1194                 /* only in cluster, thus locally this is last */
1195                 *last=EXTRUE;
1196             }
1197         }
1198         else
1199         {
1200             el = SHM_SVCINFO_INDEX(svcinfo, pos);
1201         
1202             NDRX_LOG(log_debug, "Removing service from shared mem "
1203                                 "[%s]",
1204                                 svc);
1205             /* Clean up memory block. 
1206             memset(&svcinfo[pos], 0, sizeof(svcinfo[pos]));
1207             */
1208             
1209             /* Once service was added to system, we do not remove it
1210              * automatically, unless we resolve problems with linear hash. 
1211              */
1212             memset(&el->cnodes, 0, 
1213                     sizeof(el->cnodes));
1214             el->totclustered = 0;
1215             el->csrvs = 0;
1216             el->srvs = 0;
1217 #if defined(EX_USE_POLL) || defined(EX_USE_SYSVQ)
1218             el->resnr = 0;
1219             el->resrr = 0;
1220 #endif
1221             
1222             *last=EXTRUE;
1223         }
1224     }
1225     else
1226     {
1227         NDRX_LOG(log_debug, "Service [%s] not present in shm", svc);
1228         *last=EXTRUE;
1229     }
1230     
1231 #if defined(EX_USE_POLL) || defined(EX_USE_SYSVQ)
1232     if (EXSUCCEED!=ndrx_unlock_svc_nm(svc, __func__, NDRX_SEM_TYP_WRITE))
1233     {
1234         NDRX_LOG(log_error, "Failed to sem-unlock service: %s", svc);
1235         return;
1236     }
1237 #endif
1238     
1239 }
1240 
1241 /**
1242  * Reset shared memory block
1243  * @param srvid
1244  */
1245 expublic void ndrxd_shm_resetsrv(int srvid)
1246 {
1247     shm_srvinfo_t *srv = ndrxd_shm_getsrv(srvid);
1248     if (NULL!=srv)
1249         memset(srv, 0, sizeof(shm_srvinfo_t));
1250 }
1251 
1252 /**
1253  * Get handler for server
1254  * Well event if we run with out ndrxd, we shall open the shared memory
1255  * blocks. This will make streamline testing in different modes, Posix and System V
1256  * @param srvid
1257  * @return
1258  */
1259 expublic shm_srvinfo_t* ndrxd_shm_getsrv(int srvid)
1260 {
1261     shm_srvinfo_t *ret=NULL;
1262     int pos=EXFAIL;
1263     shm_srvinfo_t *srvinfo = (shm_srvinfo_t *) G_srvinfo.mem;
1264 
1265     if (!ndrx_shm_is_attached(&G_srvinfo))
1266     {
1267         ret=NULL;
1268         goto out;
1269     }
1270 
1271     if (srvid >-1 && srvid < G_max_servers)
1272     {
1273         ret=&srvinfo[srvid];
1274     }
1275     else
1276     {
1277         NDRX_LOG(log_error, "Invalid srvid requested to "
1278                             "ndrxd_shm_getsrv => %d", srvid);
1279         ret=NULL;
1280     }
1281 
1282 out:
1283     return ret;
1284 }
1285 
1286 /**
1287  * Return list of connected nodes, installed in array byte positions.
1288  * @return SUCCEED/FAIL
1289  */
1290 expublic int ndrx_shm_birdge_getnodesconnected(char *outputbuf)
1291 {
1292     int ret=EXSUCCEED;
1293     int *brinfo = (int *) G_brinfo.mem;
1294     int i;
1295     int pos=0;
1296     
1297     if (!ndrx_shm_is_attached(&G_brinfo))
1298     {
1299         EXFAIL_OUT(ret);
1300     }
1301     
1302     for (i=1; i<=CONF_NDRX_NODEID_COUNT; i++)
1303     {
1304         if (brinfo[i-1] & NDRX_SHM_BR_CONNECTED)
1305         {
1306             outputbuf[pos] = i;
1307             pos++;
1308         }
1309     }
1310     
1311 out:
1312     return ret;
1313 }
1314 
1315 
1316 /**
1317  * Mark in the shm, that node is connected
1318  * @return 
1319  */
1320 expublic int ndrx_shm_birdge_set_flags(int nodeid, int flags, int op_end)
1321 {
1322     int ret=EXSUCCEED;
1323     int *brinfo = (int *) G_brinfo.mem;
1324 
1325     if (!ndrx_shm_is_attached(&G_brinfo))
1326     {
1327         ret=EXFAIL;
1328         goto out;
1329     }
1330 
1331     if (nodeid >= CONF_NDRX_NODEID_MIN && nodeid <= CONF_NDRX_NODEID_MAX)
1332     {
1333         if (op_end)
1334             brinfo[nodeid-1]&=flags;
1335         else
1336             brinfo[nodeid-1]|=flags;
1337     }
1338     else
1339     {
1340         NDRX_LOG(log_error, "Invalid nodeid requested to "
1341                             "shm_mark_br_connected => %d", nodeid);
1342         ret=EXFAIL;
1343     }
1344 
1345 out:
1346     return ret;
1347 }
1348 
1349 /**
1350  * Unmark bridge
1351  * @param nodeid
1352  * @return 
1353  */
1354 expublic int ndrx_shm_bridge_disco(int nodeid)
1355 {
1356     return ndrx_shm_birdge_set_flags(nodeid, ~NDRX_SHM_BR_CONNECTED, EXTRUE);
1357 }
1358 
1359 
1360 /**
1361  * Mark bridge connected.
1362  * @param nodeid
1363  * @return TRUE/FALSE
1364  */
1365 expublic int ndrx_shm_bridge_connected(int nodeid)
1366 {
1367     return ndrx_shm_birdge_set_flags(nodeid, NDRX_SHM_BR_CONNECTED, EXFALSE);
1368 }
1369 
1370 /**
1371  * Check is bridge copnnected. TODO: What heppens if ndrxd restarts and bridges do some stuff?
1372  * @param nodeid
1373  * @return 
1374  */
1375 expublic int ndrx_shm_bridge_is_connected(int nodeid)
1376 {
1377     int *brinfo = (int *) G_brinfo.mem;
1378     int ret=EXFALSE;
1379     
1380     if (!ndrx_shm_is_attached(&G_brinfo))
1381     {
1382         goto out;
1383     }
1384 
1385     if (nodeid >= CONF_NDRX_NODEID_MIN && nodeid <= CONF_NDRX_NODEID_MAX)
1386     {
1387         if (brinfo[nodeid-1]&NDRX_SHM_BR_CONNECTED)
1388         {
1389             ret=EXTRUE;
1390         }
1391     }
1392     else
1393     {
1394         NDRX_LOG(log_error, "Invalid nodeid requested to "
1395                             "shm_is_br_connected => %d", nodeid);
1396     }
1397 
1398 out:
1399     return ret;
1400 }
1401 
1402 
1403 
1404 /* vim: set ts=4 sw=4 et smartindent: */