Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Real time handling routines
0003  *
0004  * @file ddr_atmi.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 <string.h>
0035 #include <stdio.h>
0036 #include <stdlib.h>
0037 #include <memory.h>
0038 #include <errno.h>
0039 #include <math.h>
0040 #include <ndrx_ddr.h>
0041 #include <fcntl.h>
0042 #include <assert.h>
0043 
0044 #include "atmi_int.h"
0045 #include <lcfint.h>
0046 #include <atmi_shm.h>
0047 #include <typed_buf.h>
0048 /*---------------------------Externs------------------------------------*/
0049 /*---------------------------Macros-------------------------------------*/
0050 /*---------------------------Enums--------------------------------------*/
0051 /*---------------------------Typedefs-----------------------------------*/
0052 /*---------------------------Globals------------------------------------*/
0053 /*---------------------------Statics------------------------------------*/
0054 /*---------------------------Prototypes---------------------------------*/
0055 
0056 /** standard hashing stuff */
0057 exprivate int ndrx_ddr_key_hash(ndrx_lh_config_t *conf, void *key_get, size_t key_len)
0058 {
0059     return ndrx_hash_fn(key_get) % conf->elmmax;
0060 }
0061 
0062 /** standard hashing stuff */
0063 exprivate void ndrx_ddr_key_debug(ndrx_lh_config_t *conf, void *key_get, size_t key_len, 
0064     char *dbg_out, size_t dbg_len)
0065 {
0066     NDRX_STRCPY_SAFE_DST(dbg_out, key_get, dbg_len);
0067 }
0068 
0069 /** standard hashing stuff */
0070 exprivate void ndrx_ddr_debug(ndrx_lh_config_t *conf, int idx, char *dbg_out, size_t dbg_len)
0071 {
0072     snprintf(dbg_out, dbg_len, "%s", NDRX_DDRV_SVC_INDEX((*conf->memptr), idx)->svcnm);
0073     
0074 }
0075 /** standard hashing stuff */
0076 exprivate int ndrx_ddr_compare(ndrx_lh_config_t *conf, void *key_get, size_t key_len, int idx)
0077 {
0078     return strcmp(NDRX_DDRV_SVC_INDEX((*conf->memptr), idx)->svcnm, key_get);
0079 }
0080 
0081 /**
0082  * Resolve the free place where to install the service
0083  * @param svcnm service name to resolve
0084  * @param[out] pos position found suitable to succeed request
0085  * @param[out] have_value valid value is found? EXTRUE/EXFALSE.
0086  * @param mem memory segment with which we shall work
0087  * @param memmax max number of elements
0088  * @return EXTRUE -> found position/ EXFALSE - no position found
0089  */
0090 exprivate int ndrx_ddr_position_get(char *svcnm, int oflag, int *pos, 
0091         int *have_value, char **mem, long memmax)
0092 {
0093     ndrx_lh_config_t conf;
0094     
0095     conf.elmmax = memmax;
0096     conf.elmsz = sizeof(ndrx_services_t);
0097     conf.flags_offset = EXOFFSET(ndrx_services_t, flags);
0098     conf.memptr = (void **)mem;
0099     conf.p_key_hash=&ndrx_ddr_key_hash;
0100     conf.p_key_debug=&ndrx_ddr_key_debug;
0101     conf.p_val_debug=&ndrx_ddr_debug;
0102     conf.p_compare=&ndrx_ddr_compare;
0103     
0104     return ndrx_lh_position_get(&conf, svcnm, 0, oflag, pos, have_value, "ddrsvc");
0105 }
0106 
0107 /**
0108  * put service in the hashmap
0109  * @return EXSUCCEED/EXFAIL
0110  */
0111 expublic int ndrx_ddr_services_put(ndrx_services_t *svc, char *mem, long memmax)
0112 {
0113     int have_value=EXFALSE;
0114     int pos=0;
0115     int ret = EXSUCCEED;
0116     ndrx_services_t *ptr = (ndrx_services_t *)mem;
0117     
0118     /* get position */
0119     
0120     if (!ndrx_ddr_position_get(svc->svcnm, O_CREAT, &pos, &have_value, &mem, memmax))
0121     {
0122         NDRX_LOG(log_error, "Failed to get position for [%s] in LH", svc->svcnm);
0123         EXFAIL_OUT(ret);
0124     }
0125     
0126     /* put value down */
0127     memcpy(&ptr[pos], svc, sizeof(*svc));
0128     ptr[pos].flags=NDRX_LH_FLAG_ISUSED|NDRX_LH_FLAG_WASUSED;
0129     
0130 out:
0131     return ret;
0132 }
0133 
0134 /** detect that unacceptable change has happened */
0135 #define DDR_SHM_CHANGED ndrx_G_shmcfg->ddr_ver1!=ver1_ok && ndrx_G_shmcfg->ddr_ver1!=ver2_ok
0136 
0137 /*
0138  * Detect that system is slow and we cannot detect the service settings
0139  */
0140 #define DDR_SHM_VALIDATE \
0141     if (DDR_SHM_CHANGED) \
0142     {\
0143         NDRX_LOG(log_error, "Unable to get DDR data for [%s] service - increase <ddrreload> "\
0144                 "time (accepted version: %u,%u current: %u)", \
0145                 svcnm, ver1_ok, ver2_ok, ndrx_G_shmcfg->ddr_ver1);\
0146         userlog("Unable to get DDR data for [%s] service - increase <ddrreload> "\
0147                 "time (accepted version: %u,%u current: %u)", \
0148                 svcnm, ver1_ok, ver2_ok, ndrx_G_shmcfg->ddr_ver1);\
0149         ndrx_TPset_error_fmt(TPESYSTEM, "Unable to get DDR data for [%s] service - increase <ddrreload> "\
0150                 "time (accepted version: %u,%u current: %u)", \
0151                 svcnm, ver1_ok, ver2_ok, ndrx_G_shmcfg->ddr_ver1);\
0152         EXFAIL_OUT(ret);\
0153     }
0154 
0155 /**
0156  * Get services entry.
0157  * Find the entry in current page of the DDR memory.
0158  * Thus DDR reloads shall be deferred for as long as possible time.
0159  * @param svcnm service name 
0160  * @param svc service descriptor
0161  * @return EXSUCCEED/EXFALSE/EXFAIL (tp error loaded)
0162  */
0163 expublic int ndrx_ddr_services_get(char *svcnm, ndrx_services_t **svc)
0164 {
0165     int ret = EXFALSE;
0166     int have_value=EXFALSE;
0167     int pos=0;
0168     int page;
0169     unsigned char ver1_ok;
0170     unsigned char ver2_ok;
0171     ndrx_services_t *ptr;
0172     
0173     /* ddr not used. */
0174     if (!ndrx_G_shmcfg->use_ddr)
0175     {
0176         /* no DDR settings here... */
0177         return EXFALSE;
0178     }
0179     
0180     ver1_ok = ndrx_G_shmcfg->ddr_ver1;
0181     ver2_ok = ndrx_G_shmcfg->ddr_ver1+1;
0182 
0183     page = ndrx_G_shmcfg->ddr_page;
0184     ptr = (ndrx_services_t *) (ndrx_G_routsvc.mem + page*G_atmi_env.rtsvcmax * sizeof(ndrx_services_t));
0185     
0186     if (EXTRUE==ndrx_ddr_position_get(svcnm, 0, &pos, 
0187         &have_value, (char **)&ptr, G_atmi_env.rtsvcmax) && have_value)
0188     {
0189         *svc = &ptr[pos];
0190         
0191         NDRX_LOG(log_debug, "Found service [%s] in ddr service table, autotran=%d", 
0192                 (*svc)->svcnm, (*svc)->autotran);
0193         ret=EXTRUE;
0194     }
0195 
0196     DDR_SHM_VALIDATE;
0197     
0198     
0199 out:
0200     return ret;
0201 }
0202 
0203 /**
0204  * Get routing group defined for service
0205  * Note the page shall not be changed while we work here.
0206  * Thus DDR reloads shall be deferred for as long as possible time.
0207  * If routing is found, svcnm will be updated
0208  * @param[in,out] svcnm service to route, will be updated 
0209  * @param[in,out] svcnmsz buffer size of service
0210  * @param[in] data data to send to service
0211  * @param[in] len dat len to send to service
0212  * @param[out] prio if service if found return the priority
0213  * @return EXFALSE/EXSUCCEED group not found (or default), EXTRUE group loaded, EXFAIL - error
0214  */
0215 expublic int ndrx_ddr_grp_get(char *svcnm, size_t svcnmsz, char *data, long len,
0216         int *prio)
0217 {
0218     int ret = EXSUCCEED;
0219     ndrx_services_t *svc;
0220     int page;
0221     ndrx_routcrit_t *ccrit;
0222     ndrx_routcritseq_t *range;
0223     int offset_step=0, chk_step=0;
0224     int i;
0225     double floatval;
0226     long longval;
0227     char *strval=NULL;
0228     int strval_alloc=EXFALSE;
0229     buffer_obj_t *buf;
0230     char *mem_start;
0231     int in_range=EXFALSE;
0232     BFLDID fldid;
0233     int  fieldtypeid;
0234     char fldnm[UBFFLDMAX+1];
0235     int len_new;
0236     char grp[NDRX_DDR_GRP_MAX+1];
0237     unsigned char ver1_ok;
0238     unsigned char ver2_ok;
0239     int is_default = EXFALSE;
0240     int had_type_match = EXFALSE;
0241     
0242     /* not attached, nothing to return */
0243     if (!ndrx_shm_is_attached(&ndrx_G_routsvc))
0244     {
0245         goto out;
0246     }
0247 
0248     /* DDR not used system wide */
0249     if (!ndrx_G_shmcfg->use_ddr)
0250     {
0251         goto out;
0252     }
0253     
0254     ver1_ok = ndrx_G_shmcfg->ddr_ver1;
0255     ver2_ok = ndrx_G_shmcfg->ddr_ver1+1;
0256     
0257     ret=ndrx_ddr_services_get(svcnm, &svc);
0258     
0259     if (EXTRUE!=ret)
0260     {
0261         if (EXFALSE==ret)
0262         {
0263             NDRX_LOG(log_debug, "No DDR service for [%s]", svcnm);
0264         }
0265         
0266         /* no group defined at all - either failure loaded or not found
0267          * and we finish off
0268          * the ret is configured
0269          */
0270         goto out;
0271     }
0272     
0273     ret = EXSUCCEED; /* start to search now... */
0274     
0275     /* return default service call priority */
0276     *prio = svc->prio;
0277     
0278     if (EXEOS==svc->criterion[0])
0279     {
0280         /* criterion not found */
0281         goto out;
0282     }
0283     
0284     /* loop over the criterions at the offset 
0285      * and match the first buffer type on which we go over the sequence of the
0286      * rnages
0287      * Get the offset of the criterion stuff...
0288      */
0289     buf = ndrx_find_buffer(data);
0290     if (NULL==buf)
0291     {
0292         NDRX_LOG(log_error, "Cannot route [%s] service - invalid data buffer",
0293                 svcnm);
0294         userlog("Cannot route [%s] service - invalid data buffer",
0295                 svcnm);
0296         ndrx_TPset_error_fmt(TPESYSTEM, "Cannot route [%s] service - invalid data buffer",
0297                 svcnm);
0298         EXFAIL_OUT(ret);
0299     }
0300     
0301     /* OK start to run... */
0302     page = ndrx_G_shmcfg->ddr_page;
0303     mem_start = ndrx_G_routcrit.mem + page * G_atmi_env.rtcrtmax+svc->offset; 
0304     
0305     do
0306     {
0307         /* 
0308          * Check that we approach un-changed memory
0309          */
0310         DDR_SHM_VALIDATE;
0311 
0312         ccrit = (ndrx_routcrit_t *)(mem_start + offset_step);
0313         
0314         if (ccrit->criterionid!=svc->cirterionid)
0315         {
0316             /* no matching buffer - ok, this is finish in the search... 
0317              * generate error if memory has changed.
0318              */
0319             DDR_SHM_VALIDATE;
0320             goto out_rej;
0321         }
0322         
0323         /* check the types, shall match the current buffer */
0324         
0325         if (buf->type_id == ccrit->buffer_type_id)
0326         {
0327             had_type_match = EXTRUE;
0328             
0329             /*  OK this is ours to check... */
0330             if (BUF_TYPE_UBF==buf->type_id)
0331             {
0332                 fieldtypeid = ccrit->fieldtypeid;
0333                 fldid = ccrit->fldid;
0334                 NDRX_STRCPY_SAFE(fldnm, ccrit->field);
0335                 
0336                 /* Check that we are still valid here */
0337                 DDR_SHM_VALIDATE;
0338                 
0339                 if (BFLD_LONG == fieldtypeid)
0340                 {
0341                     if (EXSUCCEED!=CBget((UBFH *)data, fldid, 0, 
0342                             (char *)&longval, 0L, BFLD_LONG))
0343                     {
0344                         NDRX_LOG(log_error, "Cannot route [%s] - routing field not found [%s]: %s", 
0345                                 svcnm, fldnm, Bstrerror(Berror));
0346                         userlog("Cannot route [%s] - routing field not found [%s]: %s", 
0347                                 svcnm, fldnm, Bstrerror(Berror));
0348                         ndrx_TPset_error_fmt(TPESYSTEM, "Cannot route [%s] - routing field not found [%s]: %s", 
0349                                 svcnm, fldnm, Bstrerror(Berror));
0350                         EXFAIL_OUT(ret);
0351                     }
0352                 }
0353                 else if (BFLD_DOUBLE == fieldtypeid)
0354                 {
0355                     if (EXSUCCEED!=CBget((UBFH *)data, fldid, 0, 
0356                             (char *)&floatval, 0L, BFLD_DOUBLE))
0357                     {
0358                         NDRX_LOG(log_error, "Cannot route [%s] - routing field not found [%s]: %s", 
0359                                 svcnm, fldnm, Bstrerror(Berror));
0360                         userlog("Cannot route [%s] - routing field not found [%s]: %s", 
0361                                 svcnm, fldnm, Bstrerror(Berror));
0362                         ndrx_TPset_error_fmt(TPESYSTEM, "Cannot route [%s] - routing field not found [%s]: %s", 
0363                                 svcnm, fldnm, Bstrerror(Berror));
0364                         EXFAIL_OUT(ret);
0365                     }
0366                 }
0367                 else
0368                 {
0369                     /* alloc string copy with CF or to avoid allocations
0370                      * just use sysbuf page? as that size would gurantee that we
0371                      * fit in...
0372                      */
0373                     if (BFLD_STRING==Bfldtype(fldid))
0374                     {
0375                         /* optimization to skip the alloc if types matches. */
0376                         strval = Bfind((UBFH *)data, fldid, 0, NULL);
0377                     }
0378                     else
0379                     {
0380                         strval = Bgetsa ((UBFH *)data, fldid, 0, NULL);
0381                         /* check bellow on null too... */
0382                         strval_alloc=EXTRUE;
0383                     }
0384                     
0385                     if (NULL==strval)
0386                     {
0387                         NDRX_LOG(log_error, "Cannot route [%s] - routing field not found [%s]: %s", 
0388                                 svcnm, fldnm, Bstrerror(Berror));
0389                         userlog("Cannot route [%s] - routing field not found [%s]: %s", 
0390                                 svcnm, fldnm, Bstrerror(Berror));
0391                         ndrx_TPset_error_fmt(TPESYSTEM, "Cannot route [%s] - routing field not found [%s]: %s", 
0392                                 svcnm, fldnm, Bstrerror(Berror));
0393                         EXFAIL_OUT(ret);
0394                     }
0395                 }
0396             }
0397             
0398             offset_step+=sizeof(ndrx_routcrit_t);
0399 
0400             for (i=0; i < ccrit->rangesnr; i++)
0401             {
0402                 /* check that memory is not changed... */
0403                 DDR_SHM_VALIDATE;
0404                  
0405                 /* OK we got the range so loop over... */
0406                 range = (ndrx_routcritseq_t *)(mem_start + offset_step);
0407                 
0408                 /* check that we are in boundries */
0409                 if (range->flags & NDRX_DDR_FLAG_DEFAULT_VAL)
0410                 {
0411                     /* ranges OK, return group */
0412                     in_range=EXTRUE;
0413                 }
0414                 else if (range->flags & NDRX_DDR_FLAG_MIN)
0415                 {
0416                     /* so if bellow upper or equals then we are in the range */
0417                     if (BFLD_LONG == fieldtypeid)
0418                     {
0419                         if (longval <= range->upperl)
0420                         {
0421                             in_range=EXTRUE;
0422                         }
0423                     }
0424                     else if (BFLD_DOUBLE == fieldtypeid)
0425                     {    
0426                         if (floatval < range->upperd ||
0427                                 fabs(floatval - range->upperd) < DOUBLE_EQUAL)
0428                         {
0429                             in_range=EXTRUE;
0430                         }
0431                     }
0432                     else if (BFLD_STRING == fieldtypeid)
0433                     {
0434                         if (strcmp(strval, range->strrange) <= 0)
0435                         {
0436                             in_range=EXTRUE;
0437                         }
0438                     }
0439                 }
0440                 else if (range->flags & NDRX_DDR_FLAG_MAX)
0441                 {
0442                     /* so if bellow upper or equals then we are in the range */
0443                     if (BFLD_LONG == fieldtypeid)
0444                     {
0445                         if (longval >= range->lowerl)
0446                         {
0447                             in_range=EXTRUE;
0448                         }
0449                     }
0450                     else if (BFLD_DOUBLE == fieldtypeid)
0451                     {    
0452                         if (floatval > range->lowerd ||
0453                                 fabs(floatval - range->lowerd) < DOUBLE_EQUAL)
0454                         {
0455                             in_range=EXTRUE;
0456                         }
0457                     }
0458                     else if (BFLD_STRING == fieldtypeid)
0459                     {
0460                         /* if mem changed it can match or not match
0461                          * but anyway, the routing blobs are terminated with
0462                          * EOS in last routing block
0463                          * or rangesnr is set to 0
0464                          * thus it will never overflow.
0465                          * Also prior setting the data, memset is performed.
0466                          */
0467                         if (strcmp(strval, range->strrange) >=0)
0468                         {
0469                             in_range=EXTRUE;
0470                         }
0471                     }
0472                 }
0473                 else
0474                 {
0475                     /* full check not flags... */
0476                     if (BFLD_LONG == fieldtypeid)
0477                     {
0478                         if (longval >= range->lowerl &&
0479                                 longval <= range->upperl)
0480                         {
0481                             in_range=EXTRUE;
0482                         }
0483                     }
0484                     else if (BFLD_DOUBLE == fieldtypeid)
0485                     {    
0486                         if ( (floatval > range->lowerd ||
0487                                 fabs(floatval - range->lowerd) < DOUBLE_EQUAL) &&
0488                                 
0489                                 (floatval < range->upperd ||
0490                                 fabs(floatval - range->upperd) < DOUBLE_EQUAL)
0491                                 )
0492                         {
0493                             in_range=EXTRUE;
0494                         }
0495                     }
0496                     else if (BFLD_STRING == fieldtypeid)
0497                     {
0498                         if (strcmp(strval, range->strrange) >=0 &&
0499                                 strcmp(strval, range->strrange+range->strrange_upper) <=0
0500                                 )
0501                         {
0502                             in_range=EXTRUE;
0503                         }
0504                     }
0505                 }
0506                 
0507                 if (in_range)
0508                 {
0509                     ret=EXTRUE;
0510                     if (range->flags & NDRX_DDR_FLAG_DEFAULT_GRP)
0511                     {
0512                         NDRX_LOG(log_debug, "Default group matched");
0513                         is_default=EXTRUE;
0514                     }
0515                     else
0516                     {
0517                         /* copy off the group code */
0518                         NDRX_STRCPY_SAFE(grp, range->grp);
0519                         NDRX_LOG(log_debug, "Group [%s]  matched", grp);
0520                     }
0521                     break;
0522                 }
0523                     
0524                 /* step to next..., this is aligned step */
0525                 offset_step+=range->len;
0526             }
0527             /* validate offsets... */
0528             chk_step+=ccrit->len;
0529             
0530             /* loop is over, validate the blocks... */
0531             if (EXTRUE!=ret)
0532             {
0533                 assert(chk_step==offset_step);
0534             }
0535         }
0536         else
0537         {
0538             /* step over as not ours.. 
0539              * not sure about checks...?
0540              */
0541             offset_step+=ccrit->len;
0542         }
0543         
0544         /* check for next... */
0545     } while (svc->offset + offset_step + sizeof(ndrx_routcrit_t) < G_atmi_env.rtcrtmax && EXSUCCEED==ret);
0546     
0547     /* Validate that mem is not changed */
0548     DDR_SHM_VALIDATE;
0549     
0550     /* Route is found, if running default, no additional routing shall be done
0551      * Though one issue is that in cluster if sending the default
0552      * the bridge will attempt to route again...?
0553      */
0554     if (EXTRUE==ret && (!is_default))
0555     {
0556         /* add the group suffx, also check the buffer space 
0557          * If there is not enough space, return the error.
0558          */
0559         len_new =  strlen(svcnm) + strlen(grp) + 2;
0560         
0561         if (len_new > svcnmsz)
0562         {
0563             NDRX_LOG(log_error, "Cannot route [%s] - routed service "
0564                     "name too long incl 0x00: %d (max: %d)",
0565                     svcnm, len_new, svcnmsz);
0566             userlog("Cannot route [%s] - routed service "
0567                     "name too long incl 0x00: %d (max: %d)",
0568                     svcnm, len_new, svcnmsz);
0569             ndrx_TPset_error_fmt(TPESYSTEM, "Cannot route [%s] - routed service "
0570                     "name too long incl 0x00: %d (max: %d)",
0571                     svcnm, len_new, svcnmsz);
0572             EXFAIL_OUT(ret);
0573         }
0574         NDRX_STRCAT_S(svcnm, svcnmsz, NDRX_SYS_SVC_PFX);
0575         NDRX_STRCAT_S(svcnm, svcnmsz, grp);    
0576     }
0577     
0578     
0579 out_rej:
0580     
0581     /* terminate the request, if was routing, but route  or group / not found 
0582      * For non routed buffer types, we just bypass the routing, use default
0583      * service (Bug #779).
0584      */
0585     if (EXSUCCEED==ret && had_type_match)
0586     {
0587         NDRX_LOG(log_error, "Routing criterion for service [%s] buffer type [%s] is not found",
0588                 svcnm, G_buf_descr[buf->type_id].type);
0589         userlog("Routing criterion for service [%s] buffer type [%s] is not found",
0590                 svcnm, G_buf_descr[buf->type_id].type);
0591         ndrx_TPset_error_fmt(TPESYSTEM, "Routing criterion for service [%s] buffer type [%s] is not found",
0592                 svcnm, G_buf_descr[buf->type_id].type);
0593         ret=EXFAIL;
0594     }
0595     
0596 out:
0597     
0598     if (strval_alloc && NULL!=strval)
0599     {
0600         NDRX_FREE(strval);
0601     }
0602 
0603     NDRX_LOG(log_debug, "returns %d [%s]", ret, svcnm);
0604     
0605     return ret;
0606 }
0607 
0608 /**
0609  * Lookup the service
0610  * and provide settings
0611  * @param[in] svcnm service name to lookup
0612  * @param[out] autotran auto tran setting from services section
0613  * @param[out] trantime transaction timeout setting from services section
0614  * @return EXTRUE (loaded), EXFALSE (not found), EXFAIL (error!)
0615  */
0616 expublic int ndrx_ddr_service_get(char *svcnm, int *autotran, unsigned long *trantime)
0617 {
0618     ndrx_services_t *svc;
0619     int ret = EXFALSE;
0620     char svcnmtmp[XATMI_SERVICE_NAME_LENGTH+1];
0621     char *p;
0622     
0623     /* Check only part till the @, as we do not not care about the groups
0624      * here
0625      */
0626     NDRX_STRCPY_SAFE(svcnmtmp, svcnm);
0627     
0628     p = strchr(svcnmtmp, NDRX_SYS_SVC_PFXC);
0629     
0630     if (NULL!=p)
0631     {
0632         if (p==svcnmtmp)
0633         {
0634             /* no service */
0635             return EXFALSE;
0636         }
0637         
0638         /* terminate before the group */
0639         *p = EXEOS;
0640     }
0641     
0642     /* not attached, nothing to return */
0643     if (!ndrx_shm_is_attached(&ndrx_G_routsvc))
0644     {
0645         goto out;
0646     }
0647     
0648     /* not we might get EXFAIL here too.. */
0649     if (EXTRUE==(ret=ndrx_ddr_services_get(svcnmtmp, &svc)))
0650     {
0651         *autotran = svc->autotran;
0652         *trantime = svc->trantime;
0653     }
0654     
0655 out:
0656     return ret;
0657 }
0658 
0659 
0660 /* vim: set ts=4 sw=4 et smartindent: */