Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Enduro/X server API functions
0003  *
0004  * @file init.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 
0035 /*---------------------------Includes-----------------------------------*/
0036 #include <stdio.h>
0037 #include <stdlib.h>
0038 #include <errno.h>
0039 #include <unistd.h>
0040 
0041 #include <ndrstandard.h>
0042 #include <ndebug.h>
0043 #include <utlist.h>
0044 #include <string.h>
0045 #include "srv_int.h"
0046 #include "tperror.h"
0047 #include "atmi_tls.h"
0048 #include <atmi_int.h>
0049 #include <atmi_shm.h>
0050 #include <xa_cmn.h>
0051 #include <ndrx_ddr.h>
0052 
0053 /*---------------------------Externs------------------------------------*/
0054 /*---------------------------Macros-------------------------------------*/
0055 /*---------------------------Enums--------------------------------------*/
0056 /*---------------------------Typedefs-----------------------------------*/
0057 /*---------------------------Globals------------------------------------*/
0058 expublic shm_srvinfo_t *G_shm_srv = NULL;    /**< ptr to shared memory block of the server */
0059 exprivate MUTEX_LOCKDECL(M_advertise_lock); /**< protect from other threads doing advertise */
0060 
0061 /*---------------------------Statics------------------------------------*/
0062 /*---------------------------Prototypes---------------------------------*/
0063 
0064 /**
0065  * Protect advertise function
0066  * Protect from multi-threaded servers
0067  */
0068 expublic void ndrx_sv_advertise_lock(void)
0069 {
0070     MUTEX_LOCK_V(M_advertise_lock);
0071 }
0072 
0073 /**
0074  * Unlock advertise function
0075  */
0076 expublic void ndrx_sv_advertise_unlock(void)
0077 {
0078     MUTEX_UNLOCK_V(M_advertise_lock);
0079 }
0080 
0081 /**
0082  * Function for checking service function existance
0083  * @param a
0084  * @param b
0085  * @return
0086  */
0087 expublic int ndrx_svc_entry_fn_cmp(svc_entry_fn_t *a, svc_entry_fn_t *b)
0088 {
0089     return strcmp(a->svc_nm,b->svc_nm);
0090 }
0091 
0092 /**
0093  * This resolves service entry 
0094  * @param svc
0095  * @return
0096  */
0097 exprivate svc_entry_fn_t* resolve_service_entry(char *svc)
0098 {
0099     svc_entry_fn_t *ret=NULL, eltmp;
0100 
0101     if (NULL!=svc)
0102     {
0103         NDRX_STRCPY_SAFE(eltmp.svc_nm, svc);
0104         DL_SEARCH(G_server_conf.service_raw_list, ret, &eltmp, ndrx_svc_entry_fn_cmp);
0105     }
0106 
0107     return ret;
0108 }
0109 
0110 /**
0111  * Build final list of services to be advertised
0112  * @param svn_nm_srch
0113  * @param svn_nm_add
0114  * @param resolved
0115  * @return
0116  */
0117 exprivate int sys_advertise_service(char *svn_nm_srch, char *svn_nm_add, svc_entry_fn_t *resolved)
0118 {
0119     int ret=EXSUCCEED;
0120     int autotran=0;
0121     unsigned long trantime=NDRX_DDR_TRANTIMEDFLT;
0122     svc_entry_fn_t *svc_fn, *entry=NULL;
0123 
0124     /* resolve alias & add svc entry */
0125     if (NULL==resolved)
0126     {
0127         svc_fn=resolve_service_entry(svn_nm_srch);
0128     }
0129     else
0130     {
0131         svc_fn=resolved; /* already resolved. */
0132     }
0133 
0134     if (NULL==svc_fn)
0135     {
0136         ndrx_TPset_error_fmt(TPENOENT, "There is no entry for [%s] [%s]",
0137                         svn_nm_srch, svn_nm_add);
0138         ret=EXFAIL;
0139     }
0140     else
0141     {
0142         /* OK register that stuff */
0143         /* do the malloc! */
0144         if ( (entry = (svc_entry_fn_t*)NDRX_MALLOC(sizeof(svc_entry_fn_t))) == NULL)
0145         {
0146             NDRX_LOG(log_error, "Failed to allocate %d bytes for service entry",
0147                                             sizeof(svc_entry_fn_t));
0148 
0149             ndrx_TPset_error_fmt(TPEOS, "Failed to allocate %d bytes for service entry",
0150                                 sizeof(svc_entry_fn_t));
0151             ret=EXFAIL;
0152         }
0153         else
0154         {
0155             /* Fill up the details & let it run! */
0156             memcpy(entry, svc_fn, sizeof(svc_entry_fn_t));
0157             /* Set service name */
0158             NDRX_STRCPY_SAFE(entry->svc_nm, svn_nm_add);
0159             
0160             /* Set queue on which to listen */
0161 #ifdef EX_USE_POLL
0162             snprintf(entry->listen_q, sizeof(entry->listen_q), NDRX_SVC_QFMT_SRVID, 
0163                     G_server_conf.q_prefix, 
0164                     entry->svc_nm, (short)G_server_conf.srv_id);
0165 #else
0166             snprintf(entry->listen_q, sizeof(entry->listen_q), NDRX_SVC_QFMT, 
0167                     G_server_conf.q_prefix, entry->svc_nm);
0168 #endif
0169 
0170             /* Add to list! */
0171             /* Check the shared memory for autotran & timeout */
0172             if (EXTRUE==(ret=ndrx_ddr_service_get(svn_nm_add, &autotran, &trantime)))
0173             {
0174                 entry->autotran = autotran;
0175                 entry->trantime = trantime;
0176                 ret=EXSUCCEED;
0177             }
0178             
0179             /* if DDR memory changed too intensively
0180              * and the deferred setting was low
0181              */
0182             if (EXFAIL==ret)
0183             {
0184                 NDRX_LOG(log_error, "Failed to get DDR infos for [%s]", svn_nm_add);
0185                 EXFAIL_OUT(ret);
0186             }
0187             
0188             DL_APPEND(G_server_conf.service_list, entry);
0189             G_server_conf.adv_service_count++;
0190             NDRX_LOG(log_debug, "Advertising: SVC: [%s] FN: [%s] ADDR: [%p] "
0191                     "QUEUE: [%s] AUTOTRAN [%d] TRANTIME [%lu]",
0192                         entry->svc_nm, entry->fn_nm, entry->p_func, entry->listen_q,
0193                         entry->autotran, entry->trantime);
0194             entry=NULL;
0195         }
0196     }
0197     
0198 out:
0199     
0200     if (NULL!=entry)
0201     {
0202         NDRX_FREE(entry);
0203     }
0204     return ret;
0205 }
0206 
0207 /**
0208  * Builds linear array
0209  * @return
0210  */
0211 exprivate int build_service_array_list(void)
0212 {
0213     int ret=EXSUCCEED;
0214     int i=0;
0215     svc_entry_fn_t *f_tmp, *f_el;
0216             
0217     if (G_server_conf.service_array!=NULL)
0218         NDRX_FREE(G_server_conf.service_array);
0219 
0220     NDRX_LOG(log_debug, "about to allocate %d of svc ptrs", G_server_conf.adv_service_count);
0221 
0222     G_server_conf.service_array = NDRX_CALLOC(sizeof(svc_entry_fn_t *), G_server_conf.adv_service_count);
0223     
0224     if (NULL==G_server_conf.service_array)
0225     {
0226         ndrx_TPset_error_fmt(TPEOS, "Failed to allocate: %s", strerror(errno));
0227         ret=EXFAIL;
0228     }
0229     else
0230     {
0231         DL_FOREACH_SAFE(G_server_conf.service_list, f_el,f_tmp)
0232         {
0233             NDRX_LOG(log_debug, "assigning %d", i);
0234             G_server_conf.service_array[i] = f_el;
0235             i++;
0236         }
0237     }
0238     
0239     return ret;
0240 }
0241 
0242 /**
0243  * Add system (Enduro/X) internals specific queue 
0244  * @param qname queue name
0245  * @param is_admin is admin, else it is reply q
0246  * @return EXSUCCEED/EXFAIL
0247  */
0248 exprivate int add_specific_queue(char *qname, int is_admin)
0249 {
0250     int ret=EXSUCCEED;
0251 
0252     svc_entry_fn_t *entry;
0253     /* phase 0. Generate admin q */
0254     if ( (entry = (svc_entry_fn_t*)NDRX_CALLOC(1, sizeof(svc_entry_fn_t))) == NULL)
0255     {
0256         NDRX_LOG(log_error, "Failed to allocate %d bytes for admin service entry",
0257                                         sizeof(svc_entry_fn_t));
0258 
0259         ndrx_TPset_error_fmt(TPEOS, "Failed to allocate %d bytes for admin service entry",
0260                             sizeof(svc_entry_fn_t));
0261     }
0262     else
0263     {
0264         entry->q_descr=(mqd_t)EXFAIL;
0265         entry->p_func=NULL;
0266         entry->is_admin = is_admin;
0267         NDRX_STRCPY_SAFE(entry->listen_q, qname);
0268         /* register admin service */
0269         DL_APPEND(G_server_conf.service_list, entry);
0270         G_server_conf.adv_service_count++;
0271         NDRX_LOG(log_debug, "Advertising: SVC: [%s] FN: [%s] ADDR: [%p] QUEUE: [%s]",
0272                         entry->svc_nm, entry->fn_nm, entry->p_func, entry->listen_q);
0273     }
0274 
0275     return ret;
0276 }
0277 
0278 /**
0279  * Perform service limit check
0280  */
0281 #define LIMIT_CHECK do {                                                               \
0282         if ((final_nr_services+1) > (MAX_SVC_PER_SVR - ATMI_SRV_Q_ADJUST))             \
0283         {                                                                              \
0284             NDRX_LOG(log_error, "ERROR: Failed to advertise: service "                 \
0285                                 "limit per process %d reached on [%s]!",               \
0286                                 (MAX_SVC_PER_SVR-ATMI_SRV_Q_ADJUST), svn_nm_add);      \
0287             userlog("ERROR: Failed to advertise: service "                             \
0288                                 "limit per process %d reached on [%s]!",               \
0289                                 (MAX_SVC_PER_SVR-ATMI_SRV_Q_ADJUST), svn_nm_add);      \
0290             EXFAIL_OUT(ret);                                                           \
0291         }                                                                              \
0292     } while (0)
0293 
0294 /**
0295  * Functions builds final list what needs to be actually advertised to EX system
0296  * See description of tpadvertise_full() for -A & -s logic
0297  *
0298  * We have some few specific queues:
0299  * 0 - admin queue;
0300  * 1 - reply queue;
0301  * 
0302  * @return
0303  */
0304 expublic int atmisrv_build_advertise_list(void)
0305 {
0306     int ret=EXSUCCEED;
0307     svc_entry_t *s_tmp, *s_el;
0308     svc_entry_fn_t *f_tmp, *f_el;
0309     pid_t mypid = getpid();
0310     int final_nr_services = 0;
0311 
0312     char *svn_nm_srch=NULL;
0313     char *svn_nm_add=NULL;
0314     
0315     char adminq[NDRX_MAX_Q_SIZE+1];
0316     char replyq[NDRX_MAX_Q_SIZE+1];
0317 
0318     /* Server admin queue */
0319     snprintf(adminq, sizeof(adminq), NDRX_ADMIN_FMT, G_server_conf.q_prefix,
0320                                 G_server_conf.binary_name, 
0321                                 G_server_conf.srv_id, mypid);
0322     ret=add_specific_queue(adminq, 1);
0323     
0324     if (EXFAIL==ret)
0325         goto out;
0326 
0327     /* Server reply queue */
0328     snprintf(replyq, sizeof(replyq), NDRX_SVR_QREPLY, G_server_conf.q_prefix,
0329                                     G_server_conf.binary_name, 
0330                                     G_server_conf.srv_id, mypid);
0331     
0332     ret=add_specific_queue(replyq, 0);
0333     if (EXFAIL==ret)
0334         goto out;
0335 
0336     /* phase 1. check all command line specified */
0337     DL_FOREACH_SAFE(G_server_conf.svc_list, s_el, s_tmp)
0338     {
0339         /* In this case we are only interested in aliases */
0340         if (EXEOS!=s_el->svc_aliasof[0])
0341         {
0342             svn_nm_srch=s_el->svc_aliasof;
0343             svn_nm_add=s_el->svc_nm;
0344         }
0345         /* else if (!G_server_conf.advertise_all) - why? */
0346         else
0347         {
0348             svn_nm_srch=s_el->svc_nm;
0349             svn_nm_add=s_el->svc_nm;
0350         }
0351         
0352         /* check that this service isn't masked out for advertise */
0353         if (ndrx_svchash_chk(&ndrx_G_svchash_skip, svn_nm_add))
0354         {
0355             NDRX_LOG(log_info, "%s masked by -n - not advertising", 
0356                     svn_nm_add);
0357             continue;
0358         }
0359 
0360         LIMIT_CHECK;
0361         
0362         if (EXSUCCEED!=(ret=sys_advertise_service(svn_nm_srch, svn_nm_add, NULL)))
0363         {
0364             NDRX_LOG(log_error, "Phase 1 advertise FAIL!");
0365             goto out;
0366         }
0367         
0368         final_nr_services++;
0369 
0370     }
0371     
0372     /* phase 2. advertise all, that we have from tpadvertise 
0373      * (only in case if we have -A) 
0374      */
0375     DL_FOREACH_SAFE(G_server_conf.service_raw_list,f_el,f_tmp)
0376     {
0377         /* if have service the list of -S, then still want to be advertised */
0378         if (!G_server_conf.advertise_all &&
0379                 !ndrx_svchash_chk(&ndrx_G_svchash_funcs, f_el->svc_nm))
0380         {
0381             continue;
0382         }
0383         
0384         /* check that this service isn't masked out for advertise */
0385         if (ndrx_svchash_chk(&ndrx_G_svchash_skip, f_el->svc_nm))
0386         {
0387             NDRX_LOG(log_info, "%s masked by -n - not advertising", 
0388                     f_el->svc_nm);
0389             continue;
0390         }
0391 
0392         svn_nm_srch=f_el->svc_nm;
0393         svn_nm_add=f_el->svc_nm;
0394 
0395         LIMIT_CHECK;
0396 
0397         if (EXSUCCEED!=(ret=sys_advertise_service(svn_nm_srch, 
0398                 svn_nm_add, NULL)))
0399         {
0400             NDRX_LOG(log_error, "Phase 2 advertise FAIL!");
0401             goto out;
0402         }
0403 
0404         final_nr_services++;
0405     }
0406     
0407     ret=build_service_array_list();
0408 
0409 out:
0410 
0411     return ret;
0412 }
0413 
0414 /**
0415  * Initialize common ATMI library
0416  * @return SUCCED/FAIL
0417  */
0418 expublic int atmisrv_initialise_atmi_library(void)
0419 {
0420     int ret=EXSUCCEED;
0421     atmi_lib_conf_t conf;
0422     pid_t pid = getpid();
0423     
0424     memset(&conf, 0, sizeof(conf));
0425     
0426     /* if thread id is not set, then do it here, as if
0427      * tpsrvinit() did not do tpinit(), then ctxid could be left here as un-init 
0428      */
0429     
0430     
0431     conf.contextid = G_atmi_tls->G_atmi_conf.contextid;
0432     
0433     if (!conf.contextid)
0434     {
0435         conf.contextid = ndrx_ctxid_op(EXFALSE, EXFAIL);
0436         NDRX_DBG_SETTHREAD(conf.contextid);
0437     }
0438     
0439     /* Generate my_id */
0440     snprintf(conf.my_id, sizeof(conf.my_id), NDRX_MY_ID_SRV, 
0441             G_server_conf.binary_name, 
0442             G_server_conf.srv_id, pid, 
0443             conf.contextid, 
0444             G_atmi_env.our_nodeid);
0445     
0446     conf.is_client = 0;
0447     
0448     NDRX_LOG(log_debug, "Server my_id=[%s]", conf.my_id);
0449     /*
0450     conf.reply_q = G_server_conf.service_array[1]->q_descr;
0451     strcpy(conf.reply_q_str, G_server_conf.service_array[1]->listen_q);
0452     */
0453     
0454     NDRX_STRCPY_SAFE(conf.q_prefix, G_server_conf.q_prefix);
0455     if (EXSUCCEED!=(ret=tp_internal_init(&conf)))
0456     {
0457         goto out;
0458     }
0459     
0460     /* Try to open shm... */
0461     G_shm_srv = ndrxd_shm_getsrv(G_srv_id);
0462     
0463     /* Mark stuff as used! */
0464     if (NULL!=G_shm_srv)
0465     {
0466         G_shm_srv->srvid = G_srv_id;  
0467         /* reset any error if booting from outside... */
0468         G_shm_srv->execerr = 0;
0469     }
0470     
0471 out:
0472     return ret;
0473 }
0474 
0475 /**
0476  * Un-initialize all stuff
0477  * TODO: Think about client close in case if we fail.
0478  * @return void
0479  */
0480 expublic void atmisrv_un_initialize(int fork_uninit)
0481 {
0482     int i;
0483     atmi_tls_t *tls;
0484     
0485     
0486     /* check are we servers or clients? */
0487     if (G_atmi_tls->G_atmi_conf.is_client)
0488     {
0489         tpterm();
0490         return;
0491     }
0492     
0493     /* We should close the queues and detach shared memory!
0494      * Also we will not remove service queues, because we do not
0495      * what other instances do. This is up to ndrxd!
0496      */
0497     if (NULL!=G_server_conf.service_array)
0498     {
0499         for (i=0; i<G_server_conf.adv_service_count; i++)
0500         {
0501 
0502             if (NULL==G_server_conf.service_array[i])
0503             {
0504                 /* nothing to do if NULL */
0505                 continue;
0506             }
0507             
0508             /* remove queues from poller */
0509             if (!fork_uninit && 0!=G_server_conf.epollfd &&
0510                     EXFAIL==ndrx_epoll_ctl_mq(G_server_conf.epollfd, EX_EPOLL_CTL_DEL,
0511                     G_server_conf.service_array[i]->q_descr, NULL))
0512             {
0513                 NDRX_LOG(log_warn, "ndrx_epoll_ctl failed to remove fd %p from epollfd: %s", 
0514                         ((void *)(long)G_server_conf.service_array[i]->q_descr),
0515                         ndrx_poll_strerror(ndrx_epoll_errno()));
0516             }
0517             
0518             /* just close it, no error check */
0519             if(((mqd_t)EXFAIL)!=G_server_conf.service_array[i]->q_descr &&
0520                         ndrx_epoll_shallopenq(i) &&
0521             EXSUCCEED!=ndrx_mq_close(G_server_conf.service_array[i]->q_descr))
0522             {
0523 
0524                 NDRX_LOG(log_error, "Failed to close q descr %d: %d/%s",
0525                                             G_server_conf.service_array[i]->q_descr,
0526                                             errno, strerror(errno));
0527             }
0528 
0529             if (!fork_uninit && (ATMI_SRV_ADMIN_Q==i || ATMI_SRV_REPLY_Q==i))
0530             {
0531                 NDRX_LOG(log_debug, "Removing queue: %s",
0532                                     G_server_conf.service_array[i]->listen_q);
0533                 /* TODO: For admin Q we need a special callback to poller...
0534                  * to terminate it... So that System V could kill the thread
0535                  * and we do not get some un-expected core dumps when 
0536                  * unlink removes the queue descriptor, but thread may still
0537                  * doing something with the mqd.
0538                  */
0539                 if (EXSUCCEED!=ndrx_mq_unlink(G_server_conf.service_array[i]->listen_q))
0540                 {
0541                     NDRX_LOG(log_error, "Failed to remove queue %s: %d/%s",
0542                                             G_server_conf.service_array[i]->listen_q,
0543                                             errno, strerror(errno));
0544                 }
0545             }
0546         }/* for */
0547     }
0548 
0549     /* Now detach shared memory block */
0550     ndrxd_shm_close_all();
0551 
0552     /* close poller */
0553     NDRX_LOG(log_debug, "epollfd = %d", G_server_conf.epollfd);
0554     if (G_server_conf.epollfd > 0)
0555     {
0556         ndrx_epoll_close(G_server_conf.epollfd);
0557         G_server_conf.epollfd = 0;
0558     }
0559 
0560     if (NULL != G_server_conf.events)
0561     {
0562         NDRX_FREE((char *)G_server_conf.events);
0563     }
0564     
0565     /* close XA if was open.. */
0566     atmi_xa_uninit();
0567     ndrx_svchash_cleanup(&ndrx_G_svchash_skip);
0568     ndrx_svchash_cleanup(&ndrx_G_svchash_funcs);
0569     /* Mark our environment as un-initialized 
0570      * In external main() function cases, they might want to reuse the ATMI
0571      * context, and it is not server any more.
0572      */
0573     
0574     tls = ndrx_atmi_tls_get(0);
0575     ndrx_atmi_tls_new(tls, tls->is_auto, EXTRUE);
0576 }
0577 
0578 /**
0579  * Advertise service (internal version)
0580  * Outer version group groups might do advertise twice
0581  * OK, logic will be following:
0582  * -A advertise all services + additional (aliases) by -s
0583  * if -A missing, then advertise all
0584  * if -A missing, -s specified, then advertise those by -s only
0585  * @param[in] autotran shall we start transaction automatically?
0586  * @param[in] trantime how long auto-transaction shall live?
0587  * @return SUCCEED/FAIL
0588  */
0589 exprivate int tpadvertise_full_int(char *svc_nm, void (*p_func)(TPSVCINFO *), char *fn_nm)
0590 {
0591     int ret=EXSUCCEED;
0592     svc_entry_fn_t *entry=NULL, eltmp;
0593     int len;
0594     
0595     ndrx_sv_advertise_lock();
0596     
0597     if (NULL==fn_nm || EXEOS ==fn_nm[0])
0598     {
0599         ndrx_TPset_error_fmt(TPEINVAL, "fn_nm is NULL or empty string");
0600         EXFAIL_OUT(ret);
0601     }
0602     
0603     len=strlen(svc_nm);
0604     if (MAXTIDENT < len)
0605     {
0606         ndrx_TPset_error_fmt(TPEINVAL, "svc_nm len is %d but max is %d (MAXTIDENT)",
0607                 len, MAXTIDENT);
0608         EXFAIL_OUT(ret);
0609     }
0610     
0611     if (NULL==p_func)
0612     {
0613         ndrx_TPset_error_msg(TPEINVAL, "Service function is NULL (p_func)");
0614         EXFAIL_OUT(ret);
0615     }
0616     
0617 
0618     /* allocate memory for entry */
0619     if ( (entry = (svc_entry_fn_t*)NDRX_CALLOC(1, sizeof(svc_entry_fn_t))) == NULL)
0620     {
0621         ndrx_TPset_error_fmt(TPEOS, "Failed to allocate %d bytes while parsing -s",
0622                             sizeof(svc_entry_fn_t));
0623         ret=EXFAIL;
0624         goto out;
0625     }
0626     else
0627     {
0628         svc_entry_fn_t *existing=NULL;
0629         /* fill entry details */
0630         NDRX_STRCPY_SAFE(entry->svc_nm, svc_nm);
0631         NDRX_STRCPY_SAFE(entry->fn_nm, fn_nm);
0632 
0633         /* At this point we need to check the convert flags... */
0634         entry->xcvtflags = ndrx_xcvt_lookup(entry->fn_nm);
0635         entry->p_func = p_func;
0636         entry->q_descr = (mqd_t)EXFAIL;
0637        
0638         /* search for existing entry */
0639         NDRX_STRCPY_SAFE(eltmp.svc_nm, entry->svc_nm);
0640 
0641         if (NULL==G_server_conf.service_array)
0642         {
0643             DL_SEARCH(G_server_conf.service_raw_list, existing, &eltmp, ndrx_svc_entry_fn_cmp);
0644 
0645             if (existing)
0646             {
0647                 /* OK, we have in list. So print warning and remove old one! */
0648                 if (existing->p_func==p_func)
0649                 {
0650                     NDRX_LOG(log_info, "Service with name [%s] is already "
0651                                     "advertised, same function.", svc_nm);
0652                 }
0653                 else
0654                 {
0655                     /* We have error! */
0656                     NDRX_LOG(log_error, "ERROR: Service with name [%s] "
0657                                         "already advertised, "
0658                                         "but pointing to different "
0659                                         "function - FAIL", svc_nm);
0660                     ndrx_TPset_error_fmt(TPEMATCH, "ERROR: Service with name [%s] "
0661                                         "already advertised, "
0662                                         "but pointing to different function - "
0663                                         "FAIL", svc_nm);
0664                     userlog("ERROR: Service with name [%s] "
0665                                         "already advertised, "
0666                                         "but pointing to different function - "
0667                                         "FAIL", svc_nm);
0668                     ret=EXFAIL;
0669                 }
0670                 NDRX_FREE(entry);
0671             }
0672             else
0673             {
0674                 /* Do not count if G_server_conf.advertise_all is 0
0675                  * as these really does not open the queues...
0676                  */
0677                 if (G_server_conf.advertise_all && 
0678                         (G_server_conf.service_raw_list_count+1) > (MAX_SVC_PER_SVR - ATMI_SRV_Q_ADJUST))
0679                 {
0680                     userlog("Failed to advertise: service limit per process %d reached on [%s]!", 
0681                             MAX_SVC_PER_SVR-ATMI_SRV_Q_ADJUST, entry->svc_nm);
0682                     ndrx_TPset_error_fmt(TPELIMIT, "Failed to advertise: Service "
0683                             "limit per process %d reached on [%s]!", 
0684                             MAX_SVC_PER_SVR-ATMI_SRV_Q_ADJUST, entry->svc_nm);
0685                     NDRX_FREE(entry);
0686                     EXFAIL_OUT(ret);
0687                 }
0688                 
0689                 /* register the function */
0690                 NDRX_LOG(log_debug, "Service [%s] "
0691                                         "(function: [%s]:%p) successfully "
0692                                         "acknowledged",
0693                                         entry->svc_nm, entry->fn_nm, entry->p_func);
0694                 DL_APPEND(G_server_conf.service_raw_list, entry);
0695                 G_server_conf.service_raw_list_count++;
0696             }
0697         }
0698         else
0699         {
0700             
0701             if (G_server_conf.is_threaded)
0702             {
0703                 ndrx_TPset_error_fmt(TPENOENT, "%s: runtime tpadvertise() not "
0704                         "supported for multi-threaded servers (svcnm=[%s])", 
0705                         __func__, svc_nm);
0706                 userlog("%s: runtime tpadvertise() not "
0707                         "supported for multi-threaded servers (svcnm=[%s])", 
0708                         __func__, svc_nm);
0709                 EXFAIL_OUT(ret);
0710             }
0711 
0712             NDRX_LOG(log_warn, "Processing dynamic advertise");
0713             if (EXFAIL==dynamic_advertise(entry, svc_nm, p_func, fn_nm))
0714             {
0715                 ret=EXFAIL;
0716                 NDRX_FREE(entry);
0717                 goto out;
0718             }
0719         }
0720     }
0721     
0722 out:
0723     ndrx_sv_advertise_unlock();
0724     return ret;
0725 }
0726 
0727 /**
0728  * Unadvertises service (internal)
0729  * This will process only last request. All others will expire as queue
0730  * Possibly will be removed!
0731  * @param svcname
0732  * @return 
0733  */
0734 exprivate int tpunadvertise_int(char *svcname)
0735 {
0736     int ret=EXSUCCEED;
0737     char svc_nm[XATMI_SERVICE_NAME_LENGTH+1] = {EXEOS};
0738     svc_entry_fn_t eltmp;
0739     svc_entry_fn_t *existing=NULL;
0740     char *thisfn="tpunadvertise";
0741     
0742     ndrx_sv_advertise_lock();
0743     /* Validate argument */
0744     if (NULL==svcname || EXEOS==svcname[0])
0745     {
0746         ndrx_TPset_error_fmt(TPEINVAL, "%s: invalid svcname empty or null!", thisfn);
0747         ret=EXFAIL;
0748         goto out;
0749     }
0750     
0751     /* Crosscheck buffer. */
0752     NDRX_STRCPY_SAFE(svc_nm, svcname);
0753     
0754     /* Search for service entry */
0755     NDRX_STRCPY_SAFE(eltmp.svc_nm, svc_nm);
0756 
0757     if (NULL==G_server_conf.service_array)
0758     {
0759         DL_SEARCH(G_server_conf.service_raw_list, existing, &eltmp, ndrx_svc_entry_fn_cmp);
0760 
0761         if (existing)
0762         {
0763             NDRX_LOG(log_debug, "in server init stage - simply remove from array service");
0764             DL_DELETE(G_server_conf.service_raw_list, existing);
0765             NDRX_FREE(existing);
0766             G_server_conf.service_raw_list_count--;
0767         }
0768         else
0769         {
0770             /* Need to inform server about changes + reconfigure polling 
0771             * Firstly we re-configure polling, then delete allocated structs
0772             * then send info to server.
0773             */
0774             ndrx_TPset_error_fmt(TPENOENT, "%s: service [%s] not advertised", 
0775                     thisfn, svc_nm);
0776             ret=EXFAIL;
0777             goto out;
0778         }
0779     }
0780     else
0781     {
0782         
0783         if (G_server_conf.is_threaded)
0784         {
0785             ndrx_TPset_error_fmt(TPENOENT, "%s: runtime tpunadvertise() not "
0786                         "supported for multi-threaded servers (svcnm=[%s])", 
0787                         __func__, svc_nm);
0788             userlog("%s: runtime tpunadvertise() not "
0789                     "supported for multi-threaded servers (svcnm=[%s])", 
0790                     __func__, svc_nm);
0791             EXFAIL_OUT(ret);   
0792         }
0793         
0794         if (EXSUCCEED!=dynamic_unadvertise(svcname, NULL, NULL))
0795         {
0796             ret=EXFAIL;
0797             goto out;
0798         }
0799         
0800     }
0801     
0802 out:
0803     ndrx_sv_advertise_unlock();
0804     return ret;
0805 }
0806 
0807 
0808 
0809 /* ===========================================================================*/
0810 /* =========================API FUNCTIONS=====================================*/
0811 /* ===========================================================================*/
0812 /**
0813  * Advertise service
0814  * OK, logic will be following:
0815  * -A advertise all services + additional (aliases) by -s
0816  * if -A missing, then advertise all
0817  * if -A missing, -s specified, then advertise those by -s only
0818  * This returns error (and terminates)
0819  * @return SUCCEED/FAIL
0820  */
0821 expublic int tpadvertise_full(char *svc_nm, void (*p_func)(TPSVCINFO *), char *fn_nm)
0822 {
0823     int ret = EXSUCCEED;
0824     char svcn_nm_full[MAXTIDENT*2]={EXEOS};
0825     atmi_error_t err;
0826     int grp_ok=EXFALSE;
0827     
0828     ndrx_TPunset_error();
0829     /* if we live in group, then advertise twice... */
0830     
0831     /* Check arguments Bug #610 */
0832     if (NULL==svc_nm || EXEOS ==svc_nm[0])
0833     {
0834         ndrx_TPset_error_fmt(TPEINVAL, "svc_nm is NULL or empty string");
0835         EXFAIL_OUT(ret);
0836     }
0837     
0838     if (EXEOS!=G_atmi_env.rtgrp[0])
0839     {
0840         NDRX_STRCPY_SAFE(svcn_nm_full, svc_nm);
0841         NDRX_STRCAT_S(svcn_nm_full, sizeof(svcn_nm_full), NDRX_SYS_SVC_PFX);
0842         NDRX_STRCAT_S(svcn_nm_full, sizeof(svcn_nm_full), G_atmi_env.rtgrp);
0843      
0844         NDRX_LOG(log_info, "About to advertise group service [%s]", svcn_nm_full);
0845         if (EXSUCCEED!=tpadvertise_full_int(svcn_nm_full, p_func, fn_nm))
0846         {
0847             NDRX_LOG(log_error, "Failed to advertises group service [%s]",
0848                     svcn_nm_full);
0849             EXFAIL_OUT(ret);
0850         }
0851         
0852         grp_ok=EXTRUE;
0853     }
0854     
0855     NDRX_LOG(log_info, "About to advertise service [%s]", svc_nm);
0856     if (EXSUCCEED!=tpadvertise_full_int(svc_nm, p_func, fn_nm))
0857     {
0858         NDRX_LOG(log_error, "Failed to advertises service [%s]",
0859                 svcn_nm_full);
0860         EXFAIL_OUT(ret);
0861     }
0862     
0863 out:
0864     
0865     /* 
0866      * if failed normal advertise, then unadvertise the group service
0867      */
0868     if (EXSUCCEED!=ret && grp_ok)
0869     {
0870         ndrx_TPsave_error(&err);
0871         tpunadvertise_int(svcn_nm_full);
0872         ndrx_TPrestore_error(&err);
0873     }
0874 
0875     return ret;
0876 }
0877 
0878 /**
0879  * If living in group, remove two services
0880  * This will probe both version to remove. At first
0881  * it is group version, then it is normal version
0882  * 
0883  * @param svcname to unadvertise
0884  * @return EXSUCCEED/EXFAIL
0885  */
0886 expublic int tpunadvertise(char *svcname)
0887 {
0888     int ret = EXSUCCEED;
0889     char svcn_nm_full[MAXTIDENT*2]={EXEOS};
0890     ndrx_TPunset_error();
0891     
0892     if (NULL==svcname || EXEOS ==svcname[0])
0893     {
0894         ndrx_TPset_error_fmt(TPEINVAL, "svc_nm is NULL or empty string");
0895         EXFAIL_OUT(ret);
0896     }
0897     
0898     if (EXEOS!=G_atmi_env.rtgrp[0])
0899     {
0900         NDRX_STRCPY_SAFE(svcn_nm_full, svcname);
0901         NDRX_STRCAT_S(svcn_nm_full, sizeof(svcn_nm_full), NDRX_SYS_SVC_PFX);
0902         NDRX_STRCAT_S(svcn_nm_full, sizeof(svcn_nm_full), G_atmi_env.rtgrp);
0903      
0904         NDRX_LOG(log_info, "About to unadvertise group service [%s]", svcn_nm_full);
0905         
0906         if (EXSUCCEED!=tpunadvertise_int(svcn_nm_full))
0907         {
0908             ret=EXFAIL;
0909         }
0910         
0911         /* first erro will stay there */
0912     }
0913     
0914     NDRX_LOG(log_info, "About to unadvertise normal servcie [%s]", svcname);
0915     
0916     if (EXSUCCEED!=tpunadvertise_int(svcname))
0917     {
0918         ret=EXFAIL;
0919     }
0920     
0921 out:
0922     return ret;
0923 }
0924 
0925 
0926 /**
0927  * Removes array element & rsizes the block
0928  * @param arr
0929  * @param elem - zero based elem number to be removed.
0930  * @param len
0931  * @param sz
0932  * @return 
0933  */
0934 expublic int atmisrv_array_remove_element(void *arr, int elem, int len, int sz)
0935 {
0936     int ret=EXSUCCEED;
0937     
0938     if (elem<len-1)
0939     {
0940     /*NDRX_DUMP(log_error, "Before mem move", arr, len*sz);*/
0941         memmove(arr+elem*sz, arr+(elem+1)*sz, (len-elem-1)*sz);
0942     /*NDRX_DUMP(log_error, "After mem move", arr, len*sz);*/
0943         /* Clear up last element we removed. */
0944         memset(arr+(len-1)*sz, 0, sz);
0945     /*NDRX_DUMP(log_error, "After mem set", arr, len*sz);*/
0946     }
0947     
0948 out:
0949     return ret;
0950 }
0951 /* vim: set ts=4 sw=4 et smartindent: */