Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief UBF buffer support
0003  *
0004  * @file typed_ubf.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 <errno.h>
0039 #include <utlist.h>
0040 
0041 #include <tperror.h>
0042 #include <ubf.h>
0043 #include <atmi.h>
0044 #include <typed_buf.h>
0045 #include <ndebug.h>
0046 #include <ubf_int.h>
0047 /*---------------------------Externs------------------------------------*/
0048 /*---------------------------Macros-------------------------------------*/
0049 #define UBF_DEFAULT_SIZE    1024
0050 /*---------------------------Enums--------------------------------------*/
0051 /*---------------------------Typedefs-----------------------------------*/
0052 /*---------------------------Globals------------------------------------*/
0053 /*---------------------------Statics------------------------------------*/
0054 /*---------------------------Prototypes---------------------------------*/
0055 /*
0056  * Prepare buffer for outgoing call/reply
0057  * idata - buffer data
0058  * ilen - data len (if needed)
0059  * obuf - place where to copy prepared buffer
0060  * olen - the actual lenght of data that should sent. Also this may represent
0061  *          space for the buffer to copy to.
0062  */
0063 expublic int UBF_prepare_outgoing (typed_buffer_descr_t *descr, char *idata, 
0064         long ilen, char *obuf, long *olen, long flags)
0065 {
0066     int ret=EXSUCCEED;
0067     UBFH *p_ub = (UBFH *)idata;
0068     int ubf_used;
0069     char fn[]="UBF_prepare_outgoing";
0070     UBF_header_t *hdr;
0071     if (EXFAIL==(ubf_used=Bused(p_ub)))
0072     {
0073         ndrx_TPset_error_msg(TPEINVAL, Bstrerror(Berror));
0074         ret=EXFAIL;
0075         goto out;
0076     }
0077 
0078     /* Check that we have space enough to prepare for send 
0079      * Should'n  we reject on 0 - ok?
0080      */
0081     if (NULL!=olen && *olen < ubf_used)
0082     {
0083         ndrx_TPset_error_fmt(TPEINVAL, "%s: Internal buffer space: %d, "
0084                 "but requested: %d", fn, *olen, ubf_used);
0085         ret=EXFAIL;
0086         goto out;
0087     }
0088 
0089     memcpy(obuf, idata, ubf_used);
0090     /* Now re-size FB, so that buffer is correct */
0091     hdr = (UBF_header_t *) obuf;
0092 
0093     hdr->buf_len = ubf_used;
0094     /* return the actual length! */
0095     if (NULL!=olen)
0096         *olen = ubf_used;
0097     
0098 out:
0099     return ret;
0100 }
0101 
0102 /*
0103  * Prepare received buffer for internal processing.
0104  * May re-allocate the buffer.
0105  * rcv_data - received data buffer
0106  * odata - ptr to handler. Existing buffer may be reused or re-allocated
0107  * olen - output data length
0108  */
0109 expublic int UBF_prepare_incoming (typed_buffer_descr_t *descr, char *rcv_data, 
0110                         long rcv_len, char **odata, long *olen, long flags)
0111 {
0112     int ret=EXSUCCEED;
0113     long rcv_buf_size;
0114     long existing_size;
0115     UBFH *p_ub = (UBFH *)rcv_data;
0116     UBFH *p_ub_out;
0117     char fn[]="UBF_prepare_incoming";
0118     buffer_obj_t *outbufobj=NULL;
0119     UBF_header_t *hdr;
0120 
0121     NDRX_LOG(log_debug, "Entering %s", fn);
0122     if (EXFAIL==(rcv_buf_size=Bused(p_ub)))
0123     {
0124         ndrx_TPset_error_msg(TPEINVAL, Bstrerror(Berror));
0125         ret=EXFAIL;
0126         goto out;
0127     }
0128     /* Needs to add trailer bytes space */
0129     rcv_buf_size+=FF_USED_BYTES;
0130 
0131     /* Figure out the passed in buffer */
0132     if (NULL==(outbufobj=ndrx_find_buffer(*odata)))
0133     {
0134         ndrx_TPset_error_fmt(TPEINVAL, "Output buffer %p is not allocated "
0135                                         "with tpalloc()!", *odata);
0136         ret=EXFAIL;
0137         goto out;
0138     }
0139 
0140     /* Check the data types */
0141     if (NULL!=outbufobj)
0142     {
0143         /* If we cannot change the data type, then we trigger an error */
0144         if (flags & TPNOCHANGE && outbufobj->type_id!=BUF_TYPE_UBF)
0145         {
0146             /* Raise error! */
0147             ndrx_TPset_error_fmt(TPEOTYPE, "Receiver expects %s but got %s buffer",
0148                                         G_buf_descr[BUF_TYPE_NULL].type,
0149                                         G_buf_descr[outbufobj->type_id].type
0150                                         );
0151             ret=EXFAIL;
0152             goto out;
0153         }
0154         /* If we can change data type and this does not match, then
0155          * we should firstly free it up and then bellow allow to work in mode
0156          * when odata is NULL!
0157          */
0158         if (outbufobj->type_id!=BUF_TYPE_UBF)
0159         {
0160             NDRX_LOG(log_info, "User buffer type %s is different, "
0161                     "free it up and re-allocate as UBF", G_buf_descr[outbufobj->type_id].type);
0162             ndrx_tpfree(*odata, outbufobj);
0163             *odata=NULL;
0164         }
0165     }
0166     
0167     /* check the output buffer */
0168     if (NULL!=*odata)
0169     {
0170         p_ub_out = (UBFH *)*odata;
0171         NDRX_LOG(log_debug, "%s: Output buffer exists", fn);
0172         
0173         if (EXFAIL==(existing_size=Bsizeof(p_ub_out)))
0174         {
0175             ndrx_TPset_error_msg(TPEINVAL, Bstrerror(Berror));
0176             ret=EXFAIL;
0177             goto out;
0178         }
0179 
0180         NDRX_LOG(log_debug, "%s: Output buffer size: %ld, received %ld", fn,
0181                             existing_size, rcv_buf_size);
0182         
0183         if (existing_size>=rcv_buf_size)
0184         {
0185             /* re-use existing buffer */
0186             NDRX_LOG(log_debug, "%s: Using existing buffer", fn);
0187         }
0188         else
0189         {
0190             /* Reallocate the buffer, because we have missing some space */
0191             char *new_addr;
0192             NDRX_LOG(log_debug, "%s: Reallocating", fn);
0193             
0194             if (NULL==(new_addr=ndrx_tprealloc(*odata, rcv_buf_size)))
0195             {
0196                 NDRX_LOG(log_error, "%s: _tprealloc failed!", fn);
0197                 ret=EXFAIL;
0198                 goto out;
0199             }
0200 
0201             /* allocated OK, return new address */
0202             *odata = new_addr;
0203             p_ub_out = (UBFH *)*odata;
0204         }
0205     }
0206     else
0207     {
0208         /* allocate the buffer */
0209         NDRX_LOG(log_debug, "%s: Incoming buffer where missing - "
0210                 "allocating new (size: %d)!",  fn, rcv_buf_size);
0211 
0212         *odata = ndrx_tpalloc(&G_buf_descr[BUF_TYPE_UBF], NULL, NULL, rcv_buf_size);
0213 
0214         if (NULL==*odata)
0215         {
0216             /* error should be set already */
0217             NDRX_LOG(log_error, "Failed to allocat new buffer!");
0218             goto out;
0219         }
0220 
0221         p_ub_out = (UBFH *)*odata;
0222     }
0223 
0224     /* Do the actual data copy */
0225     if (EXSUCCEED!=Bcpy(p_ub_out, p_ub))
0226     {
0227         ret=EXFAIL;
0228         NDRX_LOG(log_error, "Bcpy failed!: %s", Bstrerror(Berror));
0229         ndrx_TPset_error_msg(TPEOS, Bstrerror(Berror));
0230         goto out;
0231     }
0232 
0233     /* Bug #789 */
0234     if (NULL!=olen)
0235     {
0236         /* header buffer size is in sync with XATMI tpalloc registry. */
0237         hdr = (UBF_header_t *) p_ub_out;
0238         *olen = hdr->buf_len;
0239     }
0240 
0241 out:
0242     return ret;
0243 }
0244 
0245 /**
0246  * Allocate the buffer & register this into list, that we have such
0247  * List maintenance should be done by parent process tpalloc!
0248  * @param subtype
0249  * @param len
0250  * @return
0251  */
0252 expublic char * UBF_tpalloc (typed_buffer_descr_t *descr, char *subtype, long *len)
0253 {
0254     char *ret=NULL;
0255 
0256     if (UBF_DEFAULT_SIZE > *len)
0257     {
0258         *len = UBF_DEFAULT_SIZE;
0259     }
0260 
0261     /* Allocate UBF buffer */
0262     ret=(char *)ndrx_Balloc(0, 0, *len);
0263 
0264     if (NULL==ret)
0265     {
0266         NDRX_LOG(log_error, "%s: Failed to allocate UBF buffer!", __func__);
0267         ndrx_TPset_error_msg(TPEOS, Bstrerror(Berror));
0268         goto out;
0269     }
0270 
0271 out:
0272     return ret;
0273 }
0274 
0275 /**
0276  * Re-allocate UBF buffer. Firstly we will find it in the list.
0277  * TODO: Fix the realloc to bytes, instead of fields, set by Brealloc!!!
0278  * 
0279  * @param ptr
0280  * @param size
0281  * @return
0282  */
0283 expublic char * UBF_tprealloc(typed_buffer_descr_t *descr, char *cur_ptr, long len)
0284 {
0285     char *ret=NULL;
0286     UBFH *p_ub = (UBFH *)cur_ptr;
0287     char fn[] = "UBF_tprealloc";
0288 
0289     if (UBF_DEFAULT_SIZE > len)
0290     {
0291         len = UBF_DEFAULT_SIZE;
0292     }
0293 
0294     /* Allocate UBF buffer */
0295     ret=(char *)ndrx_Brealloc(p_ub, 0, 0, len);
0296 
0297     if (NULL==ret)
0298     {
0299         NDRX_LOG(log_error, "%s: Failed to allocate UBF buffer!", fn);
0300         ndrx_TPset_error_msg(TPEOS, Bstrerror(Berror));
0301     }
0302 
0303     return ret;
0304 }
0305 
0306 /**
0307  * Gracefully remove free up the buffer
0308  * @param descr
0309  * @param buf
0310  */
0311 expublic void UBF_tpfree(typed_buffer_descr_t *descr, char *buf)
0312 {
0313     Bfree((UBFH *)buf);
0314 }
0315 
0316 /**
0317  * Check the boolean expression
0318  * @param descr
0319  * @param buf
0320  * @param expr
0321  * @return TRUE/FALSE.
0322  * In case of error we just return FALSE as not matched!
0323  */
0324 expublic int UBF_test(typed_buffer_descr_t *descr, char *buf, BFLDLEN len, char *expr)
0325 {
0326     int ret=EXFALSE;
0327     char *tree;
0328 
0329     /* compile the xpression */
0330     if (NULL==(tree=Bboolco (expr)))
0331     {
0332         NDRX_LOG(log_error, "Failed to compile expression [%s], err: %s",
0333                                     Bstrerror(Berror));
0334     }
0335 
0336     ret=Bboolev((UBFH *)buf, tree);
0337     
0338     /* Free up the buffer */
0339     Btreefree(tree);
0340 
0341 out:
0342     return ret;
0343 }
0344 /* vim: set ts=4 sw=4 et smartindent: */