Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Bridge command back-ends.
0003  *
0004  * @file cmd_bridge.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 <utlist.h>
0039 
0040 #include <ndrstandard.h>
0041 
0042 #include <ndebug.h>
0043 #include <userlog.h>
0044 #include <ndrxd.h>
0045 #include <ndrxdcmn.h>
0046 
0047 #include "cmd_processor.h"
0048 #include "bridge_int.h"
0049 #include "atmi_shm.h"
0050 /*---------------------------Externs------------------------------------*/
0051 /*---------------------------Macros-------------------------------------*/
0052 /*---------------------------Enums--------------------------------------*/
0053 /*---------------------------Typedefs-----------------------------------*/
0054 /*---------------------------Globals------------------------------------*/
0055 /*---------------------------Statics------------------------------------*/
0056 /*---------------------------Prototypes---------------------------------*/
0057 
0058 /**
0059  * Bridge connection established. If needed we can now start to send the stuff.
0060  * @param call
0061  * @param data
0062  * @param len
0063  * @param context
0064  * @return 
0065  */
0066 expublic int cmd_brcon (command_call_t * call, char *data, size_t len, int context)
0067 {
0068     int ret=EXSUCCEED;
0069     bridge_info_t *brcall = (bridge_info_t *)call;
0070     
0071     /* Will not check for error, bad call could case server to exit. */
0072     ndrx_shm_bridge_connected(brcall->nodeid);
0073     
0074     brd_connected(brcall->nodeid);
0075     
0076 out:
0077     return ret;
0078 }
0079 
0080 /**
0081  * The bridge have been disconnected - remove all services from shm!
0082  * @param call
0083  * @param data
0084  * @param len
0085  * @param context
0086  * @return 
0087  */
0088 expublic int cmd_brdiscon (command_call_t * call, char *data, size_t len, int context)
0089 {
0090     int ret=EXSUCCEED;
0091     bridge_info_t *brcall = (bridge_info_t *)call;
0092 
0093     /* Will not check for error, bad call could case server to exit. */
0094     ndrx_shm_bridge_disco(brcall->nodeid);
0095     
0096     brd_discconnected(brcall->nodeid);
0097     
0098 out:
0099     return ret;
0100 }
0101 
0102 /**
0103  * Update shared mem.
0104  * @param svc_nm - service name
0105  * @param count - final count.
0106  * @return 
0107  */
0108 expublic int brd_lock_and_update_shm(int nodeid, char *svc_nm, int count, char mode)
0109 {
0110     int ret=EXSUCCEED;
0111     
0112     /* ###################### CRITICAL SECTION ###################### */
0113     /* So we make this part critical... */
0114     if (EXSUCCEED!=ndrx_lock_svc_op(__func__))
0115     {
0116         ret=EXFAIL;
0117         goto out;
0118     }
0119 
0120     ret=ndrx_shm_install_svc_br(svc_nm, 0, 
0121                 EXTRUE, nodeid, count, mode, 0);
0122 
0123 
0124     /* Remove the lock! */
0125     ndrx_unlock_svc_op(__func__);
0126     /* ###################### CRITICAL SECTION, END ################# */
0127     
0128 out:
0129     return ret;
0130 }
0131 
0132 /**
0133  * Bridge sends us refersh command.
0134  * @param call
0135  * @param data
0136  * @param len
0137  * @param context
0138  * @return 
0139  */
0140 expublic int cmd_brrefresh (command_call_t * call, char *data, size_t len, int context)
0141 {
0142     int ret=EXSUCCEED;
0143     bridge_refresh_t *refresh = (bridge_refresh_t *)call;
0144     int i, j;
0145     bridgedef_t* br = brd_get_bridge(call->caller_nodeid);
0146     bridgedef_svcs_t * svc_ent;
0147     bridge_refresh_svc_t *ref_ent;
0148     
0149     /* We want temporary hash  */
0150     bridgedef_svcs_t *svcref= NULL;
0151     
0152     if (br==NULL)
0153     {
0154         NDRX_LOG(log_error, "Bridge %d not found!", call->caller_nodeid);
0155         goto out;
0156     }
0157     
0158     /* So we get the full list we should iter over */
0159     for (i=0; i<refresh->count; i++)
0160     {
0161         NDRX_LOG(log_info, "Got service from node: %d - [%s] count: [%d], mode: [%c]", 
0162                 refresh->call.caller_nodeid,
0163                 refresh->svcs[i].svc_nm,
0164                 refresh->svcs[i].count,
0165                 refresh->svcs[i].mode);
0166         ref_ent = &refresh->svcs[i];
0167         
0168         if (BRIDGE_REFRESH_MODE_FULL==refresh->mode)
0169         {
0170             brd_add_svc_to_hash_g(&svcref, ref_ent->svc_nm);
0171         }
0172         
0173         /* So now we should crosscheck the hash tables, if missing, then install
0174          * actually if service count changes, then we do not need to lock the SHM.
0175          */
0176         
0177         /* Update shared mem. */
0178         if (EXSUCCEED!=brd_lock_and_update_shm(br->nodeid, 
0179                 ref_ent->svc_nm, ref_ent->count, ref_ent->mode))
0180         {
0181             NDRX_LOG(log_error, "Failed to update shared mem for [%s]/%d/%c!",
0182                     ref_ent->svc_nm, ref_ent->count, ref_ent->mode);
0183             EXFAIL_OUT(ret);
0184         }
0185         
0186         if (NULL!=(svc_ent = brd_get_svc_brhash(br, refresh->svcs[i].svc_nm)))
0187         {
0188             /* So it was already known to the system, check the mode */
0189             if (ref_ent->mode==BRIDGE_REFRESH_MODE_FULL)
0190             {
0191                 svc_ent->count=ref_ent->count;
0192             }
0193             else
0194             {
0195         /* We receive signed delta */
0196                 svc_ent->count+=ref_ent->count;
0197                 NDRX_LOG(log_debug, "Bridge %d svc hash [%s] count: %d",
0198                         br->nodeid, ref_ent->svc_nm, svc_ent->count);
0199             }
0200             
0201             /* fix - remove zero items from hash... */
0202             if (0==svc_ent->count)
0203             {
0204                 NDRX_LOG(log_warn, "Service count 0 - remove from br hash");
0205                 brd_del_svc_brhash(br, svc_ent, ref_ent->svc_nm);
0206             }
0207             
0208         }
0209         else
0210         {
0211             /* Service not present in hash - so we should add, if it is DIFF >0, then add */
0212             if (ref_ent->count > 0)
0213             {
0214                 NDRX_LOG(log_debug, "Adding service to bridge svc hash");
0215                 /* Add that stuff to bridge! We run in full mode. */
0216                 if (EXSUCCEED!=brd_add_svc_brhash(br, ref_ent->svc_nm, 
0217                         ref_ent->count))
0218                 {
0219                     EXFAIL_OUT(ret);
0220                 }
0221             }
0222         }
0223     } /* For each refresh entry */
0224     
0225     /* Go over the list of services in bridge */
0226     if (BRIDGE_REFRESH_MODE_FULL==refresh->mode)
0227     {
0228         bridgedef_svcs_t *r = NULL;
0229         bridgedef_svcs_t *rtmp = NULL;
0230         
0231         /* Check every their service (what we see in system)
0232          * in their refresh message, if not there, then we should erase 
0233          * it from our view
0234          */
0235         EXHASH_ITER(hh, br->theyr_services, r, rtmp)
0236         {
0237             NDRX_LOG(log_debug, "Cross checking service [%s] in "
0238                                             "refresh msg", r->svc_nm);
0239             if (NULL==brd_get_svc(svcref, r->svc_nm))
0240             {
0241                 /* if sending full refresh at the same time when some delta (+) happened (bit later)
0242                  * and due to bridge re-ordering the delta may come first. Thus currently we
0243                  * will remove the delta
0244                  * TODO: Maybe we could introduce some message sequencing numbers,
0245                  * and if we have seen higher delta that this refresh message,
0246                  * then ignore this update?
0247                  * Or other option would be to ignore the older messages, if
0248                  * we have seen newer. Thus maybe some refresh or delta may be passed.
0249                  * But at least we would be more or less in sync with other node.
0250                  */
0251                 NDRX_LOG(log_warn, "Service [%s] not present in refresh "
0252                 "message, but we see it our view - there was some packet re-ordering or loss! - "
0253                         "Removing it from our view!", r->svc_nm);
0254                 /* Remove stuff from SHM.... */
0255                 brd_lock_and_update_shm(br->nodeid, r->svc_nm, 0, BRIDGE_REFRESH_MODE_FULL);
0256                 /* Remove from hash view! */
0257                 brd_del_svc_brhash(br, r, r->svc_nm);
0258             }
0259             else
0260             {
0261                 NDRX_LOG(log_debug, "Service [%s] present in refresh - OK", 
0262                         r->svc_nm);
0263             }
0264         }
0265     }
0266     
0267 out:
0268 
0269     /* if svcref is not NULL, then clean up the list! */
0270     if (NULL!=svcref)
0271     {
0272         /* Erase the list to avoid memory leak..! */
0273         brd_erase_svc_hash_g(svcref);
0274         svcref=NULL;
0275     }
0276 
0277     return ret;
0278 }
0279 
0280 
0281 
0282 /**
0283  * Do the actual work, generate list of connected bridges...!
0284  * String will be filled from start to end with node id's in random order.
0285  * @param reply
0286  * @param send_size
0287  * @param params
0288  */
0289 expublic void getbrs_reply_mod(command_reply_t *reply, size_t *send_size, mod_param_t *params)
0290 {
0291     command_reply_getbrs_t * info = (command_reply_getbrs_t *)reply;
0292     bridgedef_t *cur = NULL;
0293     bridgedef_t *rtmp = NULL;
0294     int pos = 0;
0295 
0296     reply->msg_type = NDRXD_CALL_TYPE_GETBRS;
0297     /* calculate new send size */
0298     *send_size += (sizeof(command_reply_getbrs_t) - sizeof(command_reply_t));
0299     
0300     memset(info->nodes, 0, sizeof(info->nodes));
0301     
0302     EXHASH_ITER(hh, G_bridge_hash, cur, rtmp)
0303     {    
0304         if (cur->connected)
0305         {
0306             info->nodes[pos] = (char)cur->nodeid;
0307             pos++;
0308         } /* If connected */
0309     } /* EXHASH_ITER */
0310     
0311     br_dump_nodestack(info->nodes, "Returning list of connected nodes");
0312 
0313     NDRX_LOG(log_debug, "magic: %ld", info->rply.magic);
0314 }
0315 
0316 /**
0317  * Return list of connected bridges..
0318  * @param call
0319  * @param data
0320  * @param len
0321  * @param context
0322  * @return 
0323  */
0324 expublic int cmd_getbrs (command_call_t * call, char *data, size_t len, int context)
0325 {
0326     int ret=EXSUCCEED;
0327 
0328     NDRX_LOG(log_warn, "cmd_getbrs: call flags 0x%x", call->flags);
0329 
0330     /* Generate list of connected bridges... (in callback) */
0331     if (EXSUCCEED!=simple_command_reply(call, ret, 0L, NULL, getbrs_reply_mod, 
0332             0L, 0, NULL))
0333     {
0334         userlog("Failed to send reply back to [%s]", call->reply_queue);
0335     }
0336     
0337     NDRX_LOG(log_warn, "cmd_getbrs returns with status %d", ret);
0338     
0339 out:
0340     return ret;
0341 }
0342 /* vim: set ts=4 sw=4 et smartindent: */