Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief ATMI lib part for XA api - utils
0003  *
0004  * @file xautils.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 <stdint.h>
0037 #include <stdlib.h>
0038 #include <memory.h>
0039 #include <errno.h>
0040 #include <dlfcn.h>
0041 
0042 #include <atmi.h>
0043 #include <atmi_shm.h>
0044 #include <atmi_int.h>
0045 #include <ndrstandard.h>
0046 #include <ndebug.h>
0047 #include <ndrxdcmn.h>
0048 #include <userlog.h>
0049 
0050 /* shm_* stuff, and mmap() */
0051 #include <sys/mman.h>
0052 #include <sys/types.h>
0053 /* exit() etc */
0054 #include <unistd.h>
0055 #include <fcntl.h>
0056 #include <sys/stat.h>
0057 #include <sys/ipc.h>
0058 #include <xa_cmn.h>
0059 
0060 #include <tperror.h>
0061 #include <Exfields.h>
0062 
0063 #include <xa_cmn.h>
0064 #include <atmi_tls.h>
0065 #include <ubfutil.h>
0066 #include <exbase64.h>
0067 /*---------------------------Externs------------------------------------*/
0068 /*---------------------------Macros-------------------------------------*/
0069 #define     TM_CALL_FB_SZ           1024        /* default size for TM call */
0070 
0071 
0072 #define _XAUTILS_DEBUG
0073 
0074 /*---------------------------Enums--------------------------------------*/
0075 /*---------------------------Typedefs-----------------------------------*/
0076 /*---------------------------Globals------------------------------------*/
0077 /*---------------------------Statics------------------------------------*/
0078 
0079 /*************************** XID manipulation *********************************/
0080 
0081 /**
0082  * Extract info from xid.
0083  * @param[in] xid binary xid
0084  * @param[out] p_nodeid cluster node id on which tran started
0085  * @param[out] p_srvid server which started xid
0086  * @param[out] p_rmid_start resource manager id which started tran
0087  * @param[out] p_rmid_cur current database RM ID
0088  * @param[out] p_btid current branch id
0089  */
0090 expublic void atmi_xa_xid_get_info(XID *xid, short *p_nodeid, 
0091         short *p_srvid, unsigned char *p_rmid_start, 
0092         unsigned char *p_rmid_cur, long *p_btid)
0093 {
0094     
0095     memcpy((char *)p_rmid_start, xid->data + NDRX_XID_TRID_LEN, sizeof(unsigned char));
0096 
0097     memcpy((char *)(p_nodeid), xid->data+NDRX_XID_TRID_LEN+sizeof(unsigned char)
0098             ,sizeof(short));
0099     
0100     memcpy((char *)(p_srvid), xid->data+NDRX_XID_TRID_LEN+sizeof(unsigned char)
0101             +sizeof(short)
0102             ,sizeof(short));
0103     
0104     memcpy(p_rmid_cur, xid->data + xid->gtrid_length - 
0105             sizeof(long) - sizeof(char), sizeof(unsigned char));
0106         
0107 /*
0108     memcpy(p_btid, xid->data + xid->gtrid_length - 
0109             sizeof(long), sizeof(long));
0110 */
0111     /* use btid from branch anyway... */
0112     memcpy(p_btid, xid->data + 
0113             xid->gtrid_length +
0114             G_atmi_tls->xid.gtrid_length - 
0115             sizeof(long), sizeof(long));
0116     
0117     *p_nodeid = (short) ntohs(*p_nodeid);
0118     *p_srvid = (short) ntohs(*p_srvid);
0119     *p_btid = (long)ntohll(*p_btid);
0120     
0121     NDRX_LOG(log_debug, "%hd/%hd/%hd/%ld",
0122             (short)*p_rmid_start, *p_srvid, (short)*p_rmid_cur, *p_btid);
0123     
0124 }
0125 
0126 
0127 /**
0128  * Return XID info for XID string
0129  * @param[in] xid_str
0130  * @param[out] p_nodeid cluster node id on which tran started
0131  * @param[out] p_srvid server which started xid
0132  * @param[out] p_rmid_start resource manager id which started tran
0133  * @param[out] p_rmid_cur current database RM ID
0134  * @param[out] p_btid current branch id
0135  */
0136 expublic void atmi_xa_xid_str_get_info(char *xid_str, short *p_nodeid, 
0137         short *p_srvid, unsigned char *p_rmid_start, 
0138         unsigned char *p_rmid_cur, long *p_btid)
0139 {
0140     XID xid;
0141     memset(&xid, 0, sizeof(xid));
0142     atmi_xa_xid_get_info(atmi_xa_deserialize_xid((unsigned char *)xid_str, &xid), 
0143         p_nodeid, p_srvid, p_rmid_start, p_rmid_cur, p_btid);
0144 }
0145 
0146 /**
0147  * Get `char *' representation of XID.
0148  * @param xid
0149  * @param xid_str_out
0150  */
0151 expublic char * atmi_xa_serialize_xid(XID *xid, char *xid_str_out)
0152 {
0153     int ret=EXSUCCEED;
0154     unsigned char tmp[XIDDATASIZE+64];
0155     int tot_len;
0156     size_t out_len = 0;
0157     /* we should serialize stuff in platform independent format... */
0158     
0159     NDRX_LOG(log_debug, "atmi_xa_serialize_xid - enter");
0160     /* serialize format id: */
0161     tmp[0] = (unsigned char)((xid->formatID >> 24) & 0xff);
0162     tmp[1] = (unsigned char)((xid->formatID >> 16) & 0xff);
0163     tmp[2] = (unsigned char)((xid->formatID >> 8) & 0xff);
0164     tmp[3] = (unsigned char)(xid->formatID & 0xff);
0165     tot_len=4;
0166     
0167     /* serialize gtrid_length */
0168     tmp[4] = (unsigned char)xid->gtrid_length;
0169     tot_len+=1;
0170     
0171     /* serialize bqual_length */
0172     tmp[5] = (unsigned char)xid->bqual_length;
0173     tot_len+=1;
0174     
0175     /* copy off the data portions: TODO - is data in uid endianness agnostic? */
0176     memcpy(tmp+6, xid->data, NDRX_XID_TRID_LEN);
0177     tot_len+=NDRX_XID_TRID_LEN;
0178     
0179     memcpy(tmp+6+NDRX_XID_TRID_LEN, xid->data+NDRX_XID_TRID_LEN, NDRX_XID_BQUAL_LEN);
0180     tot_len+=NDRX_XID_BQUAL_LEN;
0181     
0182     NDRX_DUMP(log_debug, "Original XID", xid, sizeof(*xid));
0183     
0184     NDRX_LOG(log_debug, "xid serialization total len: %d", tot_len);    
0185     NDRX_DUMP(log_debug, "XID data for serialization", tmp, tot_len);
0186     
0187     ndrx_xa_base64_encode(tmp, tot_len, &out_len, xid_str_out);
0188     /* xid_str_out[out_len] = EXEOS; */
0189     
0190     NDRX_LOG(log_debug, "Serialized xid: [%s]", xid_str_out);    
0191     
0192     return xid_str_out;
0193     
0194 }
0195 
0196 /**
0197  * Deserialize - make system XID
0198  * @param xid_str serialized xid, by atmi_xa_serialize_xid
0199  * @param xid_out place where to unload the xid.
0200  * @return NULL in case of error
0201  */
0202 expublic XID* atmi_xa_deserialize_xid(unsigned char *xid_str, XID *xid_out)
0203 {
0204     unsigned char tmp[XIDDATASIZE+64];
0205     size_t tot_len = 0;
0206     long l;
0207     
0208     NDRX_LOG(log_debug, "atmi_xa_deserialize_xid enter (xid_str): [%s]", xid_str);
0209     
0210     if (NULL==ndrx_xa_base64_decode(xid_str, strlen((char *)xid_str), &tot_len, (char *)tmp))
0211     {
0212         NDRX_LOG(log_error, "Failed to b64 decode: [%s]", xid_str);
0213         goto out;
0214     }
0215     
0216     NDRX_LOG(log_debug, "xid deserialization total len: %d", tot_len);
0217     NDRX_DUMP(log_debug, "XID data for deserialization", tmp, tot_len);
0218     
0219     memset(xid_out, 0, sizeof(*xid_out));
0220     
0221     /* build the format id: */
0222     l = tmp[0];
0223     l <<=24;
0224     xid_out->formatID |= l;
0225     
0226     l = tmp[1];
0227     l <<=16;
0228     xid_out->formatID |= l;
0229     
0230     l = tmp[2];
0231     l <<=8;
0232     xid_out->formatID |= l;
0233     
0234     l = tmp[3];
0235     xid_out->formatID |= l;
0236     
0237     /* restore gtrid_length */
0238     
0239     xid_out->gtrid_length = tmp[4];
0240     
0241     /* restore bqual_length */
0242     xid_out->bqual_length = tmp[5];
0243     
0244     /* restore the id */
0245     memcpy(xid_out->data, tmp+6, NDRX_XID_TRID_LEN+NDRX_XID_BQUAL_LEN);
0246     memcpy(xid_out->data+MAXGTRIDSIZE, tmp+6, NDRX_XID_TRID_LEN+NDRX_XID_BQUAL_LEN);
0247  
0248     NDRX_DUMP(log_debug, "Original XID restored ", xid_out, sizeof(*xid_out));
0249 out:
0250     return xid_out;
0251        
0252 }
0253 
0254 /***************** Manipulation functions of current transaction **************/
0255 
0256 /**
0257  * Return transaction from hash table 
0258  * @param tmxid - xid in string format
0259  * @return ptr or NULL
0260  */
0261 expublic atmi_xa_tx_info_t * atmi_xa_curtx_get(char *tmxid)
0262 {
0263     atmi_xa_tx_info_t *ret = NULL;
0264     ATMI_TLS_ENTRY;
0265     
0266     EXHASH_FIND_STR( G_atmi_tls->G_atmi_xa_curtx.tx_tab, tmxid, ret);    
0267     return ret;
0268 }
0269 
0270 /**
0271  * Add new current transaction to the hash list.
0272  * This does not register known list...
0273  * @param tmxid
0274  * @param tmrmid
0275  * @param tmnodeid
0276  * @param tmsrvid
0277  * @param[in] btid branch tid
0278  * @param[in] tmtxflags transaction flags
0279  * @return ptr to entry or NULL
0280  */
0281 expublic atmi_xa_tx_info_t * atmi_xa_curtx_add(char *tmxid,
0282         short tmrmid, short tmnodeid, short tmsrvid, char *tmknownrms, long btid,
0283         short tmtxflags)
0284 {
0285     atmi_xa_tx_info_t * tmp = NDRX_CALLOC(1, sizeof(atmi_xa_tx_info_t));
0286     ATMI_TLS_ENTRY;
0287     
0288     if (NULL==tmp)
0289     {
0290         userlog("malloc failed: %s", strerror(errno));
0291         goto out;
0292     }
0293     
0294     NDRX_STRCPY_SAFE(tmp->tmxid, tmxid);
0295     tmp->tmrmid = tmrmid;
0296     tmp->tmnodeid = tmnodeid;
0297     tmp->tmsrvid = tmsrvid;
0298     tmp->btid = btid;
0299     tmp->tmtxflags = tmtxflags;
0300     NDRX_STRCPY_SAFE(tmp->tmknownrms, tmknownrms);
0301     
0302     EXHASH_ADD_STR( G_atmi_tls->G_atmi_xa_curtx.tx_tab, tmxid, tmp );
0303     
0304 out:
0305     return tmp;
0306 }
0307 
0308 /**
0309  * Remove transaction from list of transaction in progress
0310  * @param p_txinfo
0311  */
0312 expublic void atmi_xa_curtx_del(atmi_xa_tx_info_t *p_txinfo)
0313 {
0314     ATMI_TLS_ENTRY;
0315     
0316     EXHASH_DEL( G_atmi_tls->G_atmi_xa_curtx.tx_tab, p_txinfo);
0317     /* Remove any cds involved... */
0318     /* TODO: Think about cd invalidating... */
0319     atmi_xa_cd_unregall(&(p_txinfo->call_cds));
0320     atmi_xa_cd_unregall(&(p_txinfo->conv_cds));
0321     
0322     NDRX_FREE((void *)p_txinfo);
0323     
0324     return;
0325 }
0326 
0327 /*************************** Transaction info manipulation ********************/
0328 
0329 /**
0330  * Load into UBF buffer info about new transaction created.
0331  * WARNING ! THIS DOES NOT SET TMTXBTID!
0332  * @param p_ub
0333  * @param[out] p_xai global incl local btid transaction descriptor
0334  * @return EXSUCCEED/EXFAIL
0335  */
0336 expublic int atmi_xa_load_tx_info(UBFH *p_ub, atmi_xa_tx_info_t *p_xai)
0337 {
0338     int ret = EXSUCCEED;
0339     char test[100] = {EXEOS};
0340     if (EXSUCCEED!=Bchg(p_ub, TMXID, 0, p_xai->tmxid, 0L) ||
0341             EXSUCCEED!=Bchg(p_ub, TMRMID, 0, (char *)&p_xai->tmrmid, 0L) ||
0342             EXSUCCEED!=Bchg(p_ub, TMNODEID, 0, (char *)&p_xai->tmnodeid, 0L) ||
0343             EXSUCCEED!=Bchg(p_ub, TMSRVID, 0, (char *)&p_xai->tmsrvid, 0L) ||
0344             EXSUCCEED!=Bchg(p_ub, TMKNOWNRMS, 0, (char *)p_xai->tmknownrms, 0L)
0345             )
0346     {
0347         NDRX_LOG(log_error, "Failed to setup TMXID/TMRMID/TMNODEID/"
0348                 "TMSRVID/TMKNOWNRMS! - %s", Bstrerror(Berror));
0349         EXFAIL_OUT(ret);
0350     }
0351     
0352     Bget(p_ub, TMKNOWNRMS, 0, test, 0L);
0353     
0354 out:
0355     return ret;
0356 }
0357 
0358 /**
0359  * Read transaction info received from TM
0360  * @param p_ub
0361  * @param p_xai
0362  * @param[in] flags see atmi_xa_read_tx_info_flags group
0363  * @return 
0364  */
0365 expublic int atmi_xa_read_tx_info(UBFH *p_ub, atmi_xa_tx_info_t *p_xai,
0366                     int flags)
0367 {
0368     int ret = EXSUCCEED;
0369     
0370     if (EXSUCCEED!=Bget(p_ub, TMXID, 0, p_xai->tmxid, 0L) ||
0371             EXSUCCEED!=Bget(p_ub, TMRMID, 0, (char *)&p_xai->tmrmid, 0L) ||
0372             EXSUCCEED!=Bget(p_ub, TMNODEID, 0, (char *)&p_xai->tmnodeid, 0L) ||
0373             EXSUCCEED!=Bget(p_ub, TMSRVID, 0, (char *)&p_xai->tmsrvid, 0L) ||
0374             EXSUCCEED!=Bget(p_ub, TMKNOWNRMS, 0, (char *)p_xai->tmknownrms, 0L)
0375             )
0376     {
0377         NDRX_LOG(log_error, "Failed to get TMXID/TMRMID/TMNODEID/"
0378                 "TMSRVID/TMKNOWNRMS! - %s", Bstrerror(Berror));
0379         EXFAIL_OUT(ret);
0380     }
0381 
0382     if (!(flags & XA_TXINFO_NOBTID))
0383     {
0384         if (EXSUCCEED!=Bget(p_ub, TMTXBTID, 0, (char *)&p_xai->btid, 0L))
0385         {
0386             NDRX_LOG(log_error, "Failed to get TMTXBTID! - %s", Bstrerror(Berror));
0387             EXFAIL_OUT(ret);
0388         }
0389     }
0390     
0391 out:
0392     return ret;
0393 }
0394 
0395 /**
0396  * Copy XA transaction info to tpcall() buffer
0397  * @param call
0398  * @param p_xai
0399  * @return 
0400  */
0401 expublic void atmi_xa_cpy_xai_to_call(tp_command_call_t *call, atmi_xa_tx_info_t *p_xai)
0402 {
0403     XA_TX_COPY(call, p_xai);
0404 }
0405 
0406 /**
0407  * Function prints the list known resource managers in transaction
0408  * @param tmknownrms
0409  * @return 
0410  */
0411 expublic void atmi_xa_print_knownrms(int dbglev, char *msg, char *tmknownrms)
0412 {
0413     int i;
0414     int cnt = strlen(tmknownrms);
0415     char tmp[128]={EXEOS};
0416     int len;
0417     
0418     for (i=0; i<cnt; i++)
0419     {
0420         len = strlen(tmp);
0421         if (i<cnt-1)
0422         {
0423             snprintf(tmp+len, sizeof(tmp)-len, "%hd ", (short)tmknownrms[i]);
0424         }
0425         else
0426         {
0427             snprintf(tmp+len, sizeof(tmp)-len, "%hd", (short)tmknownrms[i]);
0428         }
0429     }
0430     NDRX_LOG(dbglev, "%s: %s", msg, tmp);
0431 }
0432 
0433 /**
0434  * Reset current transaction info (remove current transaction)
0435  * @return 
0436  */
0437 expublic void atmi_xa_reset_curtx(void)
0438 {
0439     ATMI_TLS_ENTRY;
0440     
0441     if (G_atmi_tls->G_atmi_xa_curtx.txinfo)
0442     {
0443         atmi_xa_curtx_del(G_atmi_tls->G_atmi_xa_curtx.txinfo);
0444         G_atmi_tls->G_atmi_xa_curtx.txinfo = NULL;
0445     }
0446 }
0447 
0448 /**
0449  * Check is current RM known in the list
0450  * @param tmknownrms
0451  * @return 
0452  */
0453 expublic int atmi_xa_is_current_rm_known(char *tmknownrms)
0454 {
0455     if (NULL==strchr(tmknownrms, (unsigned char)G_atmi_env.xa_rmid))
0456     {
0457         return EXFALSE;
0458     }
0459     return EXTRUE;
0460 }
0461 
0462 /**
0463  * Update the list of known transaction resource managers
0464  * @param dst_tmknownrms
0465  * @param src_tmknownrms
0466  * @return 
0467  */
0468 expublic int atmi_xa_update_known_rms(char *dst_tmknownrms, char *src_tmknownrms)
0469 {
0470     int i;
0471     int len = strlen(src_tmknownrms);
0472     int len2;
0473     int ret = EXSUCCEED;
0474     
0475     NDRX_LOG(log_debug, "src len: %d", len);
0476     
0477     for (i=0; i<len; i++)
0478     {
0479         if (NULL==strchr(dst_tmknownrms, src_tmknownrms[i]))
0480         {
0481             len2=strlen(dst_tmknownrms);
0482             NDRX_LOG(log_debug, "len2=%d", len2);
0483             if (len2==NDRX_MAX_RMS)
0484             {
0485                 NDRX_LOG(log_error, "Too much RMs: src: [%s] dest: [%s]!", 
0486                         src_tmknownrms, dst_tmknownrms);
0487                 EXFAIL_OUT(ret);
0488             }
0489             NDRX_LOG(log_info, "1--> 0x%x", (unsigned int)dst_tmknownrms[len2]);
0490             NDRX_LOG(log_info, "2--> 0x%x", (unsigned int)src_tmknownrms[i]);
0491             
0492             dst_tmknownrms[len2] = src_tmknownrms[i];
0493             dst_tmknownrms[len2+1] = EXEOS;
0494         }
0495     }
0496     
0497 out:
0498     return ret;
0499 }
0500 
0501 /**
0502  * Set current thread info from xai + updates known RMs..
0503  * We should search the hash list of the current transaction and make the ptr 
0504  * as current. If not found, then we shall register
0505  * @param p_xai
0506  * @return 
0507  */
0508 expublic int atmi_xa_set_curtx_from_xai(atmi_xa_tx_info_t *p_xai)
0509 {
0510     int ret = EXSUCCEED;
0511     ATMI_TLS_ENTRY;
0512     
0513     /* Lookup the hash add if found ok switch ptr 
0514      * if not found, add and switch ptr too.
0515      */
0516     if (NULL==(G_atmi_tls->G_atmi_xa_curtx.txinfo = atmi_xa_curtx_get(p_xai->tmxid)) &&
0517          NULL==(G_atmi_tls->G_atmi_xa_curtx.txinfo = 
0518             atmi_xa_curtx_add(p_xai->tmxid, p_xai->tmrmid, 
0519             p_xai->tmnodeid, p_xai->tmsrvid, p_xai->tmknownrms, p_xai->btid,
0520             p_xai->tmtxflags)))
0521             
0522     {
0523         NDRX_LOG(log_error, "Set current transaction failed!");
0524         ret=EXFAIL;
0525         goto out;
0526     }
0527     
0528     /* mark  */
0529     
0530 out:
0531         return ret;
0532 }
0533 
0534 /**
0535  * reset UBF field only to leave call fields in
0536  * @param p_ub UBF buffer
0537  * @return EXSUCCEED/EXFAIL
0538  */
0539 expublic int atmi_xa_reset_tm_call(UBFH *p_ub)
0540 {
0541     int ret = EXSUCCEED;
0542     BFLDID fldlist [] = 
0543     {
0544         TMPROCESSID
0545         , TMCMD
0546         , TMCALLERRM
0547         , BBADFLDID
0548     };
0549     
0550     if (EXSUCCEED!=Bproj(p_ub, fldlist))
0551     {
0552         NDRX_LOG(log_error, "Failed to reset ubf buffer for tm call");
0553         EXFAIL_OUT(ret);
0554     }
0555     
0556 out:
0557     return ret;
0558 }
0559 
0560 
0561 
0562 /**
0563  * Allocate stanard TM call FB
0564  * @param pp_ub
0565  * @return NULL (error) or allocated FB
0566  */
0567 expublic UBFH * atmi_xa_alloc_tm_call(char cmd)
0568 {
0569     UBFH *p_ub = NULL;
0570     int ret = EXSUCCEED;
0571     ATMI_TLS_ENTRY;
0572     
0573     if (NULL==(p_ub = (UBFH *)tpalloc("UBF", NULL, TM_CALL_FB_SZ)))
0574     {
0575         /* TM error should be already set */
0576         NDRX_LOG(log_error, "Failed to allocate TM call FB (%d)", 
0577                 TM_CALL_FB_SZ);
0578         ret = EXFAIL;
0579         goto out;
0580     }
0581     
0582     /* install caller error */
0583     if (EXSUCCEED!=Bchg(p_ub, TMPROCESSID, 0, G_atmi_tls->G_atmi_conf.my_id, 0L))
0584     {
0585         ndrx_TPset_error_fmt(TPESYSTEM,  "Failed to setup TM call buffer (TMPROCESSID) %d:[%s]", 
0586                                         Berror, Bstrerror(Berror));
0587         
0588         ret = EXFAIL;
0589         goto out;
0590     }
0591     
0592     /* install command code */
0593     if (EXSUCCEED!=Bchg(p_ub, TMCMD, 0, &cmd, 0L))
0594     {
0595         ndrx_TPset_error_fmt(TPESYSTEM,  "Failed to setup TM call buffer (TMCMD) %d:[%s]", 
0596                                         Berror, Bstrerror(Berror));
0597         
0598         ret = EXFAIL;
0599         goto out;
0600     }
0601     
0602     /* Install caller RM code */
0603     if (EXSUCCEED!=Bchg(p_ub, TMCALLERRM, 0, (char *)&G_atmi_env.xa_rmid, 0L))
0604     {
0605         ndrx_TPset_error_fmt(TPESYSTEM,  "Failed to setup TM call buffer (TMCALLERRM) %d:[%s]", 
0606                                         Berror, Bstrerror(Berror));
0607         
0608         ret = EXFAIL;
0609         goto out;
0610     }
0611     
0612     NDRX_LOG(log_debug, "Call buffer setup OK");
0613     
0614 out:
0615 
0616     if (EXSUCCEED!=ret && NULL!=p_ub)
0617     {
0618         tpfree((char *)p_ub);
0619     }
0620 
0621     return p_ub;
0622 }
0623 
0624 /**
0625  * Setup basic admin call buffer
0626  * @param cmd
0627  * @param p_ub
0628  * @return 
0629  */
0630 expublic int atmi_xa_tm_admincall(char cmd, UBFH *p_ub)
0631 {
0632     int ret = EXSUCCEED;
0633     
0634     
0635     
0636 out:
0637     return ret;
0638 }
0639 
0640 /**
0641  * Call Transaction Manager, report status of BTID
0642  * @param p_xai transaction info block
0643  * @param rmstatus status to report
0644  * @return NULL on 
0645  */
0646 expublic UBFH* atmi_xa_call_tm_rmstatus(atmi_xa_tx_info_t *p_xai, char rmstatus)
0647 {
0648     UBFH *p_ub = atmi_xa_alloc_tm_call(ATMI_XA_RMSTATUS);
0649     
0650     
0651     if (NULL==p_ub)
0652     {
0653         NDRX_LOG(log_error, "Failed to allocate %c command buffer", ATMI_XA_RMSTATUS);
0654         goto out;
0655     }
0656     
0657     /* Set BTID */
0658     if (EXSUCCEED!=Bchg(p_ub, TMTXBTID, 0, (char *)&(p_xai->btid), 0L))
0659     {
0660         tpfree((char *)p_ub);
0661         ndrx_TPset_error_fmt(TPESYSTEM,  
0662                 "Failed to set TMTXBTID %d:[%s]", 
0663                 Berror, Bstrerror(Berror));
0664         goto out;
0665     }
0666     
0667     /* Set RM status */
0668     if (EXSUCCEED!=Bchg(p_ub, TMTXRMSTATUS, 0, (char *)&rmstatus, 0L))
0669     {
0670         tpfree((char *)p_ub);
0671         ndrx_TPset_error_fmt(TMTXRMSTATUS,  
0672                 "Failed to set TMTXBTID %d:[%s]", 
0673                 Berror, Bstrerror(Berror));
0674         goto out;
0675     }
0676     /* finally call the TMSRV */
0677     p_ub=atmi_xa_call_tm_generic_fb(ATMI_XA_RMSTATUS, NULL, EXFALSE, EXFAIL, p_xai, p_ub);
0678     
0679 out:    
0680     return p_ub;
0681     
0682 }
0683 
0684 /**
0685  * Generic transaction manager call
0686  * @param cmd - TM command
0687  * @param call_any - should we call any our RMID
0688  * @param rmid - should we call specific RM
0689  * @param p_xai
0690  * @param [in] flags shared system flags and user transaction flags
0691  *     see 
0692  * @param [in] btid branch tid
0693  * @return 
0694  */
0695 expublic UBFH* atmi_xa_call_tm_generic(char cmd, int call_any, short rmid, 
0696         atmi_xa_tx_info_t *p_xai, long flags, long btid)
0697 {
0698     UBFH *p_ub = atmi_xa_alloc_tm_call(cmd);
0699     
0700     if (NULL!=p_ub)
0701     {
0702         if (EXFAIL!=btid && EXSUCCEED!=Bchg(p_ub, TMTXBTID, 0, (char *)&btid, 0L))
0703         {
0704             tpfree((char *)p_ub);
0705             ndrx_TPset_error_fmt(TPESYSTEM,  
0706                     "Failed to set TMTXBTID %d:[%s]", 
0707                     Berror, Bstrerror(Berror));
0708             goto out;
0709         }
0710         
0711         if (EXSUCCEED!=Bchg(p_ub, TMTXFLAGS, 0, (char *)&flags, 0L))
0712         {
0713             tpfree((char *)p_ub);
0714             ndrx_TPset_error_fmt(TPESYSTEM,  
0715                     "Failed to set TMTXFALGS %d:[%s]", 
0716                     Berror, Bstrerror(Berror));
0717             goto out;
0718         }
0719 
0720         return atmi_xa_call_tm_generic_fb(cmd, NULL, call_any, rmid, p_xai, p_ub);
0721     }
0722 out:
0723     return NULL;
0724 }
0725 
0726 /**
0727  * Do generic call to TM server (using FB passed in)
0728  * @rmid - optional, FAIL if not set
0729  * @p_xai - optional, NULL if not set
0730  * @return SUCCEED/FAIL
0731  */
0732 expublic UBFH* atmi_xa_call_tm_generic_fb(char cmd, char *svcnm_spec, int call_any, short rmid, 
0733         atmi_xa_tx_info_t *p_xai, UBFH *p_ub)
0734 {
0735     int ret = EXSUCCEED;
0736     long rsplen;
0737     char svcnm[MAXTIDENT+1];
0738     
0739     ATMI_TLS_ENTRY;
0740 
0741     if (NULL==p_ub)
0742     {
0743         EXFAIL_OUT(ret);
0744     }
0745     
0746     /* Load the data into FB (if available) */
0747     if (NULL!=p_xai && EXSUCCEED!=atmi_xa_load_tx_info(p_ub, p_xai))
0748     {
0749         EXFAIL_OUT(ret);
0750     }
0751     
0752     if (svcnm_spec)
0753     {
0754        /* Override the service name! */
0755         NDRX_STRCPY_SAFE(svcnm, svcnm_spec);
0756     }
0757     else if (rmid>0)
0758     {
0759         /* Any entry of TM */
0760         snprintf(svcnm, sizeof(svcnm), NDRX_SVC_RM, rmid);
0761     }
0762     else if (call_any)
0763     {
0764         snprintf(svcnm, sizeof(svcnm), NDRX_SVC_RM, G_atmi_env.xa_rmid);
0765     }
0766     else
0767     {
0768         /* TM + srvid*/
0769         /* TODO: Think - call local or RM or global!!! */
0770         
0771         if (G_atmi_tls->G_atmi_xa_curtx.txinfo)
0772         {
0773             snprintf(svcnm, sizeof(svcnm), NDRX_SVC_TM_I, 
0774                     G_atmi_tls->G_atmi_xa_curtx.txinfo->tmnodeid, 
0775                     G_atmi_tls->G_atmi_xa_curtx.txinfo->tmrmid, 
0776                     G_atmi_tls->G_atmi_xa_curtx.txinfo->tmsrvid);
0777         }
0778         else if (p_xai)
0779         {
0780             snprintf(svcnm, sizeof(svcnm), NDRX_SVC_TM_I, p_xai->tmnodeid, 
0781                     p_xai->tmrmid, 
0782                     p_xai->tmsrvid);
0783         }
0784         else
0785         {
0786             NDRX_LOG(log_error, "No transaction RM info to call!");
0787             EXFAIL_OUT(ret);
0788         }
0789     }
0790     
0791     NDRX_LOG(log_debug, "About to call TM, service: [%s]", svcnm);
0792     
0793     
0794     ndrx_debug_dump_UBF(log_info, "Request buffer:", p_ub);
0795     
0796     if (EXFAIL == tpcall(svcnm, (char *)p_ub, 0L, (char **)&p_ub, &rsplen,TPNOTRAN))
0797     {
0798         NDRX_LOG(log_error, "%s failed: %s", svcnm, tpstrerror(tperrno));
0799         /* TODO: Needs to set the XA error code!! 
0800         FAIL_OUT(ret);*/
0801     }
0802     
0803     NDRX_LOG(log_debug, "got response from [%s]", svcnm);
0804     /* TODO Might need debug lib for FB dumps.. */
0805     ndrx_debug_dump_UBF(log_info, "Response buffer:", p_ub); 
0806     
0807     /* Check the response code - load response to atmi_lib error handler...*/
0808     /* only if we really have an code back! */
0809     if (atmi_xa_is_error(p_ub))
0810     {
0811         atmi_xa2tperr(p_ub);
0812     }
0813             
0814     if (ndrx_TPis_error())
0815     {
0816         NDRX_LOG(log_error, "Failed to call RM: %d:[%s] ", 
0817                             tperrno, tpstrerror(tperrno));
0818         
0819         /* If the XA error is not loaded, override the value
0820          * to XAER_RMERR
0821          */
0822         if (!G_atmi_tls->M_atmi_reason)
0823         {
0824             /* ok, in this case at prepare we shall roll back.. */
0825             if (TPENOENT==tperrno || TPETIME==tperrno)
0826             {
0827                 /* ask for retry... */
0828                 G_atmi_tls->M_atmi_reason=XAER_RMFAIL;
0829             }
0830             else
0831             {
0832                 G_atmi_tls->M_atmi_reason=XAER_RMERR;
0833             }
0834         }
0835         EXFAIL_OUT(ret);
0836     }
0837             
0838 out:
0839             
0840     if (EXSUCCEED!=ret && NULL!=p_ub)
0841     {
0842         atmi_error_t err;
0843         
0844         /* Save the original error/needed later! */
0845         ndrx_TPsave_error(&err);
0846         tpfree((char *)p_ub);  /* This stuff removes ATMI error!!! */
0847         ndrx_TPrestore_error(&err);
0848         p_ub = NULL;
0849     }
0850 
0851     NDRX_LOG(log_debug, "atmi_xa_call_tm_generic returns %p", p_ub);
0852     return p_ub;
0853 }
0854 
0855 /**
0856  * Return current transactions XID in context of the branch.
0857  * We should deserialize & replace branch id
0858  * Branch details are added to each part of the XID at the end.
0859  * TODO: add cache.
0860  * @param[in] btid branch tid which is part of xid
0861  * @return 
0862  */
0863 expublic XID* atmi_xa_get_branch_xid(atmi_xa_tx_info_t *p_xai, long btid)
0864 {
0865     unsigned char rmid = (unsigned char)G_atmi_env.xa_rmid; /* max 255...! */
0866     long btidh = htonll(btid);
0867     
0868     ATMI_TLS_ENTRY;
0869     
0870     memset(&G_atmi_tls->xid, 0, sizeof(G_atmi_tls->xid));
0871     atmi_xa_deserialize_xid((unsigned char *)p_xai->tmxid, &G_atmi_tls->xid);
0872     
0873     /* set current branch id - do we need this actually? 
0874      * How about byte order?
0875      */
0876     memcpy(G_atmi_tls->xid.data + 
0877             G_atmi_tls->xid.gtrid_length - 
0878             sizeof(long) - 
0879             sizeof(char), 
0880             &rmid, 
0881             sizeof(unsigned char));
0882     
0883     memcpy(G_atmi_tls->xid.data + 
0884             G_atmi_tls->xid.gtrid_length + 
0885             G_atmi_tls->xid.bqual_length - 
0886             sizeof(long) - 
0887             sizeof(char),
0888             &rmid, 
0889             sizeof(unsigned char));
0890     
0891     /* Add Branch TID: */
0892     /* Do not add BTID to gtrid if using tight branching.
0893      * but remember, Oracle DB allows only 32 branches
0894      * in the same gtrid!!
0895      */
0896     if (!(G_atmi_env.xa_flags_sys & NDRX_XA_FLAG_SYS_BTIGHT))
0897     {
0898         memcpy(G_atmi_tls->xid.data + 
0899             G_atmi_tls->xid.gtrid_length - 
0900             sizeof(long),
0901             &btidh, 
0902             sizeof(btidh));
0903     }
0904     
0905     memcpy(G_atmi_tls->xid.data + 
0906             G_atmi_tls->xid.gtrid_length + 
0907             G_atmi_tls->xid.bqual_length - 
0908             sizeof(long),
0909             &btidh, 
0910             sizeof(btidh));
0911     
0912     /* Dump the branch XID */
0913     
0914     NDRX_LOG(log_debug, "BTID=%ld/%ld rmid=%d", btid, btidh, (int)rmid);
0915     NDRX_DUMP(log_debug, "Branch XID", &G_atmi_tls->xid, sizeof(G_atmi_tls->xid));
0916     
0917     return &G_atmi_tls->xid;
0918 }   
0919 
0920 /*************************** Call descriptor manipulations ********************/
0921 
0922 /**
0923  * Register call descriptor as part of global tx
0924  * @param p_xai
0925  * @param cd
0926  * @return 
0927  */
0928 expublic int atmi_xa_cd_reg(atmi_xa_tx_cd_t **cds, int in_cd)
0929 {
0930     int ret = EXSUCCEED;
0931     
0932     atmi_xa_tx_cd_t *cdt = NDRX_CALLOC(1, sizeof(atmi_xa_tx_cd_t));
0933     
0934     if (NULL==cdt)
0935     {
0936         NDRX_LOG(log_error, "Failed to malloc: %s data for cd "
0937                 "binding to global tx!", strerror(errno));
0938         userlog("Failed to malloc: %s data for cd "
0939                 "binding to global tx!", strerror(errno));
0940         EXFAIL_OUT(ret);
0941     }
0942     
0943     cdt->cd = in_cd;
0944     
0945     EXHASH_ADD_INT((*cds), cd, cdt);
0946     
0947 out:
0948     return ret;
0949 }
0950 
0951 /**
0952  * Find the cd element in hash
0953  * @param p_xai
0954  * @param cd
0955  * @return 
0956  */
0957 expublic atmi_xa_tx_cd_t * atmi_xa_cd_find(atmi_xa_tx_cd_t **cds, int in_cd)
0958 {
0959     atmi_xa_tx_cd_t *ret = NULL;
0960     EXHASH_FIND_INT( (*cds), &in_cd, ret);    
0961     return ret;
0962 }
0963 
0964 /**
0965  * Check is any call descriptor registered under global transaction
0966  * @param p_xai
0967  * @return 
0968  */
0969 expublic int atmi_xa_cd_isanyreg(atmi_xa_tx_cd_t **cds)
0970 {
0971     int ret = EXFALSE;
0972     atmi_xa_tx_cd_t *el = NULL;
0973     atmi_xa_tx_cd_t *elt = NULL;
0974     
0975     /* Iterate over the hash! */
0976     EXHASH_ITER(hh, (*cds), el, elt)
0977     {
0978         NDRX_LOG(log_error, "Found cd=%d linked to tx!", el->cd);
0979         ret = EXTRUE;
0980     }
0981     
0982 out:
0983     return ret;
0984 }
0985 
0986 /**
0987  * Remove cd from global tx
0988  * @param p_xai
0989  * @param cd
0990  */
0991 expublic void atmi_xa_cd_unreg(atmi_xa_tx_cd_t **cds, int in_cd)
0992 {
0993     int ret = EXSUCCEED;
0994     
0995     atmi_xa_tx_cd_t *el = atmi_xa_cd_find(cds, in_cd);
0996     
0997     if (NULL!=el)
0998     {
0999         EXHASH_DEL((*cds), el);
1000         
1001         NDRX_FREE(el);
1002     }
1003 }
1004 
1005 /**
1006  * Clean up the hash - remove all registered call descriptors.
1007  * @param p_xai
1008  * @return 
1009  */
1010 expublic int atmi_xa_cd_unregall(atmi_xa_tx_cd_t **cds)
1011 {
1012     int ret = EXSUCCEED;
1013     
1014     atmi_xa_tx_cd_t *el = NULL;
1015     atmi_xa_tx_cd_t *elt = NULL;
1016     
1017     /* Iterate over the hash! */
1018     EXHASH_ITER(hh, (*cds), el, elt)
1019     {
1020         EXHASH_DEL((*cds), el);
1021         NDRX_FREE(el);
1022     }
1023     
1024 out:
1025     return ret;
1026 }
1027 
1028 /**
1029  * Filter the service names, return TRUE for those which matches individual TMs
1030  * Well we shall work only at resource ID level.
1031  * Thus only on -1
1032  * @param svcnm service name to check
1033  * @param nr_match number of dashes to match in service name
1034  * @return TRUE/FALSE
1035  */
1036 expublic int ndrx_tmfilter_int(char *svcnm, int nr_match)
1037 {
1038     int i, len;
1039     int cnt = 0;
1040     int is_ddr = EXFALSE;
1041     
1042     /*printf("Testing: [%s]\n", svcnm);*/
1043     /* example: @TM-1-1-310 */
1044     if (0==strncmp(svcnm, "@TM", 3))
1045     {
1046         /* Now it should have 3x dashes inside */
1047         len = strlen(svcnm);
1048         for (i=0; i<len; i++)
1049         {
1050             if ('-'==svcnm[i])
1051             {
1052                 cnt++;
1053             }
1054             else if (i>0 && NDRX_SYS_SVC_PFXC==svcnm[i])
1055             {
1056                 is_ddr=EXTRUE;
1057             }
1058         }
1059     }
1060     
1061     /* normally we do not process any DDRs, just may happen due to configuration */
1062     if (nr_match==cnt && !is_ddr)
1063         return EXTRUE;
1064     else
1065         return EXFALSE;
1066 }
1067 
1068 /**
1069  * Filter out service name used by the RM (common service name of RM)
1070  * @param svcnm svcnm to check
1071  * @return EXTRUE/EXFALSE
1072  */
1073 expublic int ndrx_tmfilter_common(char *svcnm)
1074 {
1075     return ndrx_tmfilter_int(svcnm, 1);
1076 }
1077 
1078 /**
1079  * Match particular TMSRV service name
1080  * @param svcnm service name to check
1081  * @return EXTRUE/EXFALSE
1082  */
1083 expublic int ndrx_tmfilter_srv(char *svcnm)
1084 {
1085     return ndrx_tmfilter_int(svcnm, 3);
1086 }
1087 
1088 /* vim: set ts=4 sw=4 et smartindent: */