Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Enduro/X identifiers routines (queue names, client ids, etc...)
0003  *
0004  * @file identifiers.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 <ndrx_config.h>
0035 #include <string.h>
0036 #include <sys/time.h>
0037 #include <stdio.h>
0038 #include <stdlib.h>
0039 #include <memory.h>
0040 #include <sys_mqueue.h>
0041 #include <errno.h>
0042 #include <sys/param.h>
0043 #include <unistd.h>
0044 #include <fcntl.h>
0045 
0046 #include <sys_unix.h>
0047 #include <atmi.h>
0048 #include <ndrstandard.h>
0049 #include <ndebug.h>
0050 #include <atmi_int.h>
0051 #include <ndrxdcmn.h>
0052 #include <utlist.h>
0053 #include <atmi_shm.h>
0054 #include <tperror.h>
0055 
0056 #include "gencall.h"
0057 #include "userlog.h"
0058 #include "exsha1.h"
0059 #include "exbase64.h"
0060 #include <xa_cmn.h>
0061 /*---------------------------Externs------------------------------------*/
0062 /*---------------------------Macros-------------------------------------*/
0063 /*---------------------------Enums--------------------------------------*/
0064 /*---------------------------Typedefs-----------------------------------*/
0065 
0066 /**
0067  * Q type prefix mapping table
0068  */
0069 struct prefixmap
0070 {
0071     char *prefix;
0072     char *offset;
0073     int len;
0074     int type;
0075     char *descr;
0076 };
0077 typedef struct prefixmap prefixmap_t;
0078 
0079 /*---------------------------Globals------------------------------------*/
0080 /*---------------------------Statics------------------------------------*/
0081 
0082 
0083 /**
0084  * Prefix mapping table for detecting Q type
0085  */
0086 expublic prefixmap_t M_prefixmap[] =
0087 {  
0088     /* prefix format string, match off, len, q type classifier */
0089     {NDRX_NDRXD,                NULL, 0, NDRX_QTYPE_NDRXD,      "ndrxd Q"},
0090     {NDRX_SVC_QFMT_PFX,         NULL, 0, NDRX_QTYPE_SVC,        "service Q"},
0091     {NDRX_ADMIN_FMT_PFX,        NULL, 0, NDRX_QTYPE_SRVADM,     "svc admin Q"},
0092     {NDRX_SVR_QREPLY_PFX,       NULL, 0, NDRX_QTYPE_SRVRPLY,    "server rply Q"},
0093     {NDRX_CLT_QREPLY_PFX,       NULL, 0, NDRX_QTYPE_CLTRPLY,    "client rply Q"},
0094     {NDRX_CONV_INITATOR_Q_PFX,  NULL, 0, NDRX_QTYPE_CONVINIT,   "conv initi Q"},
0095     {NDRX_CONV_SRV_Q_PFX,       NULL, 0, NDRX_QTYPE_CONVSRVQ,   "conv server Q"},
0096     {NULL}
0097 };
0098 
0099 /*---------------------------Prototypes---------------------------------*/
0100 
0101 /**
0102  * Parse Q. This will parse only the id, it will ignore the Q prefix
0103  * @param qname full queue named
0104  * @param p_myid parsed ID
0105  * @return SUCCEED/FAIL
0106  */
0107 expublic int ndrx_cvnq_parse_client(char *qname, TPMYID *p_myid)
0108 {
0109     int ret = EXSUCCEED;
0110     char *p;
0111     
0112     /* can be, example:
0113     - /dom2,cnv,c,srv,atmisv35,11,32159,0,2,1
0114     - /dom1,cnv,c,clt,atmiclt35,32218,5,1,1
0115      */
0116     
0117     if (NULL==(p = strchr(qname, NDRX_FMT_SEP)))
0118     {
0119         NDRX_LOG(log_error, "Invalid conversational initiator/client Q (1): [%s]", 
0120                 qname);
0121         EXFAIL_OUT(ret);
0122     }
0123     p++;
0124     
0125     if (0!=strncmp(p, "cnv"NDRX_FMT_SEP_STR, 4))
0126     {
0127         NDRX_LOG(log_error, "Invalid conversational initiator/client Q (2): [%s]", 
0128                 qname);
0129         EXFAIL_OUT(ret);
0130     }
0131     p+=4;
0132     
0133     if (0!=strncmp(p, "c"NDRX_FMT_SEP_STR, 2))
0134     {
0135         NDRX_LOG(log_error, "Invalid conversational initiator/client Q (3): [%s]", 
0136                 qname);
0137         EXFAIL_OUT(ret);
0138     }
0139     p+=2;
0140     
0141     ret = ndrx_myid_parse(p, p_myid, EXTRUE);
0142     
0143     
0144 out:
0145     
0146     return ret;
0147 }
0148 
0149 /**
0150  * Step forward number of separators
0151  * @param qname
0152  * @param num
0153  * @return 
0154  */
0155 exprivate char * move_forward(char *qname, int num)
0156 {
0157     char *p = qname;
0158     int i;
0159     
0160     for (i=0; i<num; i++)
0161     {
0162         if (NULL==(p=strchr(p, NDRX_FMT_SEP)))
0163         {
0164             NDRX_LOG(log_error, "Search for %d %c seps in [%s], step %d- fail",
0165                     num, NDRX_FMT_SEP, qname, i);
0166             goto out;
0167         }
0168         p++;
0169     }
0170     
0171 out:
0172     return p;
0173        
0174 }
0175 /**
0176  * Parse conversational server Q. Which is compiled of two initiator and acceptor:
0177  * e.g. 
0178  * - /dom2,cnv,s,srv,atmisv35,13,32163,0,2,1,srv,atmisv35,14,32165,0,2
0179  * - /dom2,cnv,s,clt,atmiclt35,32218,2,1,1,srv,atmisv35,11,32159,0,2
0180  * @param qname
0181  * @param p_myid_first
0182  * @param p_myid_second
0183  * @return 
0184  */
0185 expublic int ndrx_cvnq_parse_server(char *qname, TPMYID *p_myid_first,  TPMYID *p_myid_second)
0186 {
0187     int ret = EXSUCCEED;
0188     char tmpq[NDRX_MAX_Q_SIZE+1];
0189     char *p;
0190     char *p2;
0191     /* we might want to get specs about count of separator commas 
0192      * symbols in each of the ids. Thus we could step forward for compiled
0193      * Q identifiers.
0194      */
0195     
0196     NDRX_STRCPY_SAFE(tmpq, qname);
0197     
0198     /* /dom2,cnv,s,clt,atmiclt35,32218,2,1,1,srv,atmisv35,11,32159,0,2 */
0199     
0200     if (NULL==(p = strchr(tmpq, NDRX_FMT_SEP)))
0201     {
0202         NDRX_LOG(log_error, "Invalid conversational server Q (1): [%s]", 
0203                 qname);
0204         EXFAIL_OUT(ret);
0205     }
0206     p++;
0207     
0208     if (0!=strncmp(p, "cnv"NDRX_FMT_SEP_STR, 4))
0209     {
0210         NDRX_LOG(log_error, "Invalid conversational server Q (2): [%s]", 
0211                 qname);
0212         EXFAIL_OUT(ret);
0213     }
0214     p+=4;
0215     
0216     if (0!=strncmp(p, "s"NDRX_FMT_SEP_STR, 2))
0217     {
0218         NDRX_LOG(log_error, "Invalid conversational server Q (3): [%s]", 
0219                 qname);
0220         EXFAIL_OUT(ret);
0221     }
0222     p+=2;
0223     
0224     if (0==strncmp(p, "srv"NDRX_FMT_SEP_STR, 4))
0225     {
0226         /* +1 because we want to get till the end of the our component */
0227         if (NULL==(p2=move_forward(p, NDRX_MY_ID_SRV_CNV_NRSEPS+1)))
0228         {
0229             NDRX_LOG(log_error, "Failed to decode server myid seps count: [%s]",
0230                    p);
0231         }
0232         p2--;
0233         *p2 = EXEOS;
0234         p2++;
0235         
0236         if (strlen(p2)==0)
0237         {
0238             NDRX_LOG(log_error, "Invalid server queue");
0239             EXFAIL_OUT(ret);
0240         }
0241     }
0242     else if (0==strncmp(p, "clt"NDRX_FMT_SEP_STR, 4))
0243     {
0244         /* +1 because we want to get till the end of the our component */
0245         if (NULL==(p2=move_forward(p, NDRX_MY_ID_CLT_CNV_NRSEPS+1)))
0246         {
0247             NDRX_LOG(log_error, "Failed to decode client myid seps count: [%s]",
0248                    p);
0249         }
0250         p2--;
0251         *p2 = EXEOS;
0252         p2++;
0253         
0254         if (strlen(p2)==0)
0255         {
0256             NDRX_LOG(log_error, "Invalid client queue of server q [%s]", qname);
0257             EXFAIL_OUT(ret);
0258         }
0259     }
0260     else
0261     {
0262         NDRX_LOG(log_error, "Cannot detect myid type of conversational Q: "
0263                 "[%s]", qname);
0264         EXFAIL_OUT(ret);
0265     }
0266     
0267     NDRX_LOG(log_debug, "Parsing Q: [%s] first part: [%s] "
0268             "second part: [%s]",qname, p, p2);
0269     if (EXSUCCEED!=ndrx_myid_parse(p, p_myid_first, EXTRUE) || 
0270             EXSUCCEED!=ndrx_myid_parse(p2, p_myid_second, EXFALSE))
0271     {
0272         NDRX_LOG(log_error, "Failed to parse Q: [%s] first part: [%s] "
0273             "second part: [%s]",qname, p, p2);
0274         EXFAIL_OUT(ret);
0275     }
0276     
0277 out:
0278     NDRX_LOG(log_debug, "ndrx_parse_cnv_srv_q returns with %d", ret);
0279     return ret;
0280 }
0281 
0282 /**
0283  * Prase myid (it will detect client or server)
0284  * @param my_id myid string
0285  * @param out parsed myid
0286  * @return SUCCEED/FAIL
0287  */
0288 expublic int ndrx_myid_parse(char *my_id, TPMYID *out, int iscnv_initator)
0289 {
0290     int ret = EXSUCCEED;
0291     
0292     if (0==strncmp(my_id, "srv"NDRX_FMT_SEP_STR, 4))
0293     {
0294         NDRX_LOG(log_debug, "Parsing server myid: [%s]", my_id);
0295         return ndrx_myid_parse_srv(my_id, out, iscnv_initator);
0296     }
0297     else if (0==strncmp(my_id, "clt"NDRX_FMT_SEP_STR, 4))
0298     {
0299         NDRX_LOG(log_debug, "Parsing client myid: [%s]", my_id);
0300         return ndrx_myid_parse_clt(my_id, out, iscnv_initator);
0301     }
0302     else
0303     {
0304         NDRX_LOG(log_error, "Cannot detect myid type: [%s]", my_id);
0305         ret=EXFAIL;
0306     }
0307     
0308     return ret;
0309 }
0310 
0311 
0312 /**
0313  * Parse client id
0314  * @param my_id client id string
0315  * @param out client id out struct
0316  * @return SUCCEED
0317  */
0318 expublic int ndrx_myid_parse_clt(char *my_id, TPMYID *out, int iscnv_initator)
0319 {
0320     int ret = EXSUCCEED;
0321     int len;
0322     int i;
0323     char tmp[NDRX_MAX_Q_SIZE+1];
0324     
0325     NDRX_STRCPY_SAFE(tmp, my_id);
0326     len = strlen(tmp);
0327     for (i=0; i<len; i++)
0328     {
0329         if (NDRX_FMT_SEP==tmp[i])
0330             tmp[i]=' ';
0331     }
0332     
0333     NDRX_LOG(log_debug, "Parsing: [%s]", tmp);
0334     if (iscnv_initator)
0335     {
0336         sscanf(tmp, NDRX_MY_ID_CLT_CNV_PARSE, 
0337                 out->binary_name
0338                 ,&(out->pid)
0339                 ,&(out->contextid)
0340                 ,&(out->nodeid)
0341                 ,&(out->cd));
0342         out->isconv = EXTRUE;
0343     }
0344     else 
0345     {
0346 
0347         sscanf(tmp, NDRX_MY_ID_CLT_PARSE, 
0348                 out->binary_name
0349                 ,&(out->pid)
0350                 ,&(out->contextid)
0351                 ,&(out->nodeid));
0352         out->isconv = EXFALSE;
0353     }
0354 
0355     out->tpmyidtyp = TPMYIDTYP_CLIENT;
0356     
0357     ndrx_myid_dump(log_debug, out, "Parsed myid");
0358     
0359     return ret;
0360 }
0361 
0362 /**
0363  * Parse myid of the server process
0364  * @param my_id myid/NDRX_MY_ID_SRV formatted id
0365  * @param out filled structure of the parse id
0366  * @return SUCCEED
0367  */
0368 expublic int ndrx_myid_parse_srv(char *my_id, TPMYID *out, int iscnv_initator)
0369 {
0370     int ret = EXSUCCEED;
0371     int len;
0372     int i;
0373     char tmp[NDRX_MAX_Q_SIZE+1];
0374     
0375     NDRX_STRCPY_SAFE(tmp, my_id);
0376     len = strlen(tmp);
0377     for (i=0; i<len; i++)
0378     {
0379         if (NDRX_FMT_SEP==tmp[i])
0380             tmp[i]=' ';
0381     }
0382     
0383     NDRX_LOG(log_debug, "Parsing: [%s]", tmp);
0384     if (iscnv_initator)
0385     {
0386         sscanf(tmp, NDRX_MY_ID_SRV_CNV_PARSE, 
0387                 out->binary_name
0388                 ,&(out->srv_id)
0389                 ,&(out->pid)
0390                 ,&(out->contextid)
0391                 ,&(out->nodeid)
0392                 ,&(out->cd));
0393         out->isconv = EXTRUE;
0394     }
0395     else
0396     {
0397         sscanf(tmp, NDRX_MY_ID_SRV_PARSE, 
0398                 out->binary_name
0399                 ,&(out->srv_id)
0400                 ,&(out->pid)
0401                 ,&(out->contextid)
0402                 ,&(out->nodeid));
0403         out->isconv = EXFALSE;
0404     }
0405     
0406     out->tpmyidtyp = TPMYIDTYP_SERVER;
0407     
0408     ndrx_myid_dump(log_debug, out, "Parsed myid output");
0409     
0410     return ret;
0411 }
0412 
0413 /**
0414  * Check is process a live
0415  * @param 
0416  * @return FAIL (not our node)/TRUE (live)/FALSE (dead)
0417  */
0418 expublic int ndrx_myid_is_alive(TPMYID *p_myid)
0419 {
0420     /* Bug #291 2018/03/25 */
0421     if (p_myid->nodeid==G_atmi_env.our_nodeid)
0422     {
0423         /* cltname same pos as server proc name */
0424         return ndrx_sys_is_process_running(p_myid->pid, p_myid->binary_name);
0425     }
0426     else
0427     {
0428         return EXFAIL;
0429     }
0430 }
0431 
0432 /**
0433  * Dump the MYID struct to the log
0434  * @param p_myid ptr to myid
0435  * @param lev debug level to print of
0436  */
0437 expublic void ndrx_myid_dump(int lev, TPMYID *p_myid, char *msg)
0438 {
0439     
0440     NDRX_LOG(lev, "--- %s ---", msg);
0441     
0442     NDRX_LOG(lev, "binary_name:[%s]", p_myid->binary_name);
0443     NDRX_LOG(lev, "pid        :%d", p_myid->pid);
0444     NDRX_LOG(lev, "contextid  :%ld", p_myid->contextid);
0445     NDRX_LOG(lev, "nodeid     :%d", p_myid->nodeid);
0446     NDRX_LOG(lev, "typ        :%s (%d)", 
0447             p_myid->tpmyidtyp==TPMYIDTYP_SERVER?"server":"client", 
0448             p_myid->tpmyidtyp);
0449     
0450     if (p_myid->tpmyidtyp==TPMYIDTYP_SERVER)
0451     {
0452         NDRX_LOG(lev, "srv_id     :%d", p_myid->srv_id);
0453     }
0454     NDRX_LOG(lev, "cnv initia :%s", p_myid->isconv?"TRUE":"FALSE");
0455     
0456     if (p_myid->isconv)
0457     {
0458         NDRX_LOG(lev, "cd         :%d", p_myid->cd);
0459     }
0460     NDRX_LOG(lev, "-----------------");
0461             
0462 }
0463 
0464 /**
0465  * Translate the given my_id to reply q
0466  * This should work for servers and clients.
0467  * The rply Q is built locally...
0468  * 
0469  * @param my_id String version of my_id
0470  * @param rply_q String version (full version with pfx) of the reply Q
0471  */
0472 expublic int ndrx_myid_convert_to_q(TPMYID *p_myid, char *rply_q, int rply_q_buflen)
0473 {
0474     int ret = EXSUCCEED;
0475     
0476     /* Now build the reply Qs */
0477     if (TPMYIDTYP_SERVER==p_myid->tpmyidtyp)
0478     {
0479         /* build server q */
0480         /*#define NDRX_SVR_QREPLY   "%s,srv,reply,%s,%d,%d"  qpfx, procname, serverid, pid */
0481         snprintf(rply_q, rply_q_buflen, NDRX_SVR_QREPLY, G_atmi_env.qprefix, 
0482                 p_myid->binary_name, p_myid->srv_id, p_myid->pid);
0483         
0484     }
0485     else
0486     {
0487         /* build client q */
0488         /*#define NDRX_CLT_QREPLY   "%s,clt,reply,%s,%d,%ld"  pfx, name, pid, context id*/
0489         snprintf(rply_q, rply_q_buflen, NDRX_CLT_QREPLY, G_atmi_env.qprefix, 
0490                 p_myid->binary_name, p_myid->pid, p_myid->contextid);
0491     }
0492     
0493     NDRX_LOG(log_info, "Translated into [%s] reply q", rply_q);
0494     
0495 out:
0496     return ret;
0497 }
0498 
0499 
0500 /**
0501  * Dump the MYID struct to the log
0502  * @param p_myid ptr to myid
0503  * @param lev debug level to print of
0504  */
0505 expublic void ndrx_qdet_dump(int lev, ndrx_qdet_t *qdet, char *msg)
0506 {
0507     
0508     NDRX_LOG(lev, "--- %s ---", msg);
0509     /* I */
0510     NDRX_LOG(lev, "binary_name:[%s]", qdet->binary_name);
0511     NDRX_LOG(lev, "pid        :%d", qdet->pid);
0512     NDRX_LOG(lev, "contextid  :%ld", qdet->contextid);
0513     NDRX_LOG(lev, "typ        :%d",  qdet->qtype);
0514     
0515     NDRX_LOG(lev, "-----------------");
0516             
0517 }
0518 
0519 /**
0520  * Parse client qstr 
0521  * @param qdet queue details where to store
0522  * @param qstr Queue string to parse
0523  * @return SUCCEED
0524  */
0525 expublic int ndrx_qdet_parse_cltqstr(ndrx_qdet_t *qdet, char *qstr)
0526 {   
0527     int ret = EXSUCCEED;
0528     int len;
0529     int i;
0530     char tmp[NDRX_MAX_Q_SIZE+1];
0531     
0532     NDRX_STRCPY_SAFE(tmp, qstr);
0533     len = strlen(tmp);
0534     for (i=0; i<len; i++)
0535     {
0536         if (NDRX_FMT_SEP==tmp[i])
0537             tmp[i]=' ';
0538     }
0539     
0540     NDRX_LOG(log_debug, "Parsing: [%s]", tmp);
0541     
0542     sscanf(tmp, NDRX_CLT_QREPLY_PARSE, 
0543             qdet->qprefix,
0544             qdet->binary_name
0545             ,&(qdet->pid)
0546             ,&(qdet->contextid));
0547 
0548     
0549     qdet->qtype = NDRX_QTYPE_CLTRPLY;
0550     
0551     ndrx_qdet_dump(log_debug, qdet, "Parsed qdet client output");
0552     
0553 out:
0554     return ret;
0555 }
0556 /**
0557  * Build myid from reply q. 
0558  * @param p_myid
0559  * @param rply_q
0560  * @param nodeid - Cluster node id, as q does not encode cluster id
0561  * @return SUCCEED/FAIL
0562  */
0563 expublic int ndrx_myid_convert_from_qdet(TPMYID *p_myid, ndrx_qdet_t *qdet, long nodeid)
0564 {
0565     int ret = EXSUCCEED;
0566     
0567     if (NDRX_QTYPE_CLTRPLY==qdet->qtype)
0568     {
0569         NDRX_STRCPY_SAFE(p_myid->binary_name, qdet->binary_name);
0570         p_myid->contextid = qdet->contextid;
0571         p_myid->pid = qdet->pid;
0572         p_myid->nodeid = nodeid;
0573     }
0574     else
0575     {
0576         NDRX_LOG(log_error, "%s: Unsupported qtype for building myid: %d", 
0577                 __func__, qdet->qtype);
0578         EXFAIL_OUT(ret);
0579     }
0580     
0581 out:
0582     return ret;
0583 }
0584 
0585 /**
0586  * Convert TPMYID to string
0587  * @param p_myid
0588  * @param my_id
0589  * @return SUCCEED
0590  */
0591 expublic void ndrx_myid_to_my_id_str(TPMYID *p_myid, char *my_id)
0592 {
0593     snprintf(my_id, NDRX_MAX_ID_SIZE+1, NDRX_MY_ID_CLT, 
0594         p_myid->binary_name,
0595         p_myid->pid,
0596         p_myid->contextid,
0597         p_myid->nodeid
0598     );
0599     
0600     NDRX_LOG(log_debug, "%s: built my_id: [%s]", __func__, my_id);
0601 }
0602 
0603 /**
0604  * Initialize ATMI util lib.
0605  * Setup the queue testing strings for local host
0606  * @return SUCCEED/FAIL
0607  */
0608 expublic int ndrx_atmiutil_init(void)
0609 {
0610     int ret = EXSUCCEED;
0611     prefixmap_t *p = M_prefixmap;
0612     
0613     while (NULL!=p->prefix)
0614     {
0615         p->offset = strchr(p->prefix, NDRX_FMT_SEP);
0616         
0617         if (NULL==p->offset)
0618         {
0619             NDRX_LOG(log_error, "%s failed to search for [%c] in [%s]", __func__, 
0620                     NDRX_FMT_SEP, p->prefix);
0621             EXFAIL_OUT(ret);
0622         }
0623         
0624         /* calculate match length for the Q */
0625         p->len = strlen(p->offset);
0626         
0627         p++;
0628     }
0629     
0630 out:
0631     return ret;
0632 }
0633 
0634 /**
0635  * Return queue type classifier
0636  * @param q full queue (with prefix)
0637  * @return see NDRX_QTYPE_* or FAIL
0638  */
0639 expublic int ndrx_q_type_get(char *q)
0640 {
0641     int ret = EXFAIL;
0642     prefixmap_t *p = M_prefixmap;
0643     char *q_wo_pfx = strchr(q, NDRX_FMT_SEP);
0644     
0645     if (NULL==q_wo_pfx)
0646     {
0647         NDRX_LOG(log_error, "Invalid Enduro/X Q (possible not Enduro/X): [%s]", 
0648                 q_wo_pfx);
0649         EXFAIL_OUT(ret);
0650     }
0651     
0652     while (NULL!=p->prefix)
0653     {
0654         if (0==strncmp(p->offset, q_wo_pfx, p->len))
0655         {
0656             /* matched */
0657             break;
0658         }
0659         
0660         p++;
0661     }
0662     
0663     if (NULL!=p->prefix)
0664     {
0665         ret = p->type;
0666         NDRX_LOG(log_debug, "[%s] matched type [%d/%s]", q, ret, p->descr);
0667     }
0668     
0669 out:
0670     return ret;
0671 }
0672 
0673 /**
0674  * Internal version of tpconvert()
0675  * @param str in/out string format, the buffer size should be at least 
0676  * @param bin binary data
0677  * @param flags flags (see API descr)
0678  * @return EXSUCCEED/EXFAIL
0679  */
0680 expublic int ndrx_tpconvert(char *str, char *bin, long flags)
0681 {
0682     int ret = EXSUCCEED;
0683     CLIENTID *cltid;
0684     size_t out_len = 0;
0685     
0686     if (flags & TPTOSTRING)
0687     {
0688         out_len = TPCONVMAXSTR;
0689         NDRX_LOG(log_debug, "%s: convert to string: %"PRIx64, __func__, flags);
0690         
0691         if (flags & TPCONVCLTID)
0692         {
0693             /* client id is already string... */
0694             cltid = (CLIENTID *)bin;
0695             NDRX_STRCPY_SAFE_DST(str, cltid->clientdata, TPCONVMAXSTR);
0696         }
0697         else if (flags & TPCONVTRANID)
0698         {
0699             /* maybe needs to think about cross platform way?
0700              * but currently do not see reason for this
0701              */
0702             ndrx_xa_base64_encode((unsigned char *)bin, sizeof(TPTRANID), &out_len, str);
0703             /* str[out_len] = EXEOS; */
0704         }
0705         else if (flags & TPCONVXID)
0706         {
0707             atmi_xa_serialize_xid((XID *)bin, str);
0708         }
0709         else
0710         {
0711             ndrx_TPset_error_fmt(TPEINVAL, "Invalid convert flags: %"PRIx64, 
0712                     __func__, flags);
0713             EXFAIL_OUT(ret);
0714         }
0715     }
0716     else
0717     {
0718         NDRX_LOG(log_debug, "%s: convert to bin: %"PRIx64, __func__, flags);
0719         
0720         if (flags & TPCONVCLTID)
0721         {
0722             /* client id is already string... */
0723             cltid = (CLIENTID *)bin;
0724             NDRX_STRCPY_SAFE(cltid->clientdata, str);
0725         }
0726         else if (flags & TPCONVTRANID)
0727         {
0728             /* Decode binary data: */
0729             out_len = sizeof(TPTRANID);
0730             if (NULL==(ndrx_xa_base64_decode((unsigned char *)str, strlen(str), &out_len, bin)))
0731             {
0732                 ndrx_TPset_error_msg(TPEINVAL, "Failed to decode string, possible "
0733                         "bad base64 coding.");
0734                 EXFAIL_OUT(ret);
0735             }
0736         }
0737         else if (flags & TPCONVXID)
0738         {
0739             /* Deserialize xid. */
0740             atmi_xa_deserialize_xid((unsigned char *)str, (XID *)bin);
0741         }
0742         else
0743         {
0744             ndrx_TPset_error_fmt(TPEINVAL, "Invalid convert flags: %"PRIx64, flags);
0745             EXFAIL_OUT(ret);
0746         }
0747     }
0748     
0749 out:
0750     NDRX_LOG(log_debug, "%s returns %d", __func__, ret);
0751 
0752     return ret;
0753 }
0754 
0755 /* vim: set ts=4 sw=4 et smartindent: */