Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief General routines for handling buffer conversation
0003  *
0004  * @file typed_buf.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 <errno.h>
0038 #include <sys_primitives.h>
0039 #include <utlist.h>
0040 
0041 #include <atmi.h>
0042 #include <atmi_int.h>
0043 #include <ubf.h>
0044 #include <ndrstandard.h>
0045 #include <atmi_int.h>
0046 #include <typed_buf.h>
0047 #include <ndebug.h>
0048 #include <thlock.h> /* muli thread support */
0049 #include <typed_string.h>
0050 #include <typed_json.h>
0051 #include <typed_carray.h>
0052 #include <typed_view.h>
0053 #include <tperror.h>
0054 #include <tpadm.h>
0055 
0056 #include "atmi_tls.h"
0057 /*---------------------------Externs------------------------------------*/
0058 /*---------------------------Macros-------------------------------------*/
0059 /*---------------------------Enums--------------------------------------*/
0060 /*---------------------------Typedefs-----------------------------------*/
0061 /*---------------------------Globals------------------------------------*/
0062 exprivate buffer_obj_t * find_buffer_int(char *ptr);
0063 /*
0064  * Buffers allocated by process
0065  */
0066 expublic buffer_obj_t *ndrx_G_buffers=NULL;
0067 
0068 exprivate MUTEX_LOCKDECL(M_lock); /* This will allow multiple reads */
0069 
0070 /*
0071  * Buffer descriptors
0072  */
0073 expublic typed_buffer_descr_t G_buf_descr[] =
0074 {
0075     {BUF_TYPE_UBF,   "UBF",     "FML",     NULL, UBF_prepare_outgoing, UBF_prepare_incoming,
0076                                 UBF_tpalloc, UBF_tprealloc, UBF_tpfree, UBF_test},
0077     /* Support for FB32... */
0078     {BUF_TYPE_UBF,   "UBF32",     "FML32",     NULL, UBF_prepare_outgoing, UBF_prepare_incoming,
0079                                 UBF_tpalloc, UBF_tprealloc, UBF_tpfree, UBF_test},
0080     {BUF_TYPE_INIT,  "TPINIT",  NULL,      NULL,             NULL,            NULL,
0081                                 TPINIT_tpalloc, NULL, TPINIT_tpfree, NULL},
0082                                 
0083     {BUF_TYPE_NULL,  "NULL",  NULL,      NULL, TPNULL_prepare_outgoing,  TPNULL_prepare_incoming,
0084                                 TPNULL_tpalloc, NULL, TPNULL_tpfree, NULL},
0085                                 
0086     {BUF_TYPE_STRING,   "STRING", NULL,     NULL, STRING_prepare_outgoing, STRING_prepare_incoming,
0087                                 STRING_tpalloc, STRING_tprealloc, STRING_tpfree, STRING_test},
0088                                 
0089     {BUF_TYPE_CARRAY,   "CARRAY", "X_OCTET", NULL, CARRAY_prepare_outgoing, CARRAY_prepare_incoming,
0090                                 CARRAY_tpalloc, CARRAY_tprealloc, CARRAY_tpfree, CARRAY_test},
0091     {BUF_TYPE_JSON,   "JSON", NULL,     NULL, JSON_prepare_outgoing, JSON_prepare_incoming,
0092                                 JSON_tpalloc, JSON_tprealloc, JSON_tpfree, JSON_test},
0093     {BUF_TYPE_VIEW,   "VIEW", "VIEW32",     NULL, VIEW_prepare_outgoing, VIEW_prepare_incoming,
0094                                 VIEW_tpalloc, VIEW_tprealloc, VIEW_tpfree, VIEW_test},
0095     {EXFAIL}
0096 };
0097 
0098 /*---------------------------Statics------------------------------------*/
0099     
0100 /*---------------------------Prototypes---------------------------------*/
0101 
0102 /**
0103  * Compares two buffers in linked list (for search purposes)
0104  * @param a
0105  * @param b
0106  * @return 0 - equal/ -1 - not equal
0107  */
0108 exprivate int buf_ptr_cmp_fn(buffer_obj_t *a, buffer_obj_t *b)
0109 {
0110     return (a->buf==b->buf?EXSUCCEED:EXFAIL);
0111 }
0112 
0113 
0114 /**
0115  * List currently allocated XATMI buffers
0116  * @param list buffer list (pointers to actual data storage, not the index entries)
0117  * @return EXSUCCEED (caller must free list)/EXFAIL (list is not alloc)
0118  */
0119 expublic int ndrx_buffer_list(ndrx_growlist_t *list)
0120 {
0121     int ret = EXSUCCEED;
0122     int i = 0;
0123     buffer_obj_t *elt, *tmp;
0124     
0125     ndrx_growlist_init(list, 100, sizeof(void *));
0126     
0127     MUTEX_LOCK_V(M_lock);
0128     EXHASH_ITER(hh,ndrx_G_buffers,elt,tmp) 
0129     {
0130         ndrx_growlist_add(list, elt->buf, i);
0131         i++;
0132     }
0133     MUTEX_UNLOCK_V(M_lock);
0134     
0135 out:
0136         
0137     if (EXSUCCEED!=ret)
0138     {
0139         ndrx_growlist_free(list);
0140     }
0141 
0142     return ret;
0143 }
0144 
0145 
0146 /**
0147  * Find the buffer in list of known buffers
0148  * Public version, uses locking...
0149  * TODO: might want to optimize, so that multiple paralel reads are allowed
0150  * while there is no write...
0151  * @param ptr
0152  * @return NULL - buffer not found/ptr - buffer found
0153  */
0154 expublic buffer_obj_t * ndrx_find_buffer(char *ptr)
0155 {
0156     buffer_obj_t *ret;
0157    
0158     if (NULL==ptr)
0159     {
0160         return &G_atmi_tls->nullbuf;
0161     }
0162     
0163     MUTEX_LOCK_V(M_lock);
0164     EXHASH_FIND_PTR( ndrx_G_buffers, ((void **)&ptr), ret);
0165     MUTEX_UNLOCK_V(M_lock);
0166     
0167     return ret;
0168     
0169 }
0170 
0171 /**
0172  * Find the buffer in list of known buffers
0173  * Internal version, no locking used.
0174  * TODO: Move buffer registry to hash function
0175  * @param ptr
0176  * @return NULL - buffer not found/ptr - buffer found
0177  */
0178 exprivate buffer_obj_t * find_buffer_int(char *ptr)
0179 {
0180     buffer_obj_t *ret=NULL;
0181 
0182     /*
0183     eltmp.buf = ptr;
0184     DL_SEARCH(G_buffers, ret, &eltmp, buf_ptr_cmp_fn);
0185     */
0186     
0187     if (NULL==ptr)
0188     {
0189         return &G_atmi_tls->nullbuf;
0190     }
0191     
0192     EXHASH_FIND_PTR( ndrx_G_buffers, ((void **)&ptr), ret);
0193     
0194     return ret;
0195 }
0196 
0197 /**
0198  * Return the descriptor of typed buffer or NULL in case of error.
0199  * @param type - type to search for ( must be present )
0200  * @param subtype - may be NULL
0201  * @return NULL/or ptr to G_buf_descr[X]
0202  */
0203 expublic typed_buffer_descr_t * ndrx_get_buffer_descr(char *type, char *subtype)
0204 {
0205     typed_buffer_descr_t *p=G_buf_descr;
0206     typed_buffer_descr_t *ret = NULL;
0207 
0208     while (EXFAIL!=p->type_id)
0209     {
0210         if ((NULL!=p->type && 0==strcmp(p->type, type)) || 
0211                         (NULL!=p->alias && 0==strcmp(p->alias, type)) ||
0212                         p->type == type /*NULL buffer*/)
0213         {
0214             /* subtype is passed to the type engine.. */
0215             ret=p;
0216             break;
0217         }
0218         p++;
0219     }
0220     return ret;
0221 }
0222 
0223 /**
0224  * Internal version of tpalloc
0225  * @param type
0226  * @param subtype
0227  * @param len
0228  * @return
0229  */
0230 expublic char * ndrx_tpalloc (typed_buffer_descr_t *known_type,
0231                     char *type, char *subtype, long len)
0232 {
0233     char *ret=NULL;
0234     typed_buffer_descr_t *usr_type = NULL;
0235     buffer_obj_t *node;
0236     
0237     NDRX_LOG(log_debug, "%s: type=%s, subtype=%s len=%d",  
0238             __func__, (NULL==type?"NULL":type),
0239             (NULL==subtype?"NULL":subtype), len);
0240     
0241     if (NULL==known_type)
0242     {
0243         if (NULL==(usr_type = ndrx_get_buffer_descr(type, subtype)))
0244         {
0245             ndrx_TPset_error_fmt(TPEOTYPE, "Unknown type (%s)/subtype(%s)", 
0246                     (NULL==type?"NULL":type), (NULL==subtype?"NULL":subtype));
0247             ret=NULL;
0248             goto out;
0249         }
0250     }
0251     else
0252     {
0253         /* will re-use known type */
0254         usr_type = known_type;
0255     }
0256 
0257     /* now allocate the memory  */
0258     if (NULL==(ret=usr_type->pf_alloc(usr_type, subtype, &len)))
0259     {
0260         /* error detail should be already set */
0261         goto out;
0262     }
0263 
0264     /* now append the memory list with allocated block */
0265     if (NULL==(node=(buffer_obj_t *)NDRX_FPMALLOC(sizeof(buffer_obj_t), 0)))
0266     {
0267         ndrx_TPset_error_fmt(TPEOS, "%s: Failed to allocate buffer list node: %s",  __func__,
0268                                         strerror(errno));
0269         ret=NULL;
0270 
0271         goto out;
0272     }
0273 
0274     /* Now append the list */
0275     memset(node, 0, sizeof(buffer_obj_t));
0276 
0277     node->buf = ret;
0278     NDRX_LOG(log_debug, "%s: type=%s subtype=%s len=%d allocated=%p", 
0279              __func__, usr_type->type,
0280             (NULL==subtype?"NULL":subtype),
0281             len, ret);
0282     node->size = len;
0283     
0284     node->type_id = usr_type->type_id;
0285     
0286     if (NULL==subtype)
0287     {
0288         node->subtype[0] = EXEOS;
0289     }
0290     else
0291     {
0292         NDRX_STRCPY_SAFE(node->subtype, subtype);
0293     }
0294 
0295     MUTEX_LOCK_V(M_lock);
0296     /* Save the allocated buffer in the list */
0297     /* DL_APPEND(G_buffers, node); */
0298     EXHASH_ADD_PTR(ndrx_G_buffers, buf, node);
0299     MUTEX_UNLOCK_V(M_lock);
0300 
0301 out:
0302     
0303     return ret;
0304 }
0305 
0306 /**
0307  * Internal version of tprealloc
0308  * @param buf
0309  * @param
0310  * @return
0311  */
0312 expublic char * ndrx_tprealloc (char *buf, long len)
0313 {
0314     char *ret=NULL;
0315     buffer_obj_t * node;
0316     typed_buffer_descr_t *buf_type = NULL;
0317 
0318     NDRX_LOG(log_debug, "%s buf=%p, len=%ld",  __func__, buf, len);
0319 
0320     if (NULL==buf)
0321     {
0322         /* No realloc for NULL buffer */
0323         goto out_nolock;
0324     }
0325     
0326     if (NULL==(node=ndrx_find_buffer(buf)))
0327     {
0328         MUTEX_UNLOCK_V(M_lock);
0329          ndrx_TPset_error_fmt(TPEINVAL, "%s: Buffer %p is not know to system",  
0330                  __func__, buf);
0331         ret=NULL;
0332         goto out;
0333     }
0334     
0335     NDRX_LOG(log_debug, "%s buf=%p autoalloc=%hd", 
0336                          __func__, buf, node->autoalloc);
0337 
0338     buf_type = &G_buf_descr[node->type_id];
0339     /* remove from hash, to avoid address reuse
0340      * i.e. old address after realloc gets used
0341      * by new thread which adds similar to block
0342      * to hash. Possible colisions in the hash list
0343      * but that would be needed to test seperatelly
0344     */
0345     MUTEX_LOCK_V(M_lock);
0346     EXHASH_DEL(ndrx_G_buffers, node);
0347     MUTEX_UNLOCK_V(M_lock);
0348 
0349     /*
0350      * Do the actual buffer re-allocation!
0351      */
0352     if (NULL==(ret=buf_type->pf_realloc(buf_type, buf, len)))
0353     {
0354         ret=NULL;
0355         goto out;
0356     }
0357 
0358     node->buf = ret;
0359     
0360     /* update the hash list */
0361     MUTEX_LOCK_V(M_lock);
0362     EXHASH_ADD_PTR(ndrx_G_buffers, buf, node);
0363     MUTEX_UNLOCK_V(M_lock);
0364     
0365     node->size = len;
0366 
0367 out:
0368     
0369 out_nolock:
0370     return ret;
0371     
0372 }
0373 
0374 /**
0375  * Scan buffer in recurs
0376  * @param p_ub
0377  * @param flist free list (ptrs to be freed)
0378  */
0379 exprivate void scan_ptrs(UBFH *p_ub, ndrx_buf_free_lists_t *flist)
0380 {
0381     int ret = EXSUCCEED;
0382     Bnext_state_t state;
0383     BFLDID bfldid=BBADFLDOCC;
0384     BFLDOCC occ;
0385     char *d_ptr;
0386     char **lptr;
0387     int ftyp;
0388 
0389     ndrx_mbuf_Bnext_ptr_first(p_ub, &state);
0390 
0391     while (EXTRUE==(ret=ndrx_Bnext(&state, p_ub, &bfldid, &occ, NULL, NULL, &d_ptr)))
0392     {
0393         ftyp = bfldid >> EFFECTIVE_BITS;
0394         
0395         if (BFLD_PTR==ftyp)
0396         {
0397             /* add ptr, if dest is UBF... scan it too...
0398              */
0399             lptr=(char **)d_ptr;
0400             
0401             if (NULL!=*lptr)
0402             {
0403                 buffer_obj_t *buf = ndrx_find_buffer(*lptr);
0404                 
0405                 if (NULL!=buf && BUF_TYPE_UBF==buf->type_id)
0406                 {
0407                     /* go into... */
0408                     scan_ptrs((UBFH *)*lptr, flist);
0409                 }
0410             }
0411             
0412             /* add to free list if not main & not already in the list... */
0413             if (NULL!=*lptr && 
0414                     *lptr!=flist->mainbuf && 
0415                     NULL==ndrx_mbuf_ptr_find(&flist->ptrs_hash, *lptr))
0416             {
0417                 /* nothing if fails... might leak something at worst */
0418                 ndrx_mbuf_ptr_add(&flist->ptrs_hash, *lptr, EXFAIL);
0419             }
0420         }
0421         else if (BFLD_UBF==ftyp)
0422         {
0423             scan_ptrs((UBFH *)d_ptr, flist);
0424         }
0425     }
0426 }
0427 
0428 /**
0429  * Inner free called by recursive operations
0430  * @param buf buffer to free up
0431  * @param known_buffer ?
0432  * @param flist infos about master buffer and already free'd ptrs...
0433  */
0434 expublic void ndrx_tpfree_inner (char *buf, buffer_obj_t *known_buffer, ndrx_buf_free_lists_t *flist)
0435 {
0436     buffer_obj_t *elt;
0437     typed_buffer_descr_t *buf_type = NULL;
0438     tp_command_call_t * last_call;
0439 
0440     NDRX_LOG(log_debug, "_tpfree buf=%p", buf);
0441 
0442     if (NULL==buf)
0443     {
0444         /* nothing to do for NULLs */
0445         return;
0446     }
0447     
0448     /* Work out the buffer */
0449     if (NULL!=known_buffer)
0450         elt=known_buffer;
0451     else
0452     {
0453         elt=ndrx_find_buffer(buf);
0454     }
0455 
0456     if (NULL!=elt)
0457     {
0458         /* Check isn't it auto buffer, then reset that one too */
0459         last_call = ndrx_get_G_last_call();
0460         
0461         if (elt==last_call->autobuf)
0462         {
0463             /* kill the auto buf.. 
0464              * Thus user is left to manage the buffer by it self.
0465              */
0466             last_call->autobuf = NULL;
0467         }
0468              
0469         buf_type = &G_buf_descr[elt->type_id];
0470         
0471         /* we cannot have ptr to call infos */
0472         if (NULL!=elt->callinfobuf)
0473         {
0474             NDRX_LOG(log_debug, "Removing call info buffer %p", elt->callinfobuf);
0475             
0476             /* Do recursive gather as this UBF
0477              */
0478             if (NULL!=flist)
0479             {
0480                 scan_ptrs((UBFH *)elt->callinfobuf,  flist);
0481             }
0482             
0483             /* OK free up the callinfo (it must not be in the list anyway
0484              * as user have no access to call-info buffer ptr
0485              */
0486             ndrx_tpfree(elt->callinfobuf, NULL);
0487         }
0488         
0489         /* Remove that stuff from our linked list!! */
0490         /* DL_DELETE(G_buffers,elt); */
0491         MUTEX_LOCK_V(M_lock);
0492         EXHASH_DEL(ndrx_G_buffers, elt);
0493         MUTEX_UNLOCK_V(M_lock);
0494         
0495         /* if buffer is UBF... gather recursive... */
0496         if (BUF_TYPE_UBF==buf_type->type_id && NULL!=flist)
0497         {
0498             scan_ptrs((UBFH *)buf,  flist);
0499         }
0500 
0501         /* Remove it here, avoid address reuse and re-adding to hash! */
0502         buf_type->pf_free(buf_type, elt->buf);
0503         
0504         /* delete elt by it self */
0505         NDRX_FPFREE(elt);
0506         
0507         if (NULL!=flist)
0508         {
0509             /* free up the inner buffers... */
0510             ndrx_mbuf_ptrs_t *el, *elt;
0511             
0512             EXHASH_ITER(hh, flist->ptrs_hash, el, elt)
0513             {
0514                 ndrx_tpfree_inner(el->ptr, NULL, NULL);
0515                 
0516                 EXHASH_DEL(flist->ptrs_hash, el);
0517                 NDRX_FPFREE(el);
0518             }
0519         }
0520     }
0521     
0522 out:            
0523     return;
0524 }
0525 
0526 /**
0527  * Remove the buffer
0528  * This will traverse all sub-buffers of the UBF and
0529  * and all PTRs buffer to UBF to find BFLD_PTR linked to this UBF (if this is one)
0530  * and will free all them up...
0531  * @param buf
0532  */
0533 expublic void ndrx_tpfree (char *buf, buffer_obj_t *known_buffer)
0534 {
0535     ndrx_buf_free_lists_t flist;
0536     
0537     memset(&flist, 0, sizeof(flist));
0538     
0539     /* struct of:
0540      * - ptr to main buffer
0541      * - list of pointer to free
0542      */
0543     ndrx_tpfree_inner (buf, known_buffer, &flist);
0544 }
0545 
0546 /**
0547  * Check is buffer auto or not
0548  * @param buf ATMI allocated buffer
0549  * @return TRUE (1) if auto buffer, 0 manual buffer, -1 if error (unknown buffer)
0550  */
0551 expublic int ndrx_tpisautobuf(char *buf)
0552 {
0553     int ret;
0554     buffer_obj_t *elt;
0555 
0556     /* NULLs are Auto! */
0557     if (NULL==buf)
0558     {
0559         return EXTRUE;
0560     }
0561 
0562     elt=ndrx_find_buffer(buf);
0563 
0564     if (NULL!=elt)
0565     {
0566         ret = elt->autoalloc;
0567         NDRX_LOG(log_debug, "_tpisautobuf buf=%p, autoalloc=%d", buf, ret);
0568     }
0569     else
0570     {
0571         ndrx_TPset_error_msg(TPEINVAL, "ptr points to unknown buffer, "
0572             "not allocated by tpalloc()!");
0573         ret=EXFAIL;
0574     }
0575         
0576     return ret;
0577 }
0578 
0579 /**
0580  * Internal version of tptypes. Returns type info
0581  * @param ptr
0582  * @param type
0583  * @param subtype
0584  * @return 
0585  */
0586 expublic long ndrx_tptypes (char *ptr, char *type, char *subtype)
0587 {
0588     long ret=EXSUCCEED;
0589     
0590     typed_buffer_descr_t *buf_type = NULL;
0591     buffer_obj_t *buf;
0592 
0593     buf =  ndrx_find_buffer(ptr);
0594     
0595     if (NULL==buf)
0596     {
0597         ndrx_TPset_error_msg(TPEINVAL, "ptr points to unknown buffer, "
0598                 "not allocated by tpalloc()!");
0599         ret=EXFAIL;
0600         goto out;
0601     }
0602     else
0603     {
0604         ret = buf->size;
0605     }
0606     
0607     buf_type = &G_buf_descr[buf->type_id];
0608     
0609     if (NULL!=type)
0610     {
0611         
0612         strcpy(type, buf_type->type);
0613     }
0614     
0615     if (NULL!=subtype && EXEOS!=buf->subtype[0])
0616     {
0617         strcpy(subtype, buf->subtype);
0618     }
0619     
0620 out:
0621     
0622     return ret;
0623     
0624 }
0625 
0626 /**
0627  * Set call info
0628  * @param typed buffer to which associate meta-data
0629  * @param cibuf input buffer (must be UBF)
0630  * @param flags call flags, not used must be set to 0
0631  * @return EXSUCCEED/EXFAIL
0632  */
0633 expublic int ndrx_tpsetcallinfo(const char *msg, UBFH *cibuf, long flags)
0634 {
0635     int ret = EXSUCCEED;
0636     buffer_obj_t * node_msg;
0637     typed_buffer_descr_t *descr = &G_buf_descr[BUF_TYPE_UBF];
0638     
0639     NDRX_LOG(log_debug, "Setting call info primary buffer msg=%p, cibuf=%p, flags=%ld",
0640             msg, cibuf, flags);
0641     
0642     /* Check the call buffer */
0643     if (NULL==(node_msg=ndrx_find_buffer((char *)msg)))
0644     {
0645         ndrx_TPset_error_fmt(TPEINVAL, "msg buffer %p is not know to system", msg);
0646         EXFAIL_OUT(ret);
0647     }
0648 
0649     /* now try to receive -> setup data from incoming UBF... */
0650     if (EXSUCCEED!=descr->pf_prepare_incoming(descr, (char *)cibuf, Bused(cibuf), 
0651             &(node_msg->callinfobuf), &node_msg->callinfobuf_len, 0))
0652     {
0653         NDRX_LOG(log_error, "Failed to setup call info buffer: %s", tpstrerror(tperrno));
0654         EXFAIL_OUT(ret);
0655     }
0656     
0657 out:
0658     return ret;
0659 }
0660 
0661 /**
0662  * Retrieve meta data
0663  * @param msg call buffer
0664  * @param cibuf metadata
0665  * @param flags 0 or TPCI_NOEOFERR
0666  * @return EXSUCCEED/EXFAIL
0667  */
0668 expublic int ndrx_tpgetcallinfo(const char *msg, UBFH **cibuf, long flags)
0669 {
0670     int ret = EXSUCCEED;
0671     buffer_obj_t * node_msg;
0672     typed_buffer_descr_t *callbuf = &G_buf_descr[BUF_TYPE_UBF];
0673     long olen=0;
0674     
0675     NDRX_LOG(log_debug, "Setting call info primary buffer msg=%p, obuf=%p, flags=%ld",
0676             msg, cibuf, flags);
0677     
0678     /* Check the call buffer */
0679     if (NULL==(node_msg=ndrx_find_buffer((char *)msg)))
0680     {
0681         ndrx_TPset_error_fmt(TPEINVAL, "msg buffer %p is not know to system", msg);
0682         EXFAIL_OUT(ret);
0683     }
0684     
0685     if (NULL==node_msg->callinfobuf)
0686     {
0687         if (flags & TPCI_NOEOFERR)
0688         {
0689             NDRX_LOG(log_debug, "No call infos associated with buffer %p", msg);
0690             goto out;
0691         }
0692         else
0693         {
0694             ndrx_TPset_error_fmt(TPESYSTEM, "No call info buffer is associated with message");
0695             EXFAIL_OUT(ret);
0696         }
0697     }
0698     
0699     /* now try to receive -> setup data from incoming UBF... */
0700     if (EXSUCCEED!=callbuf->pf_prepare_incoming(callbuf, node_msg->callinfobuf, 
0701             node_msg->callinfobuf_len, (char **)cibuf, &olen, 0))
0702     {
0703         NDRX_LOG(log_error, "Failed to retrieve call infos: %s", tpstrerror(tperrno));
0704         EXFAIL_OUT(ret);
0705     }
0706     
0707     /* alternate return flag */
0708     if (flags & TPCI_NOEOFERR)
0709     {
0710         ret=EXTRUE;
0711     }
0712     
0713 out:
0714     return ret;
0715 }
0716 /* vim: set ts=4 sw=4 et smartindent: */