Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief VIEW buffer type support
0003  *   Basically all data is going to be stored in FB.
0004  *   For view not using base as 3000. And the UBF field numbers follows the
0005  *   the field number in the view (1, 2, 3, 4, ...)
0006  *   Sample file:
0007  *   #
0008  *   #type    cname   fbname count flag  size  null
0009  *   #
0010  *   int     in    -   1   -   -   -
0011  *   short    sh    -   2   -   -   -
0012  *   long     lo    -   3   -   -   -
0013  *   char     ch    -   1   -   -   -
0014  *   float    fl    -   1   -   -   -
0015  *   double    db    -   1   -   -   -
0016  *   string    st    -   1   -   15   -
0017  *   carray    ca    -   1   -   15   -
0018  *   END
0019  *
0020  * @file typed_view.c
0021  */
0022 /* -----------------------------------------------------------------------------
0023  * Enduro/X Middleware Platform for Distributed Transaction Processing
0024  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0025  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0026  * This software is released under one of the following licenses:
0027  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0028  * See LICENSE file for full text.
0029  * -----------------------------------------------------------------------------
0030  * AGPL license:
0031  *
0032  * This program is free software; you can redistribute it and/or modify it under
0033  * the terms of the GNU Affero General Public License, version 3 as published
0034  * by the Free Software Foundation;
0035  *
0036  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0037  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0038  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0039  * for more details.
0040  *
0041  * You should have received a copy of the GNU Affero General Public License along 
0042  * with this program; if not, write to the Free Software Foundation, Inc.,
0043  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0044  *
0045  * -----------------------------------------------------------------------------
0046  * A commercial use license is available from Mavimax, Ltd
0047  * contact@mavimax.com
0048  * -----------------------------------------------------------------------------
0049  */
0050 #include <string.h>
0051 #include <stdio.h>
0052 #include <stdlib.h>
0053 #include <memory.h>
0054 #include <errno.h>
0055 #include <dirent.h>
0056 
0057 #include <ndrstandard.h>
0058 #include <typed_buf.h>
0059 #include <ndebug.h>
0060 #include <tperror.h>
0061 #include <ubfutil.h>
0062 
0063 #include <userlog.h>
0064 #include <typed_view.h>
0065 #include <view_cmn.h>
0066 #include <atmi_tls.h> 
0067 #include <fieldtable.h>
0068 
0069 #include "Exfields.h"
0070 /*---------------------------Externs------------------------------------*/
0071 /*---------------------------Macros-------------------------------------*/
0072 /*---------------------------Enums--------------------------------------*/
0073 /*---------------------------Typedefs-----------------------------------*/
0074 /*---------------------------Globals------------------------------------*/
0075 /*---------------------------Statics------------------------------------*/
0076 /*---------------------------Prototypes---------------------------------*/
0077 /**
0078  * Allocate the view object
0079  * @param descr
0080  * @param subtype
0081  * @param len
0082  * @return 
0083  */
0084 expublic char * VIEW_tpalloc (typed_buffer_descr_t *descr, char *subtype, long *len)
0085 {
0086     char *ret=NULL;
0087     ndrx_typedview_t *v;
0088 
0089     if (EXSUCCEED!=ndrx_prepare_type_tables())
0090     {
0091         ndrx_TPset_error_fmt(TPESYSTEM, "%s: Failed to load UBF FD files:%s",
0092             __func__, Bstrerror(Berror));
0093         ret = NULL;
0094         goto out;
0095     }
0096     
0097     if (EXSUCCEED!=ndrx_view_init())
0098     {
0099         ndrx_TPset_error_fmt(TPESYSTEM, "%s: Failed to load view files:%s",
0100             __func__, Bstrerror(Berror));
0101         ret = NULL;
0102         goto out;
0103     }
0104             
0105     v = ndrx_view_get_view(subtype);
0106     
0107     if (NULL==v)
0108     {
0109         NDRX_LOG(log_error, "%s: VIEW [%s] NOT FOUND!", __func__, subtype);
0110         ndrx_TPset_error_fmt(TPENOENT, "%s: VIEW [%s] NOT FOUND!", 
0111                 __func__, subtype);
0112         
0113         goto out;
0114     }
0115     
0116     if (NDRX_VIEW_SIZE_DEFAULT_SIZE>*len)
0117     {
0118         *len = NDRX_VIEW_SIZE_DEFAULT_SIZE;
0119     }
0120     else if (v->ssize < *len)
0121     {
0122         NDRX_LOG(log_warn, "VIEW [%s] structure size is %ld, requested %ld -> "
0123             "upgrading to view size!", subtype, *len, v->ssize);   
0124         *len = v->ssize;
0125     }
0126     
0127     /* Allocate VIEW buffer */
0128     /* Maybe still malloc? */
0129     ret=(char *)NDRX_CALLOC(1, *len);
0130 
0131     if (NULL==ret)
0132     {
0133         NDRX_LOG(log_error, "%s: Failed to allocate VIEW buffer!", __func__);
0134         ndrx_TPset_error_msg(TPEOS, Bstrerror(Berror));
0135         goto out;
0136     }
0137     
0138     if (EXSUCCEED!=ndrx_Bvsinit_int(v, ret))
0139     {
0140         NDRX_LOG(log_error, "%s: Failed to init view: %s!", 
0141             __func__, Bstrerror(Berror));
0142 
0143         ndrx_TPset_error_fmt(TPESYSTEM, "%s: Failed to init view: %s!", 
0144             __func__, Bstrerror(Berror));
0145 
0146         goto out;    
0147     }
0148     
0149 out:
0150     return ret;
0151 }
0152 
0153 /**
0154  * Re-allocate CARRAY buffer. Firstly we will find it in the list.
0155  * @param ptr
0156  * @param size
0157  * @return
0158  */
0159 expublic char * VIEW_tprealloc(typed_buffer_descr_t *descr, char *cur_ptr, long len)
0160 {
0161     char *ret=NULL;
0162 
0163     if (0==len)
0164     {
0165         len = NDRX_VIEW_SIZE_DEFAULT_SIZE;
0166     }
0167 
0168     /* Allocate CARRAY buffer */
0169     ret=(char *)NDRX_REALLOC(cur_ptr, len);
0170     
0171 
0172     return ret;
0173 }
0174 
0175 /**
0176  * Build the outgoing buffer... This will convert the VIEW to internal UBF
0177  * format.
0178  * 
0179  * @param descr
0180  * @param idata
0181  * @param ilen
0182  * @param obuf
0183  * @param olen
0184  * @param flags
0185  * @return 
0186  */
0187 expublic int VIEW_prepare_outgoing (typed_buffer_descr_t *descr, char *idata, long ilen, 
0188                     char *obuf, long *olen, long flags)
0189 {
0190     int ret = EXSUCCEED;
0191     ndrx_view_header *hdr;
0192     buffer_obj_t *bo;
0193     ndrx_typedview_t *v;
0194     
0195     /* WARNING!!! views must be loaded already... 
0196      * otherwise not way to allocate the VIEW buffer...
0197      */
0198     /* get the view */
0199     
0200     bo = ndrx_find_buffer(idata);
0201  
0202     if (NULL==bo)
0203     {
0204         ndrx_TPset_error_fmt(TPEINVAL, "Input buffer not allocated by tpalloc!");
0205         EXFAIL_OUT(ret);
0206     }
0207     
0208     NDRX_DUMP(log_dump, "Outgoing VIEW struct", idata, ilen);
0209     
0210     NDRX_LOG(log_debug, "Preparing outgoing for VIEW [%s]", bo->subtype);
0211     
0212     v = ndrx_view_get_view(bo->subtype);
0213     
0214     if (NULL==v)
0215     {
0216         ndrx_TPset_error_fmt(TPEINVAL, "View not found [%s]!", bo->subtype);
0217         EXFAIL_OUT(ret);
0218     }
0219     
0220     /* Check that we have space enough to prepare for send 
0221      * TODO: send also view name
0222      * TODO: Do we nee
0223      */
0224     
0225     ilen = v->ssize + sizeof(ndrx_view_header);
0226     
0227     if (NULL!=olen && *olen < ilen)
0228     {
0229         ndrx_TPset_error_fmt(TPEINVAL, "Internal buffer space: %d, "
0230                 "but requested: %d", *olen, ilen);
0231         ret=EXFAIL;
0232         goto out;
0233     }
0234     
0235     hdr = (ndrx_view_header *)obuf;
0236     
0237     hdr->vflags=0;
0238     hdr->cksum = v->cksum;
0239     NDRX_STRCPY_SAFE(hdr->vname, v->vname);
0240 
0241     memcpy(hdr->data, idata, v->ssize);
0242     
0243     /* return the actual length! */
0244     if (NULL!=olen)
0245     {
0246         *olen = ilen;
0247     }
0248     
0249 out:
0250     
0251     return ret;
0252 }
0253 
0254 /**
0255  * Prepare incoming buffer. the rcv_data is non xatmi buffer. Thus we will
0256  * just make ptr 
0257  * @param descr
0258  * @param rcv_data
0259  * @param rcv_len
0260  * @param odata
0261  * @param olen
0262  * @param flags
0263  * @return 
0264  */
0265 expublic int VIEW_prepare_incoming (typed_buffer_descr_t *descr, char *rcv_data, 
0266                         long rcv_len, char **odata, long *olen, long flags)
0267 {
0268     int ret=EXSUCCEED;
0269     long existing_size;
0270     ndrx_view_header *p_hdr = (ndrx_view_header *)rcv_data;
0271     char *p_out;
0272     buffer_obj_t *outbufobj=NULL;
0273     ndrx_typedview_t *v;
0274     
0275     NDRX_LOG(log_debug, "Entering %s", __func__);
0276     
0277     if (EXSUCCEED!=ndrx_view_init())
0278     {
0279         ndrx_TPset_error_fmt(TPESYSTEM, "%s: Failed to load view files!",  __func__);
0280         EXFAIL_OUT(ret);
0281     }
0282     
0283     /* Resolve the view data, get the size... */
0284     
0285     v = ndrx_view_get_view(p_hdr->vname);
0286     
0287     if (NULL==v)
0288     {
0289         userlog("View [%s] not defined!", p_hdr->vname);
0290         ndrx_TPset_error_fmt(TPEINVAL, "View [%s] not defined!", p_hdr->vname);
0291         EXFAIL_OUT(ret);
0292     }
0293     
0294     NDRX_LOG(log_debug, "Received VIEW [%s]", p_hdr->vname);
0295 
0296     /* Figure out the passed in buffer */
0297     if (NULL==(outbufobj=ndrx_find_buffer(*odata)))
0298     {
0299         ndrx_TPset_error_fmt(TPEINVAL, "Output buffer %p is not allocated "
0300                                         "with tpalloc()!", *odata);
0301         ret=EXFAIL;
0302         goto out;
0303     }
0304 
0305     /* Check the data types */
0306     if (NULL!=outbufobj)
0307     {
0308         /* If we cannot change the data type, then we trigger an error */
0309         if (flags & TPNOCHANGE && (outbufobj->type_id!=BUF_TYPE_VIEW ||
0310                 0!=strcmp(outbufobj->subtype, p_hdr->vname)))
0311         {
0312             /* Raise error! */
0313             ndrx_TPset_error_fmt(TPEOTYPE, "Receiver expects %s/%s but got %s/%s buffer",
0314                     G_buf_descr[BUF_TYPE_VIEW].type, 
0315                     p_hdr->vname,
0316                     G_buf_descr[outbufobj->type_id].type,
0317                     outbufobj->subtype);
0318             EXFAIL_OUT(ret);
0319         }
0320         
0321         /* If we can change data type and this does not match, then
0322          * we should firstly free it up and then bellow allow to work in mode
0323          * when odata is NULL!
0324          */
0325         if (outbufobj->type_id!=BUF_TYPE_VIEW || 0!=strcmp(outbufobj->subtype, 
0326                 p_hdr->vname) )
0327         {
0328             NDRX_LOG(log_info, "User buffer %s/%s is different, "
0329                     "free it up and re-allocate as VIEW/%s", 
0330                     G_buf_descr[outbufobj->type_id].type,
0331                     (outbufobj->subtype==NULL?"NULL":outbufobj->subtype),
0332                     p_hdr->vname);
0333             
0334             ndrx_tpfree(*odata, outbufobj);
0335             *odata=NULL;
0336         }
0337     }
0338     
0339     /* check the output buffer */
0340     if (NULL!=*odata)
0341     {
0342         p_out = (char *)*odata;
0343         NDRX_LOG(log_debug, "%s: Output buffer exists", __func__);
0344         
0345         existing_size=outbufobj->size;
0346 
0347         NDRX_LOG(log_debug, "%s: Output buffer size (struct size): %ld, "
0348                 "received %ld", __func__,
0349                             existing_size, v->ssize);
0350         
0351         if (existing_size>=v->ssize)
0352         {
0353             /* re-use existing buffer */
0354             NDRX_LOG(log_debug, "%s: Using existing buffer", __func__);
0355         }
0356         else
0357         {
0358             /* Reallocate the buffer, because we have missing some space */
0359             char *new_addr;
0360             NDRX_LOG(log_debug, "%s: Reallocating", __func__);
0361             
0362             if (NULL==(new_addr=ndrx_tprealloc(*odata, v->ssize)))
0363             {
0364                 NDRX_LOG(log_error, "%s: _tprealloc failed!", __func__);
0365                 EXFAIL_OUT(ret);
0366             }
0367 
0368             /* allocated OK, return new address */
0369             *odata = new_addr;
0370             p_out = *odata;
0371         }
0372     }
0373     else
0374     {
0375         /* allocate the buffer */
0376         NDRX_LOG(log_debug, "%s: Incoming buffer where missing - "
0377                                          "allocating new!", __func__);
0378 
0379         *odata = ndrx_tpalloc(&G_buf_descr[BUF_TYPE_VIEW], NULL, 
0380                 p_hdr->vname, v->ssize);
0381 
0382         if (NULL==*odata)
0383         {
0384             /* error should be set already */
0385             NDRX_LOG(log_error, "Failed to allocate new buffer!");
0386             goto out;
0387         }
0388 
0389         p_out = *odata;
0390     }
0391     
0392     
0393     /* Verify checksum 
0394     if (v->cksum!=p_hdr->cksum)
0395     {
0396         NDRX_LOG(log_error, "Invalid checksum for VIEW [%s] received. Our cksum: "
0397                 "%ld, their: %ld - try to recompile VIEW with viewc!",
0398                 v->vname, (long)v->cksum, (long)p_hdr->cksum);
0399         
0400         ndrx_TPset_error_fmt(TPEINVAL, "Invalid checksum for VIEW [%s] "
0401                 "received. Our cksum: "
0402                 "%ld, their: %ld - try to recompile VIEW with viewc!",
0403                 v->vname, (long)v->cksum, (long)p_hdr->cksum);
0404         EXFAIL_OUT(ret);
0405     }
0406     */
0407     /* copy off the data */
0408     memcpy(*odata, p_hdr->data, v->ssize);
0409     
0410     if (NULL!=olen)
0411     {
0412         *olen = v->ssize;
0413     }
0414     
0415     NDRX_DUMP(log_dump, "Incoming VIEW struct", *odata, v->ssize);
0416     
0417 out:
0418     return ret;
0419 }
0420 
0421 /**
0422  * Gracefully remove free up the buffer
0423  * @param descr
0424  * @param buf
0425  */
0426 expublic void VIEW_tpfree(typed_buffer_descr_t *descr, char *buf)
0427 {
0428     NDRX_FREE(buf);
0429 }
0430 
0431 
0432 /**
0433  * Check the expression on buffer.
0434  * @param descr
0435  * @param buf
0436  * @param expr
0437  * @return TRUE/FALSE.
0438  * In case of error we just return FALSE as not matched!
0439  */
0440 expublic int VIEW_test(typed_buffer_descr_t *descr, char *buf, BFLDLEN len, char *expr)
0441 {
0442     int ret=EXFALSE;
0443 
0444     NDRX_LOG(log_error, "VIEW buffers do not support event filters! Expr: [%s]", expr);
0445     userlog("VIEW buffers do not support event filters! Expr: [%s]", expr);
0446     
0447     return ret;
0448 }
0449 
0450 /* vim: set ts=4 sw=4 et smartindent: */