Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief ATMI error library
0003  *   Also used by XA lib & TM process.
0004  *
0005  * @file tperror.c
0006  */
0007 /* -----------------------------------------------------------------------------
0008  * Enduro/X Middleware Platform for Distributed Transaction Processing
0009  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0010  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0011  * This software is released under one of the following licenses:
0012  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0013  * See LICENSE file for full text.
0014  * -----------------------------------------------------------------------------
0015  * AGPL license:
0016  *
0017  * This program is free software; you can redistribute it and/or modify it under
0018  * the terms of the GNU Affero General Public License, version 3 as published
0019  * by the Free Software Foundation;
0020  *
0021  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0022  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0023  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0024  * for more details.
0025  *
0026  * You should have received a copy of the GNU Affero General Public License along 
0027  * with this program; if not, write to the Free Software Foundation, Inc.,
0028  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0029  *
0030  * -----------------------------------------------------------------------------
0031  * A commercial use license is available from Mavimax, Ltd
0032  * contact@mavimax.com
0033  * -----------------------------------------------------------------------------
0034  */
0035 
0036 /*---------------------------Includes-----------------------------------*/
0037 #include <stdio.h>
0038 #include <stdarg.h>
0039 #include <memory.h>
0040 #include <stdlib.h>
0041 #include <atmi.h>
0042 #include <ndebug.h>
0043 #include <nerror.h>
0044 #include <tperror.h>
0045 #include <Exfields.h>
0046 
0047 #include <xa.h>
0048 #include <atmi_int.h>
0049 #include <atmi_tls.h>
0050 /*---------------------------Externs------------------------------------*/
0051 /*---------------------------Macros-------------------------------------*/
0052 
0053 /**
0054  * Function returns error description
0055  */
0056 #define ATMI_ERROR_DESCRIPTION(X) (M_atmi_error_defs[X<TPMINVAL?TPMINVAL:(X>TPMAXVAL?TPMAXVAL:X)].msg)
0057 #define TP_ERROR(X) X, #X
0058 /*---------------------------Enums--------------------------------------*/
0059 /*---------------------------Typedefs-----------------------------------*/
0060 /*---------------------------Globals------------------------------------*/
0061 /*---------------------------Statics------------------------------------*/
0062 
0063 /* Do we need this to be in message catalogue?
0064  * table bellow is indexed by id (i.e. direct array erorr lookup should work)
0065  */
0066 struct err_msg
0067 {
0068     int id;
0069     char *msg;
0070 } M_atmi_error_defs [] =
0071 {
0072     {TP_ERROR(TPMINVAL)},   /* 0 - minimum error message */
0073     {TP_ERROR(TPEABORT)}, /* 1 */
0074     {TP_ERROR(TPEBADDESC)}, /* 2 */
0075     {TP_ERROR(TPEBLOCK)}, /* 3 */
0076     {TP_ERROR(TPEINVAL)}, /* 4 */
0077     {TP_ERROR(TPELIMIT)}, /* 5 */
0078     {TP_ERROR(TPENOENT)}, /* 6 */
0079     {TP_ERROR(TPEOS)}, /* 7 */
0080     {TP_ERROR(TPEPERM)}, /* 8 */
0081     {TP_ERROR(TPEPROTO)}, /* 9 */
0082     {TP_ERROR(TPESVCERR)}, /* 10 */
0083     {TP_ERROR(TPESVCFAIL)}, /* 11 */
0084     {TP_ERROR(TPESYSTEM)}, /* 12 */
0085     {TP_ERROR(TPETIME)}, /* 13 */
0086     {TP_ERROR(TPETRAN)}, /* 14 */
0087     {TP_ERROR(TPGOTSIG)}, /* 15 */
0088     {TP_ERROR(TPERMERR)}, /* 16 */
0089     {TP_ERROR(TPEITYPE)}, /* 17 */
0090     {TP_ERROR(TPEOTYPE)}, /* 18 */
0091     {TP_ERROR(TPERELEASE)}, /* 19 */
0092     {TP_ERROR(TPEHAZARD)}, /* 20 */
0093     {TP_ERROR(TPEHEURISTIC)}, /* 21 */
0094     {TP_ERROR(TPEEVENT)}, /* 22 */
0095     {TP_ERROR(TPEMATCH)}, /* 23 */
0096     {TP_ERROR(TPEDIAGNOSTIC)}, /* 24 */
0097     {TP_ERROR(TPEMIB)}, /* 25 */
0098     {TP_ERROR(TPERFU26)}, /* 26 */
0099     {TP_ERROR(TPERFU27)}, /* 27 */
0100     {TP_ERROR(TPERFU28)}, /* 28 */
0101     {TP_ERROR(TPERFU29)}, /* 29 */
0102     {TP_ERROR(TPINITFAIL)}, /* 30 */
0103     {TP_ERROR(TPMAXVAL)} /* 31 - maximum error message */
0104 };
0105 
0106 /**
0107  * XA api error codes
0108  */
0109 struct err_msg_xa
0110 {
0111     short errcode;
0112     char *msg;
0113 } M_atmi_xa_error_defs [] =
0114 {
0115 {XA_RBBASE, "the inclusive lower bound of the rollback codes"},
0116 {XA_RBROLLBACK, "the rollback was caused by an unspecified reason"},
0117 {XA_RBCOMMFAIL, "the rollback was caused by a communication failure"},
0118 {XA_RBDEADLOCK, "a deadlock was detected"},
0119 {XA_RBINTEGRITY, "a condition that violates the integrity of the resources was detected"},
0120 {XA_RBOTHER, "the resource manager rolled back the transaction branch for a reason not on this list"},
0121 {XA_RBPROTO, "a protocol error occurred in the resource manager"},
0122 {XA_RBTIMEOUT, "a transaction branch took too long"},
0123 {XA_RBTRANSIENT, "may retry the transaction branch"},
0124 {XA_RBEND, " the inclusive upper bound of the rollback codes"},
0125 {XA_NOMIGRATE, "resumption must occur where suspension occurred"},
0126 {XA_HEURHAZ, "the transaction branch may have been heuristically completed"},
0127 {XA_HEURCOM, "the transaction branch has been heuristically committed"},
0128 {XA_HEURRB, "the transaction branch has been heuristically rolled back"},
0129 {XA_HEURMIX, "the transaction branch has been heuristically committed and rolled back"},
0130 {XA_RETRY, "routine returned with no effect and may be reissued"},
0131 {XA_RDONLY, "the transaction branch was read-only and has been committed"},
0132 {XA_OK, "normal execution"},
0133 {XAER_ASYNC, "asynchronous operation already outstanding"},
0134 {XAER_RMERR, "a resource manager error occurred in the transaction branch"},
0135 {XAER_NOTA, "the XID is not valid"},
0136 {XAER_INVAL, "invalid arguments were given"},
0137 {XAER_PROTO, "routine invoked in an improper context"},
0138 {XAER_RMFAIL, "resource manager unavailable"},
0139 {XAER_DUPID, "the XID already exists"},
0140 {XAER_OUTSIDE, "resource manager doing work outside global transaction"},
0141 };
0142 
0143 /*---------------------------Prototypes---------------------------------*/
0144 
0145 /**
0146  * Return error code in string format
0147  * note in case of invalid error code, the max or min values will be returned.
0148  * @param err error code
0149  * @return ptr to constant string (error code)
0150  */
0151 expublic char * tpecodestr(int err)
0152 {
0153     return ATMI_ERROR_DESCRIPTION(err);
0154 }
0155 
0156 /**
0157  * Standard.
0158  * Printer error to stderr
0159  * @param str
0160  */
0161 expublic void TP_error (char *str)
0162 {
0163     ATMI_TLS_ENTRY;
0164     
0165     if (EXEOS!=G_atmi_tls->M_atmi_error_msg_buf[0])
0166     {
0167         fprintf(stderr, "%s:%d:%s (%s)\n", str, 
0168                 G_atmi_tls->M_atmi_error, 
0169                 ATMI_ERROR_DESCRIPTION(G_atmi_tls->M_atmi_error),
0170                 G_atmi_tls->M_atmi_error_msg_buf);
0171     }
0172     else
0173     {
0174         fprintf(stderr, "%s:%d:%s\n", str, G_atmi_tls->M_atmi_error, 
0175                 ATMI_ERROR_DESCRIPTION(G_atmi_tls->M_atmi_error));
0176     }
0177 }
0178 
0179 /**
0180  * Extended version. This will print internal error message what happened.
0181  * This is not thread safe (as all other functions).
0182  * @param error_code
0183  */
0184 expublic char * tpstrerror (int err)
0185 {
0186     ATMI_TLS_ENTRY;
0187     if (EXEOS!=G_atmi_tls->M_atmi_error_msg_buf[0])
0188     {
0189         snprintf(G_atmi_tls->errbuf, sizeof(G_atmi_tls->errbuf), 
0190                 "%d:%s (last error %d: %s)",
0191                 err,
0192                 ATMI_ERROR_DESCRIPTION(err),
0193                 G_atmi_tls->M_atmi_error,
0194                 G_atmi_tls->M_atmi_error_msg_buf);
0195     }
0196     else
0197     {
0198         snprintf(G_atmi_tls->errbuf, sizeof(G_atmi_tls->errbuf), "%d:%s",
0199                     err, ATMI_ERROR_DESCRIPTION(err));
0200     }
0201 
0202     return G_atmi_tls->errbuf;
0203 }
0204 
0205 /**
0206  * ATMI standard
0207  * @return - pointer to int holding error code?
0208  */
0209 expublic int * _exget_tperrno_addr (void)
0210 {
0211     ATMI_TLS_ENTRY;
0212     return &G_atmi_tls->M_atmi_error;
0213 }
0214 
0215 /**
0216  * Internal function for setting (FORCED)
0217  * @param error_code
0218  * @param msg
0219  * @return
0220  */
0221 expublic void ndrx_TPset_error(int error_code)
0222 {
0223     ATMI_TLS_ENTRY;
0224     
0225     NDRX_LOG(log_warn, "%s: %d (%s)",
0226             __func__, error_code, ATMI_ERROR_DESCRIPTION(error_code));
0227 
0228     G_atmi_tls->M_atmi_error_msg_buf[0] = EXEOS;
0229     G_atmi_tls->M_atmi_error = error_code;
0230 }
0231 
0232 /**
0233  * Translate error from standard library to ATMI
0234  */
0235 expublic void ndrx_TPset_error_nstd(void)
0236 {
0237     int err = _Nis_error();
0238     /* copy msg only if error is present */
0239     if (err)
0240     {
0241         NDRX_STRCPY_SAFE(G_atmi_tls->M_atmi_error_msg_buf, ndrx_Nemsg_buf());
0242     }
0243     
0244     /* switch the error */
0245     switch (err)
0246     {
0247         case NEINVALKEY: /* Invalid key (probably) */
0248         case NEMANDATORY: /* Mandatory field is missing */
0249         case NEFORMAT: /* Format error */
0250         case NEINVAL: /* Invalid value passed to function */
0251         case NEINVALINI:       /* Invalid INI file */
0252             err=TPEINVAL;
0253             break;
0254         case NEMALLOC: /* Malloc failed */
0255         case NEUNIX: /* Unix error occurred */
0256             err=TPEOS;
0257             break;
0258         case NEPLUGIN: /* Plugin error */
0259         case NESYSTEM: /* System failure */
0260             err=TPESYSTEM;
0261             break;
0262         case NETOUT: /* Time-out condition */
0263             err=TPETIME;
0264             break;
0265         case NENOCONN: /* Connection not found */
0266             err=TPENOENT;
0267             break;
0268         case NENOSPACE: /* No space */
0269         case NELIMIT: /* Limit reached */
0270             err=TPELIMIT;
0271             break;
0272         default:
0273             err=TPESYSTEM;
0274             break;
0275     }
0276     
0277     G_atmi_tls->M_atmi_error=err;
0278 }
0279 
0280 /**
0281  * I nternetal function for setting
0282  * @param error_code
0283  * @param msg
0284  * @return
0285  */
0286 expublic void ndrx_TPset_error_msg(int error_code, char *msg)
0287 {
0288     int msg_len;
0289     int err_len;
0290     ATMI_TLS_ENTRY;
0291 
0292     if (!G_atmi_tls->M_atmi_error)
0293     {
0294         msg_len = strlen(msg);
0295         err_len = (msg_len>MAX_TP_ERROR_LEN)?MAX_TP_ERROR_LEN:msg_len;
0296 
0297 
0298         NDRX_LOG(log_warn, "_TPset_error_msg: %d (%s) [%s]", error_code,
0299                                 ATMI_ERROR_DESCRIPTION(error_code), msg);
0300         G_atmi_tls->M_atmi_error_msg_buf[0] = EXEOS;
0301         strncat(G_atmi_tls->M_atmi_error_msg_buf, msg, err_len);
0302         G_atmi_tls->M_atmi_error = error_code;
0303     }
0304 }
0305 
0306 
0307 /**
0308  * Override the current error code.
0309  * @param error_code
0310  */
0311 expublic void ndrx_TPoverride_code(int error_code)
0312 {
0313     ATMI_TLS_ENTRY;
0314     G_atmi_tls->M_atmi_error = error_code;
0315 }
0316 
0317 /**
0318  * Advanced error setting function, uses format list
0319  * Use this only in case where it is really needed.
0320  * @param error_code - error code
0321  * @param fmt - format string
0322  * @param ... - format details
0323  */
0324 expublic void ndrx_TPset_error_fmt(int error_code, const char *fmt, ...)
0325 {
0326     char msg[MAX_TP_ERROR_LEN+1] = {EXEOS};
0327     va_list ap;
0328     ATMI_TLS_ENTRY;
0329 
0330     if (!G_atmi_tls->M_atmi_error)
0331     {
0332         va_start(ap, fmt);
0333         (void) vsnprintf(msg, sizeof(msg), fmt, ap);
0334         va_end(ap);
0335 
0336         NDRX_STRCPY_SAFE(G_atmi_tls->M_atmi_error_msg_buf, msg);
0337         G_atmi_tls->M_atmi_error = error_code;
0338 
0339         NDRX_LOG(log_warn, "%s: %d (%s) [%s]", __func__,
0340                         error_code, ATMI_ERROR_DESCRIPTION(error_code),
0341                         G_atmi_tls->M_atmi_error_msg_buf);
0342     }
0343 }
0344 
0345 /**
0346  * Extended error setter, including reason (for XA mostly)
0347  * Silent version (no debug message)
0348  * @param error_code
0349  * @param reason
0350  * @param fmt
0351  * @param ...
0352  */
0353 expublic void ndrx_TPset_error_fmt_rsn_silent(int error_code, 
0354         short reason, const char *fmt, ...)
0355 {
0356     char msg[MAX_TP_ERROR_LEN+1] = {EXEOS};
0357     va_list ap;
0358     ATMI_TLS_ENTRY;
0359 
0360     if (!G_atmi_tls->M_atmi_error)
0361     {
0362         va_start(ap, fmt);
0363         (void) vsnprintf(msg, sizeof(msg), fmt, ap);
0364         va_end(ap);
0365 
0366         NDRX_STRCPY_SAFE(G_atmi_tls->M_atmi_error_msg_buf, msg);
0367         G_atmi_tls->M_atmi_error = error_code;
0368         G_atmi_tls->M_atmi_reason = reason;
0369     }
0370 }
0371 
0372 /**
0373  * Extended error setter, including reason (for XA mostly)
0374  * @param error_code
0375  * @param reason
0376  * @param fmt
0377  * @param ...
0378  */
0379 expublic void ndrx_TPset_error_fmt_rsn(int error_code, short reason, const char *fmt, ...)
0380 {
0381     char msg[MAX_TP_ERROR_LEN+1] = {EXEOS};
0382     va_list ap;
0383     int lev = log_warn;
0384     ATMI_TLS_ENTRY;
0385 
0386     if (!G_atmi_tls->M_atmi_error)
0387     {
0388         va_start(ap, fmt);
0389         (void) vsnprintf(msg, sizeof(msg), fmt, ap);
0390         va_end(ap);
0391         
0392         /* Support #729 */
0393         if (XA_RDONLY==reason)
0394         {
0395             lev = log_debug;
0396         }
0397 
0398         NDRX_STRCPY_SAFE(G_atmi_tls->M_atmi_error_msg_buf, msg);
0399         G_atmi_tls->M_atmi_error = error_code;
0400         G_atmi_tls->M_atmi_reason = reason;
0401 
0402         NDRX_LOG(lev, "%s: %d (%s) reason: %d [%s]", __func__, 
0403                         error_code, ATMI_ERROR_DESCRIPTION(error_code), reason,
0404                         G_atmi_tls->M_atmi_error_msg_buf);
0405     }
0406 }
0407 
0408 /**
0409  * Unset any error data currently in use
0410  */
0411 expublic void ndrx_TPunset_error(void)
0412 {
0413     ATMI_TLS_ENTRY;
0414     
0415     G_atmi_tls->M_atmi_error_msg_buf[0]=EXEOS;
0416     G_atmi_tls->M_atmi_error = BMINVAL;
0417     G_atmi_tls->M_atmi_reason = NDRX_XA_ERSN_NONE;
0418 }
0419 /**
0420  * Return >0 if error is set
0421  * @return 
0422  */
0423 expublic int ndrx_TPis_error(void)
0424 {
0425     ATMI_TLS_ENTRY;
0426     return G_atmi_tls->M_atmi_error;
0427 }
0428 
0429 /**
0430  * Append error message
0431  * @param msg
0432  */
0433 expublic void ndrx_TPappend_error_msg(char *msg)
0434 {
0435     int free_space;
0436     int app_error_len = strlen(msg);
0437     int n;
0438     
0439     ATMI_TLS_ENTRY;
0440     
0441     free_space = MAX_TP_ERROR_LEN-strlen(G_atmi_tls->M_atmi_error_msg_buf);
0442     
0443     n = free_space<app_error_len?free_space:app_error_len;
0444     strncat(G_atmi_tls->M_atmi_error_msg_buf, msg, n);
0445 }
0446 
0447 /* <XA Error handling - used by ATMI lib & TM server>*/
0448 
0449 /**
0450  * Return XA reason code (if set)
0451  * @return 
0452  */
0453 expublic short atmi_xa_get_reason(void)
0454 {   
0455     ATMI_TLS_ENTRY;
0456     return G_atmi_tls->M_atmi_reason;
0457 }
0458 
0459 /**
0460  * Internal function for setting
0461  * @param error_code
0462  * @param msg
0463  * @return
0464  */
0465 expublic void atmi_xa_set_error(UBFH *p_ub, short error_code, short reason)
0466 {
0467     if (!atmi_xa_is_error(p_ub))
0468     {
0469         NDRX_LOG(log_warn, "%s: %d (%s)", __func__,
0470                                 error_code, ATMI_ERROR_DESCRIPTION(error_code));
0471         Bchg(p_ub, TMERR_CODE, 0, (char *)&error_code, 0L);
0472         Bchg(p_ub, TMERR_REASON, 0, (char *)&reason, 0L);
0473     }
0474 }
0475 
0476 /**
0477  * Internal function for setting
0478  * @param error_code
0479  * @param msg
0480  * @return
0481  */
0482 expublic void atmi_xa_set_error_msg(UBFH *p_ub, short error_code, short reason, char *msg)
0483 {
0484     if (!atmi_xa_is_error(p_ub))
0485     {
0486         int lev;
0487         if (TPMINVAL==error_code)
0488         {
0489             lev = log_debug;
0490         }
0491         else
0492         {
0493             lev = log_warn;
0494         }
0495         NDRX_LOG(lev, "%s: %d (%s) [%s]", __func__, error_code,
0496                                 ATMI_ERROR_DESCRIPTION(error_code), msg);
0497         
0498         Bchg(p_ub, TMERR_CODE, 0, (char *)&error_code, 0L);
0499         Bchg(p_ub, TMERR_REASON, 0, (char *)&reason, 0L);
0500         Bchg(p_ub, TMERR_MSG, 0, msg, 0L);
0501     }
0502 }
0503 
0504 /**
0505  * Advanced error setting function, uses format list
0506  * Use this only in case where it is really needed.
0507  * @param error_code - error code
0508  * @param fmt - format stirng
0509  * @param ... - format details
0510  */
0511 expublic void atmi_xa_set_error_fmt(UBFH *p_ub, short error_code, short reason, 
0512         const char *fmt, ...)
0513 {
0514     char msg[MAX_TP_ERROR_LEN+1] = {EXEOS};
0515     va_list ap;
0516 
0517     if (!atmi_xa_is_error(p_ub))
0518     {
0519         va_start(ap, fmt);
0520         (void) vsnprintf(msg, sizeof(msg), fmt, ap);
0521         va_end(ap);
0522 
0523             NDRX_LOG(log_warn, "atmi_xa_set_error_fmt: %d (%s) [%s]",
0524                             error_code, ATMI_ERROR_DESCRIPTION(error_code),
0525                             msg);
0526         Bchg(p_ub, TMERR_CODE, 0, (char *)&error_code, 0L);
0527         Bchg(p_ub, TMERR_REASON, 0, (char *)&reason, 0L);
0528         Bchg(p_ub, TMERR_MSG, 0, msg, 0L);
0529     }
0530 }
0531 
0532 /**
0533  * Set local error to UBF
0534  * @param p_ub UBF buffer to fill with error data
0535  */
0536 expublic void ndrx_TPset_error_ubf(UBFH *p_ub)
0537 {
0538     short error_code;
0539     short reason;
0540         
0541     error_code = (short)G_atmi_tls->M_atmi_error;
0542     reason = (short)G_atmi_tls->M_atmi_reason;
0543     
0544     Bchg(p_ub, TMERR_CODE, 0, (char *)&error_code, 0L);
0545     Bchg(p_ub, TMERR_REASON, 0, (char *)&reason, 0L);
0546     Bchg(p_ub, TMERR_MSG, 0, G_atmi_tls->M_atmi_error_msg_buf, 0L);
0547 }
0548 
0549 /**
0550  * Override XA error code.
0551  * @param p_ub
0552  * @param error_code
0553  */
0554 expublic void atmi_xa_override_error(UBFH *p_ub, short error_code)
0555 {
0556     NDRX_LOG(log_warn, "atmi_xa_override_error: %d (%s)",
0557                     error_code, ATMI_ERROR_DESCRIPTION(error_code));
0558     Bchg(p_ub, TMERR_CODE, 0, (char *)&error_code, 0L);
0559 }
0560 
0561 
0562 /**
0563  * Unset any error data currently in use
0564  */
0565 expublic void atmi_xa_unset_error(UBFH *p_ub)
0566 {
0567     Bdel(p_ub, TMERR_CODE, 0);
0568     Bdel(p_ub, TMERR_REASON, 0);
0569     Bdel(p_ub, TMERR_MSG, 0);
0570 }
0571 /**
0572  * Return >0 if error is set
0573  * @return 
0574  */
0575 expublic int atmi_xa_is_error(UBFH *p_ub)
0576 {
0577     short errcode = TPMINVAL;
0578     Bget(p_ub, TMERR_CODE, 0, (char *)&errcode, 0L);
0579     
0580     return (int)errcode;
0581 }
0582 
0583 /**
0584  * Append error message
0585  * @param msg
0586  */
0587 expublic void atmi_xa_error_msg(UBFH *p_ub, char *msg)
0588 {
0589     char tmp[MAX_TP_ERROR_LEN+1] = {EXEOS};
0590     
0591     Bget(p_ub, TMERR_MSG, 0, tmp, 0L);
0592     
0593     int free_space = MAX_TP_ERROR_LEN-strlen(tmp);
0594     int app_error_len = strlen(msg);
0595     int n;
0596     n = free_space<app_error_len?free_space:app_error_len;
0597     strncat(tmp, msg, n);
0598     
0599     Bchg(p_ub, TMERR_MSG, 0, tmp, 0L);
0600 }
0601 
0602 /**
0603  * Convert XA FB error to ATMI lib error
0604  * @param p_ub - response from TM.
0605  */
0606 expublic void atmi_xa2tperr(UBFH *p_ub)
0607 {
0608     char msg[MAX_TP_ERROR_LEN+1] = {EXEOS};
0609     short code;
0610     short reason = 0;
0611     ATMI_TLS_ENTRY;
0612     
0613     /* unset the ATMI error. */
0614     if (Bpres(p_ub, TMERR_CODE, 0))
0615     {
0616         ndrx_TPunset_error();
0617 
0618         Bget(p_ub, TMERR_CODE, 0, (char *)&code, 0L);
0619         Bget(p_ub, TMERR_MSG, 0, msg, 0L);
0620         Bget(p_ub, TMERR_REASON, 0, (char *)&reason, 0L);
0621 
0622         ndrx_TPset_error_msg((int)code, msg);
0623 
0624         /* Append with reason code. */
0625         if (!G_atmi_tls->M_atmi_reason)
0626         {
0627             G_atmi_tls->M_atmi_reason = reason;
0628         }
0629         
0630     }
0631 }
0632 
0633 /**
0634  * return human readable error code for XA api
0635  * @param 
0636  * @return 
0637  */
0638 expublic char *atmi_xa_geterrstr(int code)
0639 {
0640     int i;
0641     static char* unknown_err = "Unknown error";
0642     char *ret = unknown_err;
0643     
0644     for (i=0; i<N_DIM(M_atmi_xa_error_defs); i++)
0645     {
0646         if (code == M_atmi_xa_error_defs[i].errcode)
0647         {
0648             ret= M_atmi_xa_error_defs[i].msg;
0649             goto out;
0650         }
0651     }
0652     
0653 out:
0654         
0655     return ret;
0656 }
0657 
0658 /**
0659  * Approve request
0660  * @param code
0661  * @return 
0662  */
0663 expublic void atmi_xa_approve(UBFH *p_ub)
0664 {
0665     atmi_xa_set_error_msg(p_ub, 0, NDRX_XA_ERSN_NONE, "Success");
0666 }
0667 /* </XA Error handling>*/
0668 
0669 
0670 
0671 /**
0672  * Save current error
0673  * @param p_err
0674  */
0675 expublic void ndrx_TPsave_error(atmi_error_t *p_err)
0676 {
0677     ATMI_TLS_ENTRY;
0678     
0679     p_err->atmi_error = G_atmi_tls->M_atmi_error;
0680     p_err->atmi_reason = G_atmi_tls->M_atmi_reason;
0681     NDRX_STRCPY_SAFE(p_err->atmi_error_msg_buf, G_atmi_tls->M_atmi_error_msg_buf);
0682 }
0683 
0684 /**
0685  * Restore current error
0686  * @param p_err
0687  */
0688 expublic void ndrx_TPrestore_error(atmi_error_t *p_err)
0689 {
0690     ATMI_TLS_ENTRY;
0691     G_atmi_tls->M_atmi_error = p_err->atmi_error;
0692     G_atmi_tls->M_atmi_reason = p_err->atmi_reason;
0693     NDRX_STRCPY_SAFE(G_atmi_tls->M_atmi_error_msg_buf, p_err->atmi_error_msg_buf);
0694 }
0695 /* vim: set ts=4 sw=4 et smartindent: */