Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief tpreturn function implementation.
0003  *
0004  * @file tpreturn.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 <stdlib.h>
0037 #include <memory.h>
0038 #include <setjmp.h>
0039 #include <errno.h>
0040 
0041 #include <atmi.h>
0042 #include <ndebug.h>
0043 #include <tperror.h>
0044 #include <typed_buf.h>
0045 #include <atmi_int.h>
0046 #include <srv_int.h>
0047 #include <gencall.h>
0048 #include <atmi_shm.h>
0049 
0050 #include <xa_cmn.h>
0051 #include <userlog.h>
0052 
0053 #include "atmi_tls.h"
0054 #include <ndrx_ddr.h>
0055 /*---------------------------Externs------------------------------------*/
0056 /*---------------------------Macros-------------------------------------*/
0057 /*---------------------------Enums--------------------------------------*/
0058 /*---------------------------Typedefs-----------------------------------*/
0059 /*---------------------------Globals------------------------------------*/
0060 /*---------------------------Statics------------------------------------*/
0061 /*---------------------------Prototypes---------------------------------*/
0062 
0063 /**
0064  * Detect are we still part of our transaction
0065  * @return EXSUCCEED/EXFAIL
0066  */
0067 exprivate int initiated_tran_attached(void)
0068 {
0069     if (NULL!=G_atmi_tls->G_atmi_xa_curtx.txinfo
0070             && (G_atmi_tls->G_atmi_xa_curtx.txinfo->tranid_flags & XA_TXINFO_INITIATOR)
0071             && !(ndrx_get_G_last_call()->sysflags & SYS_FLAG_AUTOTRAN))
0072     {
0073         return EXTRUE;
0074     }
0075     
0076     return EXFALSE;
0077 }
0078 
0079 /**
0080  * Internal version to tpreturn.
0081  * This is
0082  * TODO: If we are in thread, then disassoc of global txn must happen here!
0083  * In case if we are initiators of txn, and it is still running, we return
0084  * TPSVCERR. And transaction is aborted.
0085  * @param rval
0086  * @param rcode
0087  * @param data
0088  * @param len
0089  * @param flags
0090  */
0091 expublic void _tpreturn (int rval, long rcode, char *data, long len, long flags)
0092 {
0093     int ret=EXSUCCEED;
0094     char *buf=NULL; /**< physical place where to put the reply */
0095     size_t buf_len; /**< buf_len */
0096     tp_command_call_t *call;
0097     char fn[] = "_tpreturn";
0098     buffer_obj_t *buffer_info;
0099     long data_len;
0100     int return_status=0;
0101     char reply_to[NDRX_MAX_Q_SIZE+1] = {EXEOS};
0102     atmi_lib_conf_t *p_atmi_lib_conf = ndrx_get_G_atmi_conf();
0103     tp_conversation_control_t *p_accept_conn = ndrx_get_G_accepted_connection();
0104     tp_command_call_t * last_call;
0105     int was_auto_buf = EXFALSE;
0106     
0107     NDRX_LOG(log_debug, "%s enter data=%p", fn, data);
0108     last_call = ndrx_get_G_last_call();
0109     
0110     if (last_call->flags & TPNOREPLY)
0111     {
0112         NDRX_LOG(log_debug, "No reply required (TPNOREPLY) - return to main() "
0113                 "flags: %ld", last_call->flags);
0114         
0115         /* commit or abort .. if autotran was started */
0116         if (last_call->sysflags & SYS_FLAG_AUTOTRAN
0117             && tpgetlev())
0118         {
0119             /* try to commit */
0120             if (rval==TPSUCCESS)
0121             {
0122                 if (EXSUCCEED!=ndrx_tpcommit(0))
0123                 {
0124                     NDRX_LOG(log_error, "Auto commit failed: %s ", tpstrerror(tperrno));
0125                     userlog("Auto commit failed: %s", tpstrerror(tperrno));
0126                 }
0127             }
0128             else
0129             {
0130                 if (EXSUCCEED!=ndrx_tpabort(0, EXTRUE))
0131                 {
0132                     NDRX_LOG(log_error, "Auto abort failed: %s", tpstrerror(tperrno));
0133                     userlog("Auto abort failed: %s", tpstrerror(tperrno));
0134                 }
0135             }
0136         }
0137         
0138         /* If our tran is open, terminate it... */
0139         if (initiated_tran_attached())
0140         {
0141             NDRX_LOG(log_error, "Still in transaction [%s] - aborting",
0142                     G_atmi_tls->G_atmi_xa_curtx.txinfo->tmxid);
0143             userlog("Still in transaction [%s] - aborting",
0144                     G_atmi_tls->G_atmi_xa_curtx.txinfo->tmxid);
0145         
0146             if (EXSUCCEED!=ndrx_tpabort(0, EXTRUE))
0147             {
0148                 NDRX_LOG(log_error, "Auto abort failed: %s", tpstrerror(tperrno));
0149                 userlog("Auto abort failed: %s", tpstrerror(tperrno));
0150             }
0151         }
0152         
0153         goto out;
0154     }
0155 
0156     /* If our tran is open, terminate it... */
0157     if (initiated_tran_attached())
0158     {
0159         /* return TPESVCERR back to caller */
0160         rcode=TPESVCERR;
0161         flags=TPSOFTERR;
0162         
0163         NDRX_LOG(log_error, "Still in transaction [%s] - aborting, returning TPESVCERR",
0164                     G_atmi_tls->G_atmi_xa_curtx.txinfo->tmxid);
0165         userlog("Still in transaction [%s] - aborting, returning TPESVCERR",
0166                     G_atmi_tls->G_atmi_xa_curtx.txinfo->tmxid);
0167         if (EXSUCCEED!=ndrx_tpabort(0, EXTRUE))
0168         {
0169             NDRX_LOG(log_error, "Auto abort failed: %s", tpstrerror(tperrno));
0170             userlog("Auto abort failed: %s", tpstrerror(tperrno));
0171         }
0172     }
0173     
0174     /* client with last call is acceptable...! 
0175      * As it can be a server's companion thread
0176      */
0177     if (p_atmi_lib_conf->is_client && !last_call->cd)
0178     {
0179         /* this is client */
0180         NDRX_LOG(log_debug, "tpreturn is not available for clients "
0181                 "(is_client=%d, cd=%d)!!!", p_atmi_lib_conf->is_client, 
0182                 last_call->cd);
0183         ndrx_TPset_error_fmt(TPEPROTO, "tpreturn - not available for clients!!!");
0184         return; /* <<<< RETURN */
0185     }
0186     
0187     NDRX_SYSBUF_MALLOC_WERR_OUT(buf, buf_len, ret);
0188     call =(tp_command_call_t *)buf;
0189 
0190     memset(call, 0, sizeof(*call));
0191 
0192     close_open_client_connections(); /* disconnect any calls when we are clients */
0193 
0194     /* Set descriptor */
0195     call->cd = last_call->cd;
0196 
0197     if (CONV_IN_CONVERSATION==p_accept_conn->status)
0198     {
0199         call->cd-=NDRX_CONV_UPPER_CNT;
0200         call->msgseq = p_accept_conn->msgseqout;
0201         p_accept_conn->msgseqout++;
0202     }
0203 
0204     call->timestamp = last_call->timestamp;
0205     /* store the client timeout setting, so that bridge can drop on expiry */
0206     call->clttout = last_call->clttout;
0207     call->callseq = last_call->callseq;
0208     call->sysflags = 0; /* reset the flags. */
0209     
0210     /* TODO: put our call node id? As source which generated reply? */
0211 
0212     /* Send our queue path back 
0213     strcpy(call->reply_to, G_atmi_conf.reply_q_str);
0214     */
0215     /* Save original reply to path, so that bridge knows what to next */
0216     NDRX_STRCPY_SAFE(call->reply_to, last_call->reply_to);
0217     
0218     /* Mark as service failure. */
0219     if (TPSUCCESS!=rval)
0220     {
0221         return_status|=RETURN_SVC_FAIL;
0222     }
0223     
0224     if (last_call->sysflags & SYS_FLAG_AUTOTRAN
0225             && tpgetlev()) /* if we are in the transaction. */
0226     {
0227         /* tpcommit() or tpabort() 
0228          * at this point we need to ignore the ownership of the transaction.
0229          */
0230         if (rval==TPSUCCESS)
0231         {
0232             /* try to commit */
0233             if (EXSUCCEED!=ndrx_tpcommit(0))
0234             {
0235                 NDRX_LOG(log_error, "Auto commit failed: %s - returning TPESVCERR", 
0236                         tpstrerror(tperrno));
0237                 userlog("Auto commit failed: %s - returning TPESVCERR", 
0238                         tpstrerror(tperrno));
0239                 
0240                 call->sysflags |=SYS_FLAG_REPLY_ERROR;
0241                 call->rcode = TPESVCERR;
0242                 ret=EXFAIL;
0243                 goto out_send;
0244                 
0245             }
0246         }
0247         else
0248         {
0249             /* try to abort */
0250             if (EXSUCCEED!=ndrx_tpabort(0, EXTRUE))
0251             {
0252                 NDRX_LOG(log_error, "Auto abort failed: %s - returning TPESVCERR", 
0253                         tpstrerror(tperrno));
0254                 userlog("Auto abort failed: %s - returning TPESVCERR", 
0255                         tpstrerror(tperrno));
0256                 
0257                 call->sysflags |=SYS_FLAG_REPLY_ERROR;
0258                 call->rcode = TPESVCERR;
0259                 ret=EXFAIL;
0260                 goto out_send;
0261                 
0262             }
0263         }
0264         
0265     }
0266     /* work out the XA data */
0267     else if (ndrx_get_G_atmi_xa_curtx()->txinfo)
0268     {
0269         /* Update the list  
0270         strcpy(call->tmknownrms, ndrx_get_G_atmi_xa_curtx()->txinfo->tmknownrms);
0271         strcpy(call->tmxid, ndrx_get_G_atmi_xa_curtx()->txinfo->tmxid);
0272          * */
0273         XA_TX_COPY(call, ndrx_get_G_atmi_xa_curtx()->txinfo);
0274     }
0275     
0276     /* will override later */
0277     call->rcode = rcode;
0278     /* prepare reply buffer */
0279     if (TPFAIL==rval || TPSUCCESS==rval || TPEXIT==rval)
0280     {
0281         /* try convert the data */
0282         if (NULL==(buffer_info = ndrx_find_buffer(data)))
0283         {
0284             NDRX_LOG(log_error, "Err: No buffer as %p registered in system", data);
0285             /* set reply fail FLAG */
0286             call->sysflags |=SYS_FLAG_REPLY_ERROR;
0287             call->rcode = TPESVCERR;
0288             ret=EXFAIL;
0289         }
0290         else
0291         {
0292             /* Convert back, if convert flags was set */
0293             if (SYS_SRV_CVT_ANY_SET(last_call->sysflags))
0294             {
0295                 if (buffer_info == last_call->autobuf)
0296                 {
0297                     was_auto_buf=EXTRUE;
0298                 }
0299                 
0300                 NDRX_LOG(log_debug, "about reverse xcvt...");
0301                 /* Convert buffer back.. */
0302                 if (EXSUCCEED!=typed_xcvt(&buffer_info, last_call->sysflags, EXTRUE))
0303                 {
0304                     NDRX_LOG(log_debug, "Failed to convert buffer back to "
0305                             "callers format: %llx", last_call->sysflags);
0306                     userlog("Failed to convert buffer back to "
0307                             "callers format: %llx", last_call->sysflags);
0308                     /* set reply fail FLAG */
0309                     call->sysflags |=SYS_FLAG_REPLY_ERROR;
0310                     call->rcode = TPESVCERR;
0311                     ret=EXFAIL;
0312                 }
0313                 else
0314                 {
0315                     data = buffer_info->buf;
0316                     /* Assume that length not used for self describing buffers */
0317                     /* Bug #250 restore auto buf if was so... */
0318                     if (was_auto_buf)
0319                     {
0320                         last_call->autobuf = buffer_info;
0321                     }
0322                 }
0323             }
0324             
0325             if (EXFAIL!=ret)
0326             {
0327                 /* otherwise cannot generate error */
0328                 call->data_len = MAX_CALL_DATA_SIZE;
0329                 /* build reply data here */
0330                 if (EXFAIL==ndrx_mbuf_prepare_outgoing (data, 
0331                             len, call->data, &call->data_len, flags, 0)
0332                         )
0333                 {
0334                     /* set reply fail FLAG */
0335                     call->sysflags |=SYS_FLAG_REPLY_ERROR;
0336                     call->rcode = TPESYSTEM;
0337                     ret=EXFAIL;
0338                 }
0339             }
0340         }
0341     }
0342     else
0343     {
0344         /* no data in reply */
0345         call->data_len = 0;
0346     }
0347     
0348 out_send:    
0349     /* Feature #594 */
0350     if (TPEXIT==rval)
0351     {
0352         call->rval = TPFAIL;
0353     }
0354     else
0355     {
0356         call->rval = rval;
0357     }
0358 
0359     data_len = sizeof(tp_command_call_t)+call->data_len;
0360     call->command_id = ATMI_COMMAND_TPREPLY;
0361     
0362     /* If this is gateway timeout, then set the flags accordingly */
0363     
0364     if (flags & TPSOFTTIMEOUT)
0365     {
0366         NDRX_LOG(log_error, "TPSOFTTIMEOUT present -> returning service error TPETIME!");
0367         call->sysflags |=SYS_FLAG_REPLY_ERROR;
0368         call->rcode = TPETIME;
0369         ret=EXFAIL;
0370     } 
0371     else if (flags & TPSOFTENOENT)
0372     {
0373         NDRX_LOG(log_error, "TPSOFTENOENT present -> returning service error TPENOENT!");
0374         call->sysflags |=SYS_FLAG_REPLY_ERROR;
0375         call->rcode = TPENOENT;
0376         ret=EXFAIL;
0377     }
0378     else if (flags & TPSOFTERR)
0379     {
0380         NDRX_LOG(log_error, "TPSOFTERR present -> returning service "
0381                 "error code: %ld", call->rcode);
0382         call->sysflags |=SYS_FLAG_REPLY_ERROR;
0383         ret=EXFAIL;
0384     }
0385     
0386     /* keep the timer from last call. */
0387     call->timer = last_call->timer;
0388     
0389     /* Get the reply order... */
0390     NDRX_STRCPY_SAFE(call->callstack, last_call->callstack);
0391     if (EXSUCCEED!=fill_reply_queue(call->callstack, last_call->reply_to, reply_to))
0392     {
0393         NDRX_LOG(log_error, "ATTENTION!! Failed to get reply queue");
0394         goto out;
0395     }
0396     
0397     /* Needs some hint for multi-threaded bridge
0398      * To choose reply thread (all convs goes to thread number = cd % workers_count
0399      */
0400     if (CONV_IN_CONVERSATION==p_accept_conn->status)
0401     {
0402         call->sysflags |=SYS_CONVERSATION;
0403     }
0404     
0405     /* well if we are in global TX we shall disconnect/end here
0406      * otherwise tmsrv might get locked txn..
0407      */
0408     if (ndrx_get_G_atmi_xa_curtx()->txinfo)
0409     {
0410         int end_fail=EXFALSE;
0411         int prop_fail = EXFALSE;
0412         
0413         if (ndrx_get_G_atmi_xa_curtx()->txinfo->tmtxflags & TMTXFLAGS_IS_ABORT_ONLY)
0414         {
0415             prop_fail=EXTRUE;
0416         }
0417         
0418         _tp_srv_disassoc_tx(EXFALSE, &end_fail);
0419         
0420         if (prop_fail || end_fail)
0421         {
0422             if (end_fail)
0423             {
0424                 NDRX_LOG(log_error, "Marking transaction as abort only "
0425                         "due to xa_end() failure");
0426             }
0427             /* propagate back to caller */
0428             call->tmtxflags|=TMTXFLAGS_IS_ABORT_ONLY;
0429         }
0430     }
0431     
0432     /* send the reply back actually */
0433     NDRX_LOG(log_debug, "Returning to %s cd %d, timestamp %d, callseq: %u, rval: %d, rcode: %ld",
0434                             reply_to, call->cd, call->timestamp, call->callseq,
0435                             call->rval, call->rcode);
0436 
0437     /* TODO: Chose the cluster node to send to, Scan the stack, to find
0438      * the closest reply node... We might event not to pop the stack.
0439      * But each node searches for closest path, from right to left.
0440      */
0441     if (EXFAIL==ndrx_generic_q_send(reply_to, (char *)call, data_len, flags, 0))
0442     {
0443         NDRX_LOG(log_error, "ATTENTION!! Reply to queue [%s] failed!",
0444                                             reply_to);
0445         goto out;
0446     }
0447 
0448     /* Wait for ack if we run in conversation */
0449     if (CONV_IN_CONVERSATION==p_accept_conn->status)
0450     {
0451         /* If this is conversation, then we should release conversation queue */
0452         normal_connection_shutdown(p_accept_conn, EXFALSE, "tpreturn on open conversation");
0453     }
0454 
0455 out:
0456     
0457     if (NULL!=buf)
0458     {
0459         NDRX_SYSBUF_FREE(buf);
0460         buf = NULL;
0461     }
0462 
0463     /* Hmm we can free up the data? 
0464      * - well mvitolin 16/01/2017 - only auto buffers & this one.
0465      * Not sure how with Tuxedo multi-threading?
0466      * - mvitolin 03/03/2017 - will make free any buffer
0467      * 
0468      * - mvitolin 01/07/2019 - with NULL buffers (which are real NULLs we have
0469      * an issue). Because for those there are is no pointer descriptor object.
0470      * thus if prepare incoming NULL did de-reallocate the object, then we
0471      * never know it. Thus in this case all prepare incomings if doing buffer
0472      * free, shall check the last call and reset the auto buf.
0473      */
0474     if (NULL!=data)
0475     {
0476         if (NULL!=last_call->autobuf && last_call->autobuf->buf==data)
0477         {
0478             last_call->autobuf=NULL;
0479         }
0480         NDRX_LOG(log_debug, "%s free buffer %p", fn, data);
0481         ndrx_tpfree(data, NULL);
0482     }
0483 
0484     if (NULL!=last_call->autobuf)
0485     {
0486         NDRX_LOG(log_debug, "%s free auto buffer %p", fn, last_call->autobuf->buf);
0487         ndrx_tpfree(last_call->autobuf->buf, NULL);
0488         last_call->autobuf = NULL;
0489     }
0490 
0491     /* server thread, no long jump... (thread should kill it self.)*/
0492     if (!(last_call->sysflags & SYS_SRV_THREAD))
0493     {        
0494          return_status|=RETURN_TYPE_TPRETURN;
0495          if (EXFAIL==ret)
0496              return_status|=RETURN_FAILED;
0497 
0498         if (G_libatmisrv_flags & ATMI_SRVLIB_NOLONGJUMP)
0499         {
0500             NDRX_LOG(log_debug, "%s normal return to main - no longjmp", fn);
0501             G_atmi_tls->atmisrv_reply_type = return_status;
0502         }
0503         else
0504         {
0505             NDRX_LOG(log_debug, "%s about to jump to main()", fn);
0506             
0507             /* initiate shutdown ... if requested so ... */
0508             if (TPEXIT==rval)
0509             {
0510                 tpexit();
0511             }
0512             longjmp(G_atmi_tls->call_ret_env, return_status);
0513         }
0514     }
0515     else
0516     {
0517         NDRX_LOG(log_debug, "Thread ending...");
0518     }
0519 
0520     /* initiate shutdown ... if requested so.. */
0521     if (TPEXIT==rval)
0522     {
0523         tpexit();
0524     }
0525 
0526     return;
0527 }
0528 
0529 /**
0530  * Forward the call to next service
0531  * @param svc
0532  * @param data
0533  * @param len
0534  * @param flags - should be managed from parent function (is it real async call
0535  *                  or tpcall wrapper)
0536  * @return SUCCEED/FAIL
0537  */
0538 expublic void _tpforward (char *svc, char *data,
0539                 long len, long flags)
0540 {
0541     int ret=EXSUCCEED;
0542     char *buf = NULL;
0543     size_t buf_len;
0544     tp_command_call_t *call;
0545     buffer_obj_t *buffer_info;
0546     char fn[] = "_tpforward";
0547     long data_len = MAX_CALL_DATA_SIZE;
0548     char send_q[NDRX_MAX_Q_SIZE+1];
0549     long return_status=0;
0550     int is_bridge;
0551     tp_command_call_t * last_call;
0552     int was_auto_buf = EXFALSE;
0553     atmi_lib_conf_t *p_atmi_lib_conf = ndrx_get_G_atmi_conf();
0554     int prio = NDRX_MSGPRIO_DEFAULT;
0555     tp_conversation_control_t *p_accept_conn = ndrx_get_G_accepted_connection();
0556     char svcddr[XATMI_SERVICE_NAME_LENGTH+1]; /**< routed service name */
0557     
0558     NDRX_LOG(log_debug, "%s enter", fn);
0559     
0560     last_call = ndrx_get_G_last_call();
0561 
0562     NDRX_STRCPY_SAFE(svcddr, svc);
0563     
0564     /* abort / tpreturn transaction if we are initiator & transaction
0565      * is still started
0566      */
0567     if (initiated_tran_attached())
0568     {
0569         NDRX_LOG(log_error, "Cannot forward to [%s] - initiated transaction [%s] is attached",
0570                 svc, G_atmi_tls->G_atmi_xa_curtx.txinfo->tmxid);
0571         
0572         /* pass the data fields to, as these shall be freed */
0573         _tpreturn(TPFAIL, TPESVCERR, data, len, TPSOFTERR);
0574     return;
0575     }
0576     
0577     /* try the DDR */
0578     if (EXFAIL==ndrx_ddr_grp_get(svcddr, sizeof(svcddr), data, len,
0579         &prio))
0580     {
0581         /* error shall be set */
0582         EXFAIL_OUT(ret);
0583     }
0584     
0585     /* client with last call is acceptable...! 
0586      * It can be servers companion thread.
0587      * TODO: Add the check.
0588      */
0589     if (p_atmi_lib_conf->is_client && !last_call->cd)
0590     {
0591         /* this is client */
0592         NDRX_LOG(log_debug, "tpforward is not available for clients "
0593                 "(is_client=%d, cd=%d)!!!", p_atmi_lib_conf->is_client, 
0594                 last_call->cd);
0595         ndrx_TPset_error_fmt(TPEPROTO, "tpforward - not available for clients!!!");
0596         return; /* <<<< RETURN */
0597     }
0598     
0599     /* Cannot do the forward if we are in conversation! */
0600     if (CONV_IN_CONVERSATION==p_accept_conn->status ||
0601             have_open_connection())
0602     {
0603         ndrx_TPset_error_fmt(TPEPROTO, "tpforward no allowed for conversation server!");
0604     return;
0605     }
0606     
0607     NDRX_SYSBUF_MALLOC_WERR_OUT(buf, buf_len, ret);
0608     call = (tp_command_call_t *)buf;
0609     
0610     memset(call, 0, sizeof(*call)); /* have some safety net */
0611 
0612     call->data_len = MAX_CALL_DATA_SIZE;
0613 
0614     if (NULL==(buffer_info = ndrx_find_buffer(data)))
0615     {
0616         ndrx_TPset_error_fmt(TPEINVAL, "Buffer %p not known to system!", fn);
0617         ret=EXFAIL;
0618         goto out;
0619     }
0620     
0621     /* Convert back, if convert flags was set */
0622     if (SYS_SRV_CVT_ANY_SET(last_call->sysflags))
0623     {
0624         if (buffer_info == last_call->autobuf)
0625         {
0626             was_auto_buf=EXTRUE;
0627         }
0628         
0629         NDRX_LOG(log_debug, "about reverse xcvt...");
0630         /* Convert buffer back.. */
0631         if (EXSUCCEED!=typed_xcvt(&buffer_info, last_call->sysflags, EXTRUE))
0632         {
0633             NDRX_LOG(log_debug, "Failed to convert buffer back to "
0634                     "callers format: %llx", last_call->sysflags);
0635             userlog("Failed to convert buffer back to "
0636                     "callers format: %llx", last_call->sysflags);
0637             ret=EXFAIL;
0638             goto out;
0639         }
0640         else
0641         {
0642             data = buffer_info->buf;
0643             /* Assume that length not used for self describing buffers */
0644             /* Bug #250 restore auto buf if was so... */
0645             if (was_auto_buf)
0646             {
0647                 last_call->autobuf = buffer_info;
0648             }
0649         }
0650     }
0651 
0652     /* prepare buffer for call 
0653      * TODO: should we check call/buf (buf_len) buffer output size?
0654      */
0655     if (EXSUCCEED!=ndrx_mbuf_prepare_outgoing(data, len, call->data, &data_len, flags, 0L))
0656     {
0657         /* not good - error should be already set */
0658         ret=EXFAIL;
0659         goto out;
0660     }
0661     
0662     /* OK, now fill up the details */
0663     call->data_len = data_len;
0664 
0665     data_len+=sizeof(tp_command_call_t);
0666 
0667     NDRX_STRCPY_SAFE(call->reply_to, last_call->reply_to); /* <<< main difference from call! */
0668     
0669     call->clttout = last_call->clttout; /* store the client timeout setting */
0670     call->command_id = ATMI_COMMAND_TPCALL;
0671 
0672     NDRX_STRNCPY(call->name, svcddr, XATMI_SERVICE_NAME_LENGTH);
0673     call->name[XATMI_SERVICE_NAME_LENGTH] = EXEOS;
0674     call->flags = last_call->flags; /* preserve the original call flags Bug #570 */
0675     call->cd = last_call->cd; /* <<< another difference from call! */
0676     call->timestamp = last_call->timestamp;
0677     call->callseq = last_call->callseq;
0678     NDRX_STRCPY_SAFE(call->callstack, last_call->callstack);
0679     
0680     /* TODO: forward the indication of syste but only if we are in the transaction at the momment */
0681     call->sysflags|= (last_call->sysflags & SYS_FLAG_AUTOTRAN);
0682     
0683     /* work out the XA data */
0684     if (ndrx_get_G_atmi_xa_curtx()->txinfo)
0685     {
0686         /* Copy TX data */
0687         XA_TX_COPY(call, ndrx_get_G_atmi_xa_curtx()->txinfo);
0688     }
0689     
0690 #if 0
0691     - moved ot tmisabortonly.
0692     /* If we have global transaction & failed. Then set abort only flag 
0693      * On the other side, receiver should mark it's global tx too
0694      * as abort only.
0695      */
0696     if (ndrx_get_G_atmi_xa_curtx()->txinfo && ndrx_get_G_atmi_xa_curtx()->txinfo->tmisabortonly)
0697     {
0698         call->sysflags|=SYS_XA_ABORT_ONLY;
0699     }
0700 #endif
0701     
0702     /* Want to keep original call time... */
0703     memcpy(&call->timer, &last_call->timer, sizeof(call->timer));
0704     
0705     /* Hmm we can free up the data? - do it here because we still need buffer_info!
0706      * ???? NOTE HERE! Bug #250 - all job is done bellow!
0707     if (NULL!=data)
0708     {
0709         ndrx_tpfree(data, NULL);
0710     }
0711     *
0712     */
0713     /* Check is service available? */
0714     if (EXSUCCEED!=ndrx_shm_get_svc(call->name, send_q, &is_bridge, NULL))
0715     {
0716         NDRX_LOG(log_error, "Service is not available %s by shm", 
0717                 call->name);
0718         ret=EXFAIL;
0719         ndrx_TPset_error_fmt(TPENOENT, "%s: Service is not available %s by shm", 
0720                 fn, call->name);
0721                 /* we should reply back, that call failed, so that client does not wait */
0722         reply_with_failure(flags, last_call, NULL, NULL, TPESVCERR);
0723         goto out;
0724     }
0725     
0726     /* well if we are in global TX we shall disconnect/end here
0727      * otherwise tmsrv might get locked txn..
0728      */
0729     if (ndrx_get_G_atmi_xa_curtx()->txinfo)
0730     {
0731         int end_fail=EXFALSE;
0732         int prop_fail = EXFALSE;
0733         
0734         if (ndrx_get_G_atmi_xa_curtx()->txinfo->tmtxflags & TMTXFLAGS_IS_ABORT_ONLY)
0735         {
0736             prop_fail=EXTRUE;
0737         }
0738         
0739         _tp_srv_disassoc_tx(EXFALSE, &end_fail);
0740         
0741         if (prop_fail || end_fail)
0742         {
0743             if (end_fail)
0744             {
0745                 NDRX_LOG(log_error, "Marking transaction as abort only "
0746                         "due to xa_end() failure");
0747             }
0748             /* propagate back to caller */
0749             call->tmtxflags|=TMTXFLAGS_IS_ABORT_ONLY;
0750         }
0751     }
0752 
0753     NDRX_LOG(log_debug, "Forwarding cd %d, timestamp %d, callseq %u to %s",
0754                     call->cd, call->timestamp, call->callseq, send_q);
0755         
0756     if (EXSUCCEED!=(ret=ndrx_generic_q_send(send_q, (char *)call, data_len, flags, prio)))
0757     {
0758         /* reply FAIL back to caller! */
0759         int err;
0760 
0761         /* basically we override some conditions here! */
0762         if (ENOENT==ret)
0763         {
0764             err=TPENOENT;
0765         }
0766         else
0767         {
0768             CONV_ERROR_CODE(ret, err);
0769         }
0770 
0771         ndrx_TPset_error_fmt(err, "%s: Failed to send, os err: %s", fn, strerror(ret));
0772         userlog("%s: Failed to send, os err: %s", fn, strerror(ret));
0773         ret=EXFAIL;
0774 
0775         /* we should reply back, that call failed, so that client does not wait */
0776         reply_with_failure(flags, last_call, NULL, NULL, TPESVCERR);
0777     }
0778 
0779 out:
0780 
0781     if (NULL!=buf)
0782     {
0783         NDRX_SYSBUF_FREE(buf);
0784     }
0785 
0786     if (NULL!=data)
0787     {
0788         /* Lookup the buffer infos for data, and then compare with autobuf!
0789          * as the last_call autobuf might be already free - the same for tpforward
0790          * for xcv -> update the autobuf if changed auto buf...
0791          */
0792         if (last_call->autobuf && last_call->autobuf->buf==data)
0793         {
0794             last_call->autobuf=NULL;
0795         }
0796         NDRX_LOG(log_debug, "%s free buffer %p", fn, data);
0797         ndrx_tpfree(data, NULL);
0798     }
0799 
0800     if (last_call->autobuf)
0801     {
0802         NDRX_LOG(log_debug, "%s free auto buffer %p", fn, last_call->autobuf->buf);
0803         ndrx_tpfree(last_call->autobuf->buf, NULL);
0804         last_call->autobuf = NULL;
0805     }
0806 
0807     NDRX_LOG(log_debug, "%s return %d (information only)", fn, ret);
0808 
0809     /* server thread, no long jump... (thread should kill it self.)*/
0810     if (!(last_call->sysflags & SYS_SRV_THREAD))
0811     {
0812         return_status|=RETURN_TYPE_TPFORWARD;
0813         if (EXFAIL==ret)
0814             return_status|=RETURN_FAILED;
0815         
0816         if (G_libatmisrv_flags & ATMI_SRVLIB_NOLONGJUMP)
0817         {
0818             NDRX_LOG(log_debug, "%s normal return to main - no longjmp", fn);
0819             G_atmi_tls->atmisrv_reply_type = return_status;
0820         }
0821         else 
0822         {
0823             NDRX_LOG(log_debug, "%s longjmp to main()", fn);
0824             longjmp(G_atmi_tls->call_ret_env, return_status);
0825         }
0826     }
0827     else
0828     {
0829         NDRX_LOG(log_debug, "Thread ending...");
0830     }
0831     
0832     return;
0833 }
0834 
0835 /**
0836  * Task is copied to thread.
0837  * The main thread goes back to polling.
0838  */
0839 expublic void _tpcontinue (void)
0840 {
0841     
0842     /* shall we abort transaction, if not terminated? */
0843     
0844     /* mvitolin 11.01.2017 
0845      * We can do thing when we are not running in integration mode!
0846      */
0847     if (G_libatmisrv_flags & ATMI_SRVLIB_NOLONGJUMP)
0848     {
0849        NDRX_LOG(log_debug, "Not jumping - as integra mode!");
0850        G_atmi_tls->atmisrv_reply_type|=RETURN_TYPE_THREAD;
0851     }
0852     else 
0853     {
0854         long return_status=0;
0855         return_status|=RETURN_TYPE_THREAD;
0856         
0857         NDRX_LOG(log_debug, "Long jumping to continue!");
0858         longjmp(G_atmi_tls->call_ret_env, return_status);
0859         /* NDRX_LOG(log_error, "doing nothing after long jmp!"); - not reached. */
0860     }
0861 }
0862 /* vim: set ts=4 sw=4 et smartindent: */