Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Administrative server
0003  *
0004  * @file tpadmsv.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 <stdio.h>
0035 #include <stdlib.h>
0036 #include <string.h>
0037 #include <errno.h>
0038 #include <regex.h>
0039 #include <utlist.h>
0040 #include <unistd.h>
0041 #include <signal.h>
0042 
0043 #include <ndebug.h>
0044 #include <atmi.h>
0045 #include <atmi_int.h>
0046 #include <typed_buf.h>
0047 #include <ndrstandard.h>
0048 #include <ubf.h>
0049 #include <Exfields.h>
0050 #include <Excompat.h>
0051 #include <ubfutil.h>
0052 #include <tpadm.h>
0053 
0054 #include "tpadmsv.h"
0055 /*---------------------------Externs------------------------------------*/
0056 /*---------------------------Macros-------------------------------------*/
0057 /*---------------------------Enums--------------------------------------*/
0058 /*---------------------------Typedefs-----------------------------------*/
0059 /*---------------------------Globals------------------------------------*/
0060 expublic ndrx_adm_conf_t ndrx_G_adm_config;   /**< admin server config    */
0061 /*---------------------------Statics------------------------------------*/
0062 
0063 /*---------------------------Prototypes---------------------------------*/
0064 
0065 expublic char ndrx_G_svcnm_node[MAXTIDENT+1]; /**< node based entry */
0066 expublic char ndrx_G_svcnm2[MAXTIDENT+1]; /**< our service name, per instance. */
0067 
0068 /**
0069  * MIB Service
0070  * @param p_svc
0071  */
0072 void MIB (TPSVCINFO *p_svc)
0073 {
0074     int ret=EXSUCCEED;
0075     char clazz[MAXTIDENT+1];
0076     char op[MAXTIDENT+1];
0077     char cursid[MAXTIDENT+1];
0078     char cursid_svc[MAXTIDENT+1];
0079     ndrx_adm_cursors_t cursnew; /* New cursor */
0080     ndrx_adm_cursors_t *curs;
0081     BFLDLEN len;
0082     ndrx_adm_class_map_t *class_map;
0083     int is_get = EXFALSE;
0084     long ret_occurs = 0;
0085     long ret_more = 0;
0086     UBFH *p_ub = (UBFH *)p_svc->data;
0087     /* get the incoming buffer new size: */
0088     long bufsz = NDRX_MIN(ndrx_G_adm_config.buffer_minsz, NDRX_MSGSIZEMAX);
0089     
0090     /* Allocate some buffer size  */
0091     
0092     ndrx_debug_dump_UBF(log_info, "Request buffer:", p_ub);
0093     
0094     /* Realloc to size: */
0095     p_ub = (UBFH *)tprealloc (p_svc->data, bufsz);
0096         
0097     if (NULL==p_ub)
0098     {
0099         NDRX_LOG(log_error, "Failed realloc UBF to %d bytes: %s", 
0100                 bufsz, tpstrerror(tperrno));
0101         p_ub = (UBFH *)p_svc->data;
0102         EXFAIL_OUT(ret);
0103     }
0104     
0105     len = sizeof(op);
0106     if (EXSUCCEED!=Bget(p_ub, TA_OPERATION, 0, op, &len))
0107     {
0108         NDRX_LOG(log_error, "Failed to get TA_OPERATION: %s", Bstrerror(Berror));
0109         
0110         ndrx_adm_error_set(p_ub, TAEREQUIRED, TA_OPERATION, 
0111                 "Failed to get TA_OPERATION: %s", Bstrerror(Berror));
0112         
0113         EXFAIL_OUT(ret);
0114     }
0115     
0116     /* get cursor if required */
0117     if (0==strcmp(NDRX_TA_GETNEXT, op))
0118     {
0119         char *p;
0120         len = sizeof(cursid);
0121         if (EXSUCCEED!=Bget(p_ub, TA_CURSOR, 0, cursid, &len))
0122         {
0123             NDRX_LOG(log_error, "Failed to get TA_CURSOR: %s", Bstrerror(Berror));
0124 
0125             ndrx_adm_error_set(p_ub, TAEREQUIRED, TA_CURSOR, 
0126                         "Failed to get TA_CURSOR: %s", Bstrerror(Berror));
0127 
0128             EXFAIL_OUT(ret);
0129         }
0130         
0131         /* check the cursor target, if other MIB server, then forward
0132          * the call
0133          */
0134         
0135         NDRX_STRCPY_SAFE(cursid_svc, cursid);
0136         
0137         p=strchr(cursid_svc, '_');
0138         
0139         if (NULL!=p)
0140         {
0141             *p = EXEOS;
0142         }
0143         else
0144         {
0145             NDRX_LOG(log_error, "Invalid TA_CURSOR format [%s]", cursid_svc);
0146 
0147             ndrx_adm_error_set(p_ub, TAEINVAL, TA_CURSOR, 
0148                         "Invalid TA_CURSOR format [%s]", cursid_svc);
0149             EXFAIL_OUT(ret);
0150         }
0151         
0152         if (0!=strcmp(cursid_svc, ndrx_G_svcnm2))
0153         {
0154             NDRX_LOG(log_info, "Not our cursor our [%s] vs [%s] - forward",
0155                     ndrx_G_svcnm2, cursid_svc);
0156             tpforward(cursid_svc, (char *)p_ub, 0, 0L);
0157         }
0158     }
0159     
0160     /* Get request class: 
0161      * In case if we get cursor from other node, then we shall forward there
0162      * the current request.
0163      */
0164     len = sizeof(clazz);
0165     if (EXSUCCEED!=Bget(p_ub, TA_CLASS, 0, clazz, &len))
0166     {
0167         NDRX_LOG(log_error, "Failed to get TA_CLASS: %s", Bstrerror(Berror));
0168         
0169         ndrx_adm_error_set(p_ub, TAEREQUIRED, TA_CLASS, 
0170                 "Failed to get TA_CLASS: %s", Bstrerror(Berror));
0171         
0172         EXFAIL_OUT(ret);
0173     }
0174     
0175     /* TODO: Needs functions for error handling:
0176      * with following arguments:
0177      * TA_ERROR code, TA_BADFLD (optional only for INVAL), TA_STATUS message.
0178      * The function shall receive UBF buffer and allow to process the format
0179      * string which is loaded into TA_STATUS.
0180      * 
0181      * We need a function to check is buffer approved, if so then we can set
0182      * the reject. Reject on reject is not possible (first is more significant).
0183      */
0184 
0185     
0186     /* find class */
0187     class_map = ndrx_adm_class_map_get(clazz);
0188     
0189     if (NULL==class_map)
0190     {
0191         NDRX_LOG(log_error, "Unsupported class [%s]", clazz);
0192 
0193         ndrx_adm_error_set(p_ub, TAESUPPORT, TA_CLASS, 
0194                     "Unsupported class [%s]", clazz);
0195         EXFAIL_OUT(ret);
0196     }
0197         
0198     if (0==strcmp(NDRX_TA_GET, op))
0199     {
0200         is_get = EXTRUE;
0201         memset(&cursnew, 0, sizeof(cursnew));
0202         
0203         /* get cursor data */
0204         NDRX_LOG(log_debug, "About to open cursor [%s]",  clazz);
0205         cursnew.list.maxindexused = EXFAIL;
0206         if (EXSUCCEED!=class_map->p_get(clazz, &cursnew, 0L))
0207         {
0208             NDRX_LOG(log_error, "Failed to open %s cursor", clazz);
0209 
0210             ndrx_adm_error_set(p_ub, TAESYSTEM, BBADFLDID, 
0211                         "Failed to open %s cursor", clazz);
0212             EXFAIL_OUT(ret);
0213         }
0214         
0215         /* Prepare cursor  */
0216         curs = ndrx_adm_curs_new(p_ub, class_map, &cursnew);
0217         
0218         if (NULL==curs)
0219         {
0220             /* ERR ! Failed to open cursor.. */
0221             NDRX_LOG(log_error, "Failed to open cursor for %s", clazz);
0222 
0223             ndrx_adm_error_set(p_ub, TAESYSTEM, BBADFLDID, 
0224                         "Failed to open cursor for %s", clazz);
0225             EXFAIL_OUT(ret);
0226         }
0227         
0228         /* Load cursor id */
0229         
0230         if (EXSUCCEED!=Bchg(p_ub, TA_CURSOR, 0, curs->cursorid, 0L))
0231         {
0232             NDRX_LOG(log_error, "Failed to add cursor name: %s", Bstrerror(Berror));
0233 
0234             ndrx_adm_error_set(p_ub, TAESYSTEM, BBADFLDID, 
0235                         "Failed to add cursor name: %s", Bstrerror(Berror));
0236             EXFAIL_OUT(ret);
0237         }
0238         
0239     }
0240     else if (0==strcmp(NDRX_TA_GETNEXT, op))
0241     {
0242         is_get = EXTRUE;
0243         /* read cursor id */
0244         curs = ndrx_adm_curs_get(cursid);
0245     }
0246     else
0247     {
0248         ndrx_adm_error_set(p_ub, TAESUPPORT, TA_OPERATION, 
0249                     "Unsupported operation [%s]", op);
0250         EXFAIL_OUT(ret);
0251     }
0252     
0253     if (is_get)
0254     {
0255         
0256         if (NULL==curs)
0257         {
0258             /* Load the fields in the buffer */  
0259             goto out_nomore;
0260         }
0261         
0262         /* Fetch cursor to UBF buffer */
0263         if (EXSUCCEED!=ndrx_adm_curs_fetch(p_ub, curs, &ret_occurs, &ret_more))
0264         {
0265             NDRX_LOG(log_error, "Failed to fetch!");
0266             ndrx_adm_error_set(p_ub, TAESYSTEM, BBADFLDID, 
0267                         "Failed to fetch!");
0268         }
0269     }
0270     
0271 out_nomore:
0272     
0273     if (is_get)
0274     {
0275         if (EXSUCCEED!=Bchg(p_ub, TA_OCCURS, 0, (char *)&ret_occurs, 0L))
0276         {
0277             NDRX_LOG(log_error, "Failed to set TA_OCCURS to %ld: %s",
0278                     ret_occurs, Bstrerror(Berror));
0279         }
0280             
0281         if (EXSUCCEED!=Bchg(p_ub, TA_MORE, 0, (char *)&ret_more, 0L))
0282         {
0283             NDRX_LOG(log_error, "Failed to set TA_MORE to %ld: %s",
0284                     ret_more, Bstrerror(Berror));
0285         }
0286         
0287         /* approve the request... */
0288         ndrx_adm_error_set(p_ub, TAOK, BBADFLDID, "OK");
0289     }
0290     
0291 out:
0292     
0293     ndrx_debug_dump_UBF(log_info, "Reply buffer:", p_ub);
0294 
0295     tpreturn(  ret==EXSUCCEED?TPSUCCESS:TPFAIL,
0296                 0,
0297                 (char *)p_ub,
0298                 0L,
0299                 0L);
0300 }
0301 
0302 /**
0303  * Do initialization
0304  * Have a local MIB & shared MIB
0305  */
0306 int NDRX_INTEGRA(tpsvrinit)(int argc, char **argv)
0307 {
0308     int ret=EXSUCCEED;
0309     signed char c;
0310     
0311     memset(&ndrx_G_adm_config, 0, sizeof(ndrx_G_adm_config));
0312     
0313     /* parse clopt: cursor limit and buffer size to alloc... */
0314     
0315     /* Parse command line  */
0316     while ((c = getopt(argc, argv, "n:b:v:s:")) != -1)
0317     {
0318         if (optarg)
0319         {
0320             NDRX_LOG(log_debug, "%c = [%s]", c, optarg);
0321         }
0322         else
0323         {
0324             NDRX_LOG(log_debug, "got %c", c);
0325         }
0326 
0327         switch(c)
0328         {
0329             case 'n':
0330                 /* number of cursors allow */
0331                 ndrx_G_adm_config.cursors_max = atoi(optarg);
0332                 break;
0333             case 'b':
0334                 /* initial buffer size */    
0335                 ndrx_G_adm_config.buffer_minsz = atoi(optarg);
0336                 break;
0337             case 'v':
0338                 /* cursor validity time, seconds */
0339                 ndrx_G_adm_config.validity = atoi(optarg);
0340                 break;
0341             case 's':
0342                 /* scan time for dead cursors */
0343                 ndrx_G_adm_config.scantime = atoi(optarg);
0344                 break;
0345         }
0346     }
0347     
0348     if (ndrx_G_adm_config.buffer_minsz<=0)
0349     {
0350         ndrx_G_adm_config.buffer_minsz = TPADM_DEFAULT_BUFFER_MINSZ;
0351     }
0352     
0353     if (ndrx_G_adm_config.validity<=0)
0354     {
0355         ndrx_G_adm_config.validity = TPADM_DEFAULT_VALIDITY;
0356     }
0357     
0358     if (ndrx_G_adm_config.scantime<=0)
0359     {
0360         ndrx_G_adm_config.scantime = TPADM_DEFAULT_SCANTIME;
0361     }
0362     
0363     if (ndrx_G_adm_config.cursors_max<=0)
0364     {
0365         ndrx_G_adm_config.cursors_max = TPADM_DEFAULT_CURSORS_MAX;
0366     }
0367     
0368     NDRX_LOG(log_info, "Max number of cursors allow: %d", 
0369             ndrx_G_adm_config.cursors_max);
0370     
0371     NDRX_LOG(log_info, "Alloc buffer size for return: %d bytes", 
0372             ndrx_G_adm_config.buffer_minsz);
0373     
0374     NDRX_LOG(log_info, "Cursor validity seconds: %d sec", 
0375             ndrx_G_adm_config.validity);
0376     
0377     NDRX_LOG(log_info, "Cursor housekeep: %d sec", 
0378             ndrx_G_adm_config.scantime);
0379     
0380     snprintf(ndrx_G_svcnm2, sizeof(ndrx_G_svcnm2), NDRX_SVC_TMIBNODESV, 
0381             tpgetnodeid(), tpgetsrvid());
0382     
0383     snprintf(ndrx_G_svcnm_node, sizeof(ndrx_G_svcnm_node), NDRX_SVC_TMIBNODE, 
0384             tpgetnodeid());
0385 
0386     if (EXSUCCEED!=tpadvertise(NDRX_SVC_TMIB, MIB))
0387     {
0388         NDRX_LOG(log_error, "Failed to initialize [%s]!", NDRX_SVC_TMIB);
0389         EXFAIL_OUT(ret);
0390     }
0391     else if (EXSUCCEED!=tpadvertise(ndrx_G_svcnm2, MIB))
0392     {
0393         NDRX_LOG(log_error, "Failed to initialize [%s]!", ndrx_G_svcnm2);
0394         EXFAIL_OUT(ret);
0395     }
0396     else if (EXSUCCEED!=tpadvertise(ndrx_G_svcnm_node, MIB))
0397     {
0398         NDRX_LOG(log_error, "Failed to initialize [%s]!", ndrx_G_svcnm_node);
0399         EXFAIL_OUT(ret);
0400     }
0401     
0402     /* Register timer check.... */
0403     if (EXSUCCEED==ret &&
0404             EXSUCCEED!=tpext_addperiodcb(ndrx_G_adm_config.scantime, 
0405             ndrx_adm_curs_housekeep))
0406     {
0407         
0408         NDRX_LOG(log_error, "tpext_addperiodcb failed: %s",
0409                         tpstrerror(tperrno));
0410         EXFAIL_OUT(ret);
0411     }
0412 
0413 out:
0414     return ret;
0415 }
0416 
0417 void NDRX_INTEGRA(tpsvrdone)(void)
0418 {
0419     /* just for build... */
0420 }
0421 
0422 /* vim: set ts=4 sw=4 et smartindent: */