Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Multi-buffer serialization handler
0003  *  call info, primary buffer and other sub-ptrs buffers are all written off
0004  *  in TLV master blob.
0005  *
0006  * @file multibuf.c
0007  */
0008 /* -----------------------------------------------------------------------------
0009  * Enduro/X Middleware Platform for Distributed Transaction Processing
0010  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0011  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0012  * This software is released under one of the following licenses:
0013  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0014  * See LICENSE file for full text.
0015  * -----------------------------------------------------------------------------
0016  * AGPL license:
0017  *
0018  * This program is free software; you can redistribute it and/or modify it under
0019  * the terms of the GNU Affero General Public License, version 3 as published
0020  * by the Free Software Foundation;
0021  *
0022  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0023  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0024  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0025  * for more details.
0026  *
0027  * You should have received a copy of the GNU Affero General Public License along 
0028  * with this program; if not, write to the Free Software Foundation, Inc.,
0029  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0030  *
0031  * -----------------------------------------------------------------------------
0032  * A commercial use license is available from Mavimax, Ltd
0033  * contact@mavimax.com
0034  * -----------------------------------------------------------------------------
0035  */
0036 #include <ndrx_config.h>
0037 #include <string.h>
0038 #include <stdio.h>
0039 #include <stdlib.h>
0040 #include <memory.h>
0041 #include <errno.h>
0042 #include <sys/sem.h>
0043 
0044 #include <atmi.h>
0045 #include <multibuf.h>
0046 #include <atmi_shm.h>
0047 #include <ndrstandard.h>
0048 #include <ndebug.h>
0049 #include <ndrxdcmn.h>
0050 #include <userlog.h>
0051 #include <ubf_int.h>
0052 #include <typed_buf.h>
0053 
0054 /*---------------------------Externs------------------------------------*/
0055 /*---------------------------Macros-------------------------------------*/
0056 /*---------------------------Enums--------------------------------------*/
0057 /*---------------------------Typedefs-----------------------------------*/
0058 /*---------------------------Globals------------------------------------*/
0059 /*---------------------------Statics------------------------------------*/
0060 /*---------------------------Prototypes---------------------------------*/
0061 
0062 
0063 /**
0064  * Find the particular ptr in t
0065  * @param ptr real pointer to check for multi buf descriptor
0066  * @return NULL (not found), ptr to MB if found 
0067  */
0068 expublic ndrx_mbuf_ptrs_t* ndrx_mbuf_ptr_find(ndrx_mbuf_ptrs_t **ptrs, char *ptr)
0069 {
0070     ndrx_mbuf_ptrs_t *ret=NULL;
0071     
0072     EXHASH_FIND_PTR( (*ptrs), ((void **)&ptr), ret);
0073     
0074     return ret;   
0075 }
0076 
0077 /**
0078  * Register exported pointer in the hash
0079  * @param ptrs hashmap of the real pointers
0080  * @param ptr pointer to register
0081  * @param tag tag to add
0082  * @return ptr descr / NULL (OOM)
0083  */
0084 expublic ndrx_mbuf_ptrs_t * ndrx_mbuf_ptr_add(ndrx_mbuf_ptrs_t **ptrs, char *ptr, int tag)
0085 {
0086     ndrx_mbuf_ptrs_t *ret = NULL;
0087     
0088     /* Alloc the memory block */
0089     if (NULL==(ret=(ndrx_mbuf_ptrs_t *)NDRX_FPMALLOC(sizeof(ndrx_mbuf_ptrs_t), 0)))
0090     {
0091         ndrx_TPset_error_fmt(TPEOS, "%s: Failed temporary hash space");
0092         goto out;
0093     }
0094     
0095     ret->ptr = ptr;
0096     ret->tag = tag;
0097     
0098     /* only if used by mbuf */
0099     if (EXFAIL!=tag)
0100     {
0101         NDRX_LOG(log_debug, "pointer %p mapped to tag %d", ptr, tag);
0102     }
0103     
0104     EXHASH_ADD_PTR((*ptrs), ptr, ret);
0105     
0106 out:
0107     return ret;
0108 }
0109 
0110 /**
0111  * Free up the hash list of pointers
0112  * @param ptrs pointer hashmap
0113  */
0114 expublic void ndrx_mbuf_ptr_free(ndrx_mbuf_ptrs_t **ptrs)
0115 {
0116     ndrx_mbuf_ptrs_t * el, *elt;
0117     
0118     EXHASH_ITER(hh, (*ptrs), el, elt)
0119     {
0120         EXHASH_DEL((*ptrs), el);
0121         NDRX_FPFREE(el);
0122     }
0123 }
0124 
0125 /**
0126  * Remap the buffer back to real pointers
0127  * @param list list of ptrs by index
0128  * @param p_ub ubf to scan (recursively)
0129  * @return EXSUCCEED/EXFAIL
0130  */
0131 exprivate int ndrx_mbuf_ptrs_map_in(ndrx_growlist_t *list, UBFH *p_ub)
0132 {
0133     int ret = EXSUCCEED;
0134     Bnext_state_t state;
0135     BFLDID bfldid=BBADFLDOCC;
0136     BFLDOCC occ;
0137     char *d_ptr;
0138     char **lptr;
0139     ndrx_mbuf_vptrs_t *access_vptr;
0140     UBF_header_t *hdr = (UBF_header_t *)p_ub;
0141     int ftyp;
0142     unsigned int tag;
0143     BFLDID   *p_bfldid_start = &hdr->bfldid;
0144     
0145     state.p_cur_bfldid = (BFLDID *)(((char *)p_bfldid_start) + hdr->cache_ptr_off);
0146     state.cur_occ = 0;
0147     state.p_ub = p_ub;
0148     state.size = hdr->bytes_used;
0149 
0150     while (EXTRUE==(ret=ndrx_Bnext(&state, p_ub, &bfldid, &occ, NULL, NULL, &d_ptr)))
0151     {
0152         ftyp = bfldid >> EFFECTIVE_BITS;
0153         
0154         
0155         if (BFLD_PTR==ftyp)
0156         {
0157             
0158             /* if we get field, then this needs to be updated with real
0159              * ptr. Also in this case we shall reprocess the field
0160              * if it is UBF (but also if there are several ptrs to one
0161              * field, we shall do it once)
0162              */
0163             
0164             /* resolve the VPTR */
0165             lptr=(char **)d_ptr;
0166             access_vptr = (ndrx_mbuf_vptrs_t *)(list->mem + ((long)(*lptr))*sizeof(ndrx_mbuf_vptrs_t));
0167             
0168             NDRX_LOG(log_debug, "Mapping tag %ld to %p", (long)*lptr, access_vptr->data);
0169             
0170             tag = (unsigned int)(ndrx_longptr_t)*lptr;
0171             *lptr = access_vptr->data;
0172 
0173         }
0174         else if (BFLD_UBF==ftyp)
0175         {
0176             /* process the sub-buffer... (re-map sub-fields) */
0177             if (EXSUCCEED!=ndrx_mbuf_ptrs_map_in(list, (UBFH *)d_ptr))
0178             {
0179                 NDRX_LOG(log_error, "Failed to re-map master buffer %p "
0180                         "sub-field (UBF) %d", p_ub, bfldid);
0181                 EXFAIL_OUT(ret);
0182             }
0183         }
0184         else
0185         {
0186             /* we are done */
0187             ret=EXSUCCEED;
0188             break;
0189         }
0190     }
0191     
0192     if (EXFAIL==ret)
0193     {
0194         NDRX_LOG(log_error, "Failed to loop ubf: %s", Bstrerror(Berror));
0195         ndrx_TPset_error_fmt(TPESYSTEM, "Failed to loop ubf: %s", Bstrerror(Berror));
0196         EXFAIL_OUT(ret);
0197     }
0198             
0199 out:
0200 
0201     return ret;
0202 }
0203 
0204 /**
0205  * receive TLV data with several buffers
0206  * buffers needs to be indexed and pointer remapped for embedded PTR
0207  * types
0208  * @param rcv_data data received (with out header)
0209  * @param rcv_len data received length
0210  * @param odata output buffer. This is master buffer. Call header
0211  *  may be linked. The master buffer could be ubf with ptrs to ubfs which
0212  *  may also contain ptrs... Received data pointer are virtually numbered
0213  *  and corresponds to TLV index. Thus atmi buffers needs to be allocated
0214  *  and their pointers needs to updated in ubf buffer. Also one UBF
0215  *  may point to one atmi buffer several times. Thus needs some hash of
0216  *  pointers which would map the linear array index. 
0217  * @param olen master buffer received length
0218  * @param flags atmi flags
0219  * @param mflags MBUF flags
0220  * @return EXSUCCEED/EXFAIL
0221  */
0222 expublic int ndrx_mbuf_prepare_incoming (char *rcv_data, long rcv_len, char **odata, 
0223         long *olen, long flags, long mflags)
0224 {
0225     int ret = EXSUCCEED;
0226     ndrx_growlist_t list;
0227     ndrx_mbuf_tlv_t *tlv_hdr;
0228     long tlv_pos;
0229     unsigned int tag_exp=0;
0230     ndrx_mbuf_vptrs_t current_vptr;
0231     ndrx_mbuf_vptrs_t *access_vptr;
0232     typed_buffer_descr_t *descr;
0233     int primary_loaded = EXFALSE;
0234     int i;
0235     /* parse the TLV and load into growlist with index of VPTRs */
0236     ndrx_growlist_init(&list, 50, sizeof(ndrx_mbuf_vptrs_t));
0237     
0238     /* OK load the stuff ... */
0239     NDRX_LOG(log_debug, "Parse incoming buffer TLV");
0240     for (tlv_pos=0; tlv_pos<rcv_len; tlv_pos+=(ALIGNED_GEN(tlv_hdr->len)+sizeof(ndrx_mbuf_tlv_t)), tag_exp++)
0241     {
0242         int is_callinfo;
0243         unsigned int tag;
0244         int btype;
0245         
0246         tlv_hdr=(ndrx_mbuf_tlv_t *)(rcv_data + tlv_pos);
0247         
0248         tag = NDRX_MBUF_TAGTAG(tlv_hdr->tag);
0249         btype = NDRX_MBUF_TYPE(tlv_hdr->tag);
0250         is_callinfo = !!(tlv_hdr->tag & NDRX_MBUF_CALLINFOBIT);
0251         
0252         NDRX_LOG(log_debug, "Received buffer tag: %u type: %d callinfo: %d len: %ld",
0253                 tag, btype, is_callinfo, tlv_hdr->len);
0254         
0255         if (tag!=tag_exp)
0256         {
0257             NDRX_LOG(log_error, "ERROR: Expected tag %u but got %u", tag_exp, tag);
0258             userlog("ERROR: Expected tag %u but got %u", tag_exp, tag);
0259             ndrx_TPset_error_fmt(TPESYSTEM, "ERROR: Expected tag %u but got %u", 
0260                     tag_exp, tag);
0261             EXFAIL_OUT(ret);
0262         }
0263         
0264         /* get the work area: */
0265         descr = &G_buf_descr[btype];
0266 
0267         current_vptr.btype = btype;/**< cache buffer type               */
0268         /* set the primary data, if any */
0269         if (!primary_loaded && !is_callinfo)
0270         {
0271             current_vptr.data=*odata;
0272             current_vptr.len=*olen;
0273         }
0274         else
0275         {
0276             current_vptr.data=NULL;
0277             current_vptr.len=0;
0278         }
0279                 
0280         /* check is this primary or not? */
0281         ret=descr->pf_prepare_incoming(descr,
0282                 tlv_hdr->data,
0283                 tlv_hdr->len,
0284                 &current_vptr.data,
0285                 &current_vptr.len,
0286                 flags);
0287         
0288         if (EXSUCCEED!=ret)
0289         {
0290             NDRX_LOG(log_error, "Failed to prepare incoming buffer tag: %u type: %d callinfo: %d",
0291                 tag, btype, is_callinfo);
0292             EXFAIL_OUT(ret);
0293         }
0294         
0295         /* add buffer to vptr list */
0296         if (EXSUCCEED!=ndrx_growlist_append(&list, &current_vptr))
0297         {
0298             NDRX_LOG(log_error, "Failed to append vptr list with tag: %u addr: %p len: %ld - OOM?",
0299                     tag, current_vptr.data, current_vptr.len);
0300             ndrx_TPset_error_fmt(TPEOS, "Failed to append vptr list with tag: %u addr: %p len: %ld - OOM?",
0301                     tag, current_vptr.data, current_vptr.len);
0302             EXFAIL_OUT(ret);
0303         }
0304         
0305         /* check the primary buffer status */
0306         if (!primary_loaded && !is_callinfo)
0307         {
0308             *odata = current_vptr.data;
0309             *olen = current_vptr.len;   
0310             
0311             /* get buffer object, assoc new call header, destroy oldone if
0312              * existed */
0313             if (1==tag)
0314             {
0315                 buffer_obj_t * buffer_info = ndrx_find_buffer(*odata);
0316                 
0317                 if (NULL!=buffer_info->callinfobuf)
0318                 {
0319                     tpfree(buffer_info->callinfobuf);
0320                 }
0321                 /* callinfos are at pos 0 */
0322                 access_vptr = (ndrx_mbuf_vptrs_t *)list.mem;
0323                 buffer_info->callinfobuf = access_vptr->data;
0324                 buffer_info->callinfobuf_len = access_vptr->len;
0325             }
0326             
0327             primary_loaded=EXTRUE;
0328         }
0329         
0330         if (primary_loaded && is_callinfo)
0331         {
0332             NDRX_LOG(log_error, "Call info expected only for primary buffer, "
0333                     "but at the tag %u", tag);
0334             ndrx_TPset_error_fmt(TPESYSTEM, "Call info expected only for primary buffer, "
0335                     "but at the tag %u", tag);
0336             EXFAIL_OUT(ret);
0337         }
0338         
0339     }
0340     
0341     NDRX_LOG(log_debug, "Remap the vptrs (tags) to real pointers");
0342     
0343     /* go over the list of tags, and perform map-in operation on each of it */
0344     
0345     for (i=0; i<=list.maxindexused; i++)
0346     {
0347         
0348         access_vptr = (ndrx_mbuf_vptrs_t *)(list.mem + (i)*sizeof(ndrx_mbuf_vptrs_t));
0349         
0350         if (BUF_TYPE_UBF==access_vptr->btype)
0351         {
0352             if (EXSUCCEED!=ndrx_mbuf_ptrs_map_in(&list, (UBFH *)access_vptr->data))
0353             {
0354                 NDRX_LOG(log_error, "Failed to re-map tag %i", i);
0355                 EXFAIL_OUT(ret);
0356             }
0357         }
0358     }
0359     
0360 out:
0361     
0362     ndrx_growlist_free(&list);
0363     
0364     return ret;
0365 }
0366 
0367 /**
0368  * Write entry to TLV
0369  * @param idata input data
0370  * @param ilen input data buffer len (seems for PTR -> carrays we need to
0371  *  send all allocated space, for others we can evaluate the size)
0372  * @param obuf output buffer where to print the TLV
0373  * @param olen_max max size of buf
0374  * @param olen_used current un-aligned buffer use
0375  * @param tag tag number to assign for this buffer.
0376  * @param flags ATMI flags
0377  * @return EXSUCCEED/EXFAIL (ATMI error loaded)
0378  */
0379 exprivate int ndrx_mbuf_tlv_do(char *idata, long ilen, char *obuf, 
0380         long olen_max, long *olen_used, unsigned int tag, long flags)
0381 {
0382     int ret = EXSUCCEED;
0383     ndrx_mbuf_tlv_t *hdr;
0384     long new_used = ALIGNED_GEN(*olen_used);
0385     int pad=*olen_used-new_used;
0386     long tmp_olen;
0387     buffer_obj_t * buffer_info = ndrx_find_buffer(idata);
0388     typed_buffer_descr_t *descr;
0389     
0390     if (NULL==buffer_info)
0391     {
0392         NDRX_LOG(log_error, "Input buffer %p not atmi allocated", idata);
0393         ndrx_TPset_error_fmt(TPEINVAL, "Input buffer %p not atmi allocated", idata);
0394         EXFAIL_OUT(ret);
0395     }
0396     
0397     if (EXFAIL==ilen)
0398     {
0399         /* in case of carray we do not know the real used len */
0400         ilen=buffer_info->size;
0401     }
0402     
0403     /* put the header down */
0404     hdr = (ndrx_mbuf_tlv_t *)(obuf+new_used);
0405     
0406     /* get get aligned size*/
0407     new_used += sizeof(ndrx_mbuf_tlv_t);
0408     
0409     if (new_used> olen_max)
0410     {
0411         ndrx_TPset_error_fmt(TPEINVAL, "%s: Internal buffer size %ld, new data %ld (tag)", 
0412                 __func__, olen_max, new_used);
0413         ret=EXFAIL;
0414         goto out;
0415     }
0416     
0417     hdr->tag = tag | (buffer_info->type_id << NDRX_MBUF_OFFSET);
0418     
0419     
0420     /* get the buffer type */    
0421     /* calculate the amount left */
0422     tmp_olen = olen_max-new_used;
0423     
0424     descr = &G_buf_descr[buffer_info->type_id];
0425     
0426     /* prepare buffer for call */
0427     NDRX_LOG(log_debug, "Prep tag: %u (ttag %u, type %d). Src %p, "
0428             "dst %p olen_max=%ld new_used=%ld pad=%d buffer_left=%ld", 
0429             tag, hdr->tag, buffer_info->type_id, idata, obuf, olen_max, new_used, pad, tmp_olen);
0430     
0431     if (EXSUCCEED!=descr->pf_prepare_outgoing(descr, idata, ilen, hdr->data, 
0432             &tmp_olen, flags))
0433     {
0434         NDRX_LOG(log_error, "ERROR: pf_prepare_outgoing failed: %u (ttag %u, type %d). Src %p, "
0435             "dst %p olen_max=%ld new_used=%ld pad=%d buffer_left=%ld: %s", 
0436             tag, hdr->tag, buffer_info->type_id, idata, obuf, olen_max, new_used, pad, tmp_olen,
0437                 tpstrerror(tperrno));
0438         EXFAIL_OUT(ret);
0439     }
0440     hdr->len = tmp_olen;
0441     /* new used is loaded */
0442     *olen_used=new_used+tmp_olen;
0443     NDRX_LOG(log_debug, "tag=%d loaded new_used=%ld", tag, *olen_used);
0444     
0445 out:
0446     return ret;    
0447 }
0448 
0449 /**
0450  * Set Bnext state to first BFLD_PTR type
0451  * used for recursive ubf/ptr buffer processing
0452  * Note endurox-python module does extern to this
0453  * @param p_ub UBF buffer to process
0454  * @param state state to intialize
0455  */
0456 expublic void ndrx_mbuf_Bnext_ptr_first(UBFH *p_ub, Bnext_state_t *state)
0457 {
0458     UBF_header_t *hdr = (UBF_header_t *)p_ub;
0459     BFLDID   *p_bfldid_start = &hdr->bfldid;
0460     state->p_cur_bfldid = (BFLDID *)(((char *)p_bfldid_start) + hdr->cache_ptr_off);
0461     state->cur_occ = 0;
0462     state->p_ub = p_ub;
0463     state->size = hdr->bytes_used;
0464 }
0465 
0466 /**
0467  * Loop the UBF buffer and add any ptr to output memory block.
0468  * This may go in recursion if we find any sub-UBF buffer of particular
0469  * UBF.
0470  * @param ptrs pointer hashmap
0471  * @param p_ub ubf to scan
0472  * @param obuf start address of serialized block of buffers
0473  * @param olen_max buffer max len
0474  * @param olen_used currently used space
0475  * @param p_tag currently used tag and next tag (set here)
0476  * @param flags RFU
0477  * @return EXSUCCEED/EXFAIL
0478  */
0479 exprivate int ndrx_mbuf_ptrs_map_out(ndrx_mbuf_ptrs_t **ptrs, UBFH *p_ub,
0480         char *obuf, long olen_max, long *olen_used, unsigned int *p_tag, long flags)
0481 {
0482     int ret = EXSUCCEED;
0483     Bnext_state_t state;
0484     BFLDID bfldid=BBADFLDOCC;
0485     BFLDOCC occ;
0486     char *d_ptr;
0487     char **lptr;
0488     ndrx_longptr_t tmp_ptr;
0489     ndrx_mbuf_ptrs_t *hptr; /* hash pointer */
0490     int ftyp;
0491     
0492     ndrx_mbuf_Bnext_ptr_first(p_ub, &state);
0493 
0494     while (EXTRUE==(ret=ndrx_Bnext(&state, p_ub, &bfldid, &occ, NULL, NULL, &d_ptr)))
0495     {
0496         ftyp = bfldid >> EFFECTIVE_BITS;
0497         
0498         if (BFLD_PTR==ftyp)
0499         {
0500             lptr=(char **)d_ptr;
0501             
0502             if (NULL==(hptr = ndrx_mbuf_ptr_find(ptrs, *lptr)))
0503             {
0504                 /* map the pointer (add to hash the tag, or resolve the 
0505                  * existing tag, and just update the UBF buffer)
0506                  */
0507                 *p_tag=*p_tag+1;
0508                 
0509                 hptr = ndrx_mbuf_ptr_add(ptrs, *lptr, *p_tag);
0510                 
0511                 if (NULL==hptr)
0512                 {
0513                     NDRX_LOG(log_error, "Failed to allocate ptr hash element");
0514                     EXFAIL_OUT(ret);
0515                 }
0516                 
0517                 NDRX_LOG(log_debug, "fldid=%d occ=%d ptr to %p -> serialize to tag %u",
0518                         bfldid, occ, *lptr, *p_tag);
0519 
0520                 /* how about buffer len? we do not know what is used len, so
0521                  * needs to extract from types? */
0522                 if (EXSUCCEED!=ndrx_mbuf_tlv_do((char *)*lptr, EXFAIL, obuf, 
0523                         olen_max, olen_used, hptr->tag, flags))
0524                 {
0525                     NDRX_LOG(log_error, "Failed to add ptr %p to export data tag=%u",
0526                             (char *)lptr, *p_tag);
0527                     EXFAIL_OUT(ret);
0528                 }
0529             }
0530             
0531             /* update ubf buffer with tag */
0532             tmp_ptr=hptr->tag;
0533             *lptr = (char *)tmp_ptr;
0534         }
0535         else if (BFLD_UBF==ftyp)
0536         {
0537             NDRX_LOG(log_debug, "Processing sub-buffer field %d", bfldid);
0538             if (EXSUCCEED!=ndrx_mbuf_ptrs_map_out(ptrs, (UBFH *)d_ptr,
0539                 obuf, olen_max, olen_used, p_tag, flags))
0540             {
0541                 NDRX_LOG(log_error, "Sub-buffer (ubf) for fld %d failed to map");
0542                 EXFAIL_OUT(ret);
0543             }
0544         }
0545         else
0546         {
0547             /* we are done */
0548             ret=EXSUCCEED;
0549             break;
0550         }
0551     }
0552     
0553     if (EXFAIL==ret)
0554     {
0555         NDRX_LOG(log_error, "Failed to loop ubf: %s", Bstrerror(Berror));
0556         ndrx_TPset_error_fmt(TPESYSTEM, "Failed to loop ubf: %s", Bstrerror(Berror));
0557         EXFAIL_OUT(ret);
0558     }
0559             
0560 out:
0561     return ret;
0562 }
0563 
0564 /**
0565  * Prepare outgoing data. Needs to check for call info existence
0566  * That would be set to ptr 0. Starting with index 10, data buffers
0567  * begins. The buffer 10 is master buffer and 11+ are ptr buffers.
0568  * Once we parse the TLV, each of the buffers needs to be allocated. Real
0569  * ptr needs to be stored in growlist.
0570  * then in the loop all in recursive way buffers needs to be updated
0571  * from virtual pointer to real pointer.
0572  * @param idata input master buffer (may have linked call info associated) 
0573  * and embedded buffers with pointer to atmi buffers
0574  * @param ilen input buffer used space
0575  * @param obuf output buffer
0576  * @param olen output buffer size, on input it is buffer size of output
0577  *  in output it returns the bytes written for send
0578  * @param flags atmi flags
0579  * @param mflags MBUF flags
0580  * @return EXSUCCEED/EXFAIL
0581  */
0582 expublic int ndrx_mbuf_prepare_outgoing (char *idata, long ilen, char *obuf, long *olen, 
0583         long flags, long mflags)
0584 {
0585     int ret = EXSUCCEED;
0586     buffer_obj_t * ibuf = ndrx_find_buffer(idata);
0587     long used=0;
0588     /* pointer mapping hash */
0589     ndrx_mbuf_ptrs_t *ptrs=NULL;
0590     long tlv_pos;
0591     ndrx_mbuf_tlv_t *tlv_hdr;
0592     unsigned int ptr_tag=0;
0593     
0594     if (NULL==ibuf)
0595     {
0596         NDRX_LOG(log_error, "Input buffer %p not atmi allocated", idata);
0597         ndrx_TPset_error_fmt(TPEINVAL, "Input buffer %p not atmi allocated", idata);
0598         EXFAIL_OUT(ret);
0599     }
0600     
0601     /* check for call info, if any, serialize to TLV */
0602     if (NULL!=ibuf->callinfobuf && !(mflags & NDRX_MBUF_FLAG_NOCALLINFO))
0603     {
0604         if (EXSUCCEED!=ndrx_mbuf_tlv_do(ibuf->callinfobuf, ibuf->callinfobuf_len, obuf, 
0605             *olen, &used, ptr_tag | NDRX_MBUF_CALLINFOBIT, flags))
0606         {
0607             NDRX_LOG(log_error, "Failed to run TLV on callinfo");
0608             EXFAIL_OUT(ret);
0609         }
0610         ptr_tag++;
0611     }
0612     
0613     /* serialize main buffer to TLV */
0614     if (EXSUCCEED!=ndrx_mbuf_tlv_do(idata, ilen, obuf, *olen, &used, 
0615             ptr_tag, flags))
0616     {
0617         NDRX_LOG(log_error, "Failed to run TLV on base buffer");
0618         EXFAIL_OUT(ret);
0619     }
0620     
0621     /* iterate over the main buffer, remap the pointers on the fly 
0622      * looping shall be done in outer function to support the recursion
0623      */ 
0624     for (tlv_pos=0; tlv_pos<used; tlv_pos+=(ALIGNED_GEN(tlv_hdr->len)+sizeof(ndrx_mbuf_tlv_t)))
0625     {
0626         int is_callinfo;
0627         
0628         tlv_hdr=(ndrx_mbuf_tlv_t *) (obuf + tlv_pos);
0629         is_callinfo = !!(tlv_hdr->tag & NDRX_MBUF_CALLINFOBIT);
0630        
0631         NDRX_LOG(log_debug, "Post-processing (vptr mapping) tag: %u typed: %d callinfo: %d offset: %ld", 
0632                NDRX_MBUF_TAGTAG(tlv_hdr->tag), NDRX_MBUF_TYPE(tlv_hdr->tag), is_callinfo, tlv_pos);
0633        
0634         /* check the buffer type, if it is UBF, then run the mapping... */
0635         if (BUF_TYPE_UBF == NDRX_MBUF_TYPE(tlv_hdr->tag))
0636         {
0637            if (EXSUCCEED!=ndrx_mbuf_ptrs_map_out(&ptrs, (UBFH *)tlv_hdr->data,
0638                 obuf, *olen, &used, &ptr_tag, flags))
0639            {
0640                 NDRX_LOG(log_debug, "Post-processing (vptr mapping) for tag: %d typed: %d failed callinfo: %d", 
0641                     NDRX_MBUF_TAGTAG(tlv_hdr->tag), NDRX_MBUF_TYPE(tlv_hdr->tag), is_callinfo);
0642                 EXFAIL_OUT(ret);
0643            }
0644         }
0645     }
0646     
0647     /* finally set the data len */
0648     *olen = used;
0649     
0650 out:
0651     
0652     /* TODO: Shouldn't this be done from the outside?  */
0653     if (NULL!=ptrs)
0654     {
0655         ndrx_mbuf_ptr_free(&ptrs);
0656     }
0657 
0658     NDRX_LOG(log_debug, "%ld data bytes ret=%d", *olen, ret);
0659 
0660     return ret;
0661 }
0662 
0663 /**
0664  * Dump the TLV data
0665  * @param rcv_data serialized buffer
0666  * @param rcv_len total buffer len
0667  */
0668 expublic void ndrx_mbuf_tlv_debug (char *rcv_data, long rcv_len)
0669 {
0670     ndrx_mbuf_tlv_t *tlv_hdr;
0671     long tlv_pos;
0672     unsigned int tag_exp=0;
0673     
0674     /* OK load the stuff ... */
0675     NDRX_LOG(log_debug, "** DUMP TLV START **");
0676     for (tlv_pos=0; tlv_pos<rcv_len; tlv_pos+=(ALIGNED_GEN(tlv_hdr->len)+sizeof(ndrx_mbuf_tlv_t)), tag_exp++)
0677     {
0678         int is_callinfo;
0679         unsigned int tag;
0680         int btype;
0681         
0682         tlv_hdr=(ndrx_mbuf_tlv_t *)(rcv_data + tlv_pos);
0683         
0684         tag = NDRX_MBUF_TAGTAG(tlv_hdr->tag);
0685         btype = NDRX_MBUF_TYPE(tlv_hdr->tag);
0686         is_callinfo = !!(tlv_hdr->tag & NDRX_MBUF_CALLINFOBIT);
0687         
0688         NDRX_LOG(log_debug, "Buffer raw tag: %u tag: %u type: %d callinfo: %d len: %ld aligned: %d",
0689                 tlv_hdr->tag, tag, btype, is_callinfo, tlv_hdr->len, ALIGNED_GEN(tlv_hdr->len));
0690         
0691         if (tag!=tag_exp)
0692         {
0693             NDRX_LOG(log_error, "ERROR: Expected tag %u but got %u", tag_exp, tag);
0694             return;
0695         }
0696         
0697         NDRX_DUMP(log_debug, "TAG data", tlv_hdr->data, tlv_hdr->len);
0698         
0699     }
0700     NDRX_LOG(log_debug, "** DUMP TLV END **");
0701     
0702 }
0703 
0704 
0705 /* vim: set ts=4 sw=4 et smartindent: */