Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Server API functions
0003  *
0004  * @file serverapi.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 
0040 #include <atmi.h>
0041 #include <ndebug.h>
0042 #include <tperror.h>
0043 #include <typed_buf.h>
0044 #include <atmi_int.h>
0045 #include "srv_int.h"
0046 #include "userlog.h"
0047 /*---------------------------Externs------------------------------------*/
0048 /*---------------------------Macros-------------------------------------*/
0049 #define API_ENTRY {ndrx_TPunset_error();}
0050 /*---------------------------Enums--------------------------------------*/
0051 /*---------------------------Typedefs-----------------------------------*/
0052 /*---------------------------Globals------------------------------------*/
0053 /*---------------------------Statics------------------------------------*/
0054 /*---------------------------Prototypes---------------------------------*/
0055 
0056 /**
0057  * API function tpreturn
0058  * @param rval
0059  * @param rcode
0060  * @param data
0061  * @param len
0062  * @param flags
0063  */
0064 expublic void tpreturn (int rval, long rcode, char *data, long len, long flags)
0065 {
0066     API_ENTRY;
0067 
0068     _tpreturn(rval, rcode, data, len, flags);
0069 }
0070 
0071 /**
0072  * API function of tpforward
0073  * @param svc
0074  * @param data
0075  * @param len
0076  * @param flags
0077  */
0078 expublic void tpforward (char *svc, char *data, long len, long flags)
0079 {
0080     API_ENTRY;
0081 
0082     _tpforward (svc, data, len, flags);
0083 }
0084 
0085 /**
0086  * Main server thread, continue with polling.
0087  */
0088 expublic void tpcontinue (void)
0089 {
0090     API_ENTRY;
0091     _tpcontinue ();
0092 }
0093 
0094 
0095 /**
0096  * Return server id
0097  * @return Server id (-i argument value). Can be 0 or random value, if server
0098  *                  not intialized
0099  */
0100 expublic int tpgetsrvid (void)
0101 {
0102     API_ENTRY;
0103     return  G_server_conf.srv_id;
0104 }
0105 
0106 /**
0107  * Add poller extension
0108  * @param fd
0109  * @param events
0110  * @param p_pollevent
0111  * @return 
0112  */
0113 expublic int tpext_addpollerfd(int fd, uint32_t events, 
0114         void *ptr1, int (*p_pollevent)(int fd, uint32_t events, void *ptr1))
0115 {
0116     int ret=EXSUCCEED;
0117     char *fn="tpext_addpollerfd";
0118     API_ENTRY;
0119     
0120     if (EXFAIL==fd)
0121     {
0122         ndrx_TPset_error_fmt(TPEINVAL, "%s - invalid fd, %d", fn, fd);
0123         ret=EXFAIL;
0124         goto out;
0125     }
0126     
0127     if (NULL==p_pollevent)
0128     {
0129         ndrx_TPset_error_fmt(TPEINVAL, "%s - invalid p_pollevent=NULL!", fn);
0130         ret=EXFAIL;
0131         goto out;
0132     }
0133     
0134     ret=_tpext_addpollerfd(fd, events, ptr1, p_pollevent);
0135     
0136 out:
0137     return ret;
0138 }
0139 
0140 /**
0141  * Delete poller extension
0142  * @param fd
0143  * @return 
0144  */
0145 expublic int tpext_delpollerfd(int fd)
0146 {
0147     int ret=EXSUCCEED;
0148     char *fn="tpext_delpollerfd";
0149     API_ENTRY;
0150     
0151     if (EXFAIL==fd)
0152     {
0153         ndrx_TPset_error_fmt(TPEINVAL, "%s - invalid fd, %d", fn, fd);
0154         ret=EXFAIL;
0155         goto out;
0156     }
0157     
0158     ret=_tpext_delpollerfd(fd);
0159     
0160 out:
0161     return ret;
0162 }
0163 
0164 /**
0165  * Add periodical check
0166  * @param fd
0167  * @return 
0168  */
0169 expublic int tpext_addperiodcb(int secs, int (*p_periodcb)(void))
0170 {
0171     int ret=EXSUCCEED;
0172     char *fn="tpext_addperiodcb";
0173     API_ENTRY;
0174     
0175     if (secs<=0)
0176     {
0177         ndrx_TPset_error_fmt(TPEINVAL, "%s - invalid secs %d, must be >=0", fn, secs);
0178         ret=EXFAIL;
0179         goto out;
0180     }
0181     
0182     if (NULL==p_periodcb)
0183     {
0184         ndrx_TPset_error_fmt(TPEINVAL, "%s - invalid p_periodcb, it is NULL!", fn);
0185         ret=EXFAIL;
0186         goto out;
0187     }
0188     
0189     ret=_tpext_addperiodcb(secs, p_periodcb);
0190     
0191 out:
0192     return ret;
0193     
0194 }
0195 
0196 /**
0197  * Remove periodical check
0198  * @param fd
0199  * @return 
0200  */
0201 expublic int tpext_delperiodcb(void)
0202 {
0203     API_ENTRY;
0204     
0205     return _tpext_delperiodcb();
0206 }
0207 
0208 /**
0209  * Add before poll check
0210  * @param fd
0211  * @return 
0212  */
0213 expublic int tpext_addb4pollcb(int (*p_b4pollcb)(void))
0214 {
0215     int ret=EXSUCCEED;
0216     char *fn="tpext_addb4pollcb";
0217     API_ENTRY;
0218     
0219     if (NULL==p_b4pollcb)
0220     {
0221         ndrx_TPset_error_fmt(TPEINVAL, "%s - invalid p_b4pollcb, it is NULL!", fn);
0222         ret=EXFAIL;
0223         goto out;
0224     }
0225     
0226     ret=_tpext_addb4pollcb(p_b4pollcb);
0227     
0228 out:
0229     return ret;
0230     
0231 }
0232 
0233 /**
0234  * Remove periodical check
0235  * @param fd
0236  * @return 
0237  */
0238 expublic int tpext_delb4pollcb(void)
0239 {
0240     API_ENTRY;
0241     
0242     return _tpext_delb4pollcb();
0243 }
0244 
0245 /**
0246  * Set server flags, this will be used by bridge.
0247  * @param flags
0248  */
0249 expublic void tpext_configbrige 
0250     (int nodeid, int flags, int (*p_qmsg)(char **buf, int len, char msg_type))
0251 {
0252     
0253     ndrx_TPunset_error();
0254     G_server_conf.flags = flags;
0255     G_server_conf.nodeid = nodeid;
0256     G_server_conf.p_qmsg = p_qmsg;
0257     NDRX_LOG(log_debug, "Bridge %d, flags set to: %d, p_qmsg=%p", 
0258             nodeid, flags, p_qmsg);   
0259 }
0260 
0261 /**
0262  * Mark current process as singleton group lock provider
0263  * @param singlegrp group number to which locks are provided
0264  */
0265 expublic void tpext_configprocgrp_lp (int procgrp_lp_no)
0266 {
0267     ndrx_TPunset_error();
0268     G_server_conf.procgrp_lp_no=procgrp_lp_no;
0269     G_server_conf.flags |= SRV_KEY_FLAGS_PROCGRPLP;
0270     
0271     NDRX_LOG(log_debug, "Singleton procerss group %d lock provder", 
0272             procgrp_lp_no);
0273 }
0274 
0275 /**
0276  * Read current call context data
0277  * NOTE: buffer must be freed by caller!
0278  * + Server context is being reset. Assuming that next action by main thread
0279  * is tpcontinue()
0280  * WARNING! This suspends global tx!
0281  * 
0282  * @param p_buf if not NULL, then use as input buffer, if NULL, then will allocate the buf
0283  * @param p_len if pp_buf not NULL, size of input buffer, on output real size put in pp_buf is set
0284  * @return ptr to p_buf or allocated memory or NULL and tperrno will set to error
0285  */
0286 expublic char * tpsrvgetctxdata2 (char *p_buf, long *p_len)
0287 {
0288     server_ctx_info_t *ret = NULL;
0289     tp_command_call_t *last_call = ndrx_get_G_last_call();
0290     tp_conversation_control_t *p_accept_con;
0291     
0292     API_ENTRY;
0293     
0294     if (NULL==p_buf)
0295     {
0296         ret = NDRX_MALLOC(sizeof(server_ctx_info_t));
0297         if (NULL==ret)
0298         {
0299             ndrx_TPset_error_fmt(TPEOS, "Failed to malloc ctx data: %s", 
0300                     strerror(errno));
0301             goto out;
0302         }
0303     }
0304     else
0305     {
0306         /* p_buf is not NULL */
0307         if (*p_len < sizeof(server_ctx_info_t))
0308         {
0309             ndrx_TPset_error_fmt(TPEOS, "%s: ERROR ! Context data size: %d, "
0310                     "but non NULL buffer size %ld", __func__, 
0311                     strerror(errno), (int)sizeof(server_ctx_info_t), *p_len);
0312             goto out;
0313         }
0314         
0315         ret = (server_ctx_info_t *)p_buf;
0316     }
0317     
0318     *p_len = sizeof(server_ctx_info_t);
0319     
0320     if (tpgetlev())
0321     {
0322         ret->is_in_global_tx = EXTRUE;
0323         if (EXSUCCEED!=tpsuspend(&ret->tranid, 0))
0324         {
0325             userlog("Failed to suspend transaction: [%s]", tpstrerror(tperrno));
0326             NDRX_FREE((char *)ret);
0327             ret = NULL;
0328             goto out;
0329         }
0330     }
0331     else
0332     {
0333         ret->is_in_global_tx = EXFALSE;
0334     }
0335     
0336     /* reset thread data */
0337     memcpy(&ret->G_last_call, last_call, sizeof(ret->G_last_call));
0338     memset(last_call, 0, sizeof(ret->G_last_call));
0339     
0340     p_accept_con = ndrx_get_G_accepted_connection();
0341     memcpy(&ret->G_accepted_connection, p_accept_con, sizeof(*p_accept_con));
0342     memset(p_accept_con, 0, sizeof(*p_accept_con));
0343     
0344 out:
0345     NDRX_LOG(log_debug, "%s: returning %p (last call cd: %d)", 
0346         __func__, ret, ret->G_last_call.cd);
0347     return (char *)ret;
0348 }
0349 
0350 /**
0351  * Original version tpsrvgetctxdata, just wrap the automatically allocated memory
0352  * @return 
0353  */
0354 expublic char * tpsrvgetctxdata (void)
0355 {
0356     long len;
0357     return tpsrvgetctxdata2 (NULL, &len);
0358 }
0359 
0360 /**
0361  * Free up the memory buffer allocated by tpsrvgetctxdata
0362  * @param p_buf buffer allocated by tpsrvgetctxdata or tpsrvgetctxdata2 with p_buf NULL
0363  */
0364 expublic void tpsrvfreectxdata(char *p_buf)
0365 {
0366     NDRX_FREE(p_buf);
0367 }
0368 
0369 /**
0370  * Set context data
0371  * @param data
0372  * @param flags
0373  * @return 
0374  */
0375 expublic int tpsrvsetctxdata (char *data, long flags)
0376 {
0377     int ret=EXSUCCEED;
0378     API_ENTRY;
0379     server_ctx_info_t *ctxdata  = (server_ctx_info_t *)data;
0380     char *fn = "tpsrvsetctxdata";
0381     tp_conversation_control_t *p_accept_con;
0382     tp_command_call_t * last_call = ndrx_get_G_last_call();
0383     
0384     NDRX_LOG(log_debug, "%s: data=%p flags=%ld (last call cd: %d)", 
0385             fn, data, flags, ctxdata->G_last_call.cd);
0386     
0387     if (NULL==data)
0388     {
0389         ndrx_TPset_error_fmt(TPEINVAL, "%s - data is NULL", fn);
0390         EXFAIL_OUT(ret);
0391     }
0392     
0393 #if 0
0394     if (flags & SYS_SRV_THREAD)
0395     {
0396         /* init the client + set reply possible...! */
0397         if (EXSUCCEED!=tpinit(NULL))
0398         {
0399             NDRX_LOG(log_error, "Failed to initialise server thread");
0400             ret=EXFAIL;
0401             goto out;
0402         }
0403     }
0404 #endif
0405     memcpy(last_call, &ctxdata->G_last_call, sizeof(ctxdata->G_last_call));
0406     
0407     p_accept_con = ndrx_get_G_accepted_connection();
0408     memcpy(p_accept_con, &ctxdata->G_accepted_connection, 
0409                 sizeof(*p_accept_con));
0410     
0411     /* Add the additional flags to the user. */
0412     last_call->sysflags |= flags;
0413     
0414     if (flags & TPNOAUTBUF)
0415     {
0416         last_call->autobuf = NULL;
0417     }
0418     
0419     if (ctxdata->is_in_global_tx && EXSUCCEED!=tpresume(&ctxdata->tranid, 0))
0420     {
0421         userlog("Failed to resume transaction: [%s]", tpstrerror(tperrno));
0422         EXFAIL_OUT(ret);
0423     }
0424     
0425 out:
0426     return ret;
0427 }
0428 
0429 /**
0430  * Get current ATMI library flags.
0431  * @return return LIBATMISRV server flags
0432  */
0433 expublic NDRX_API long ndrx_atmisrv_get_flags(void)
0434 {
0435     return G_libatmisrv_flags;
0436 }
0437 
0438 /**
0439  * Set LIBATMISRV. This is very internal function. Use only when you know
0440  * what are you doing.
0441  * @param[in] flags combination of ATMI_SRVLIB_ flags from xatmi.h
0442  */
0443 expublic NDRX_API void ndrx_atmisrv_set_flags(long flags)
0444 {
0445     G_libatmisrv_flags = flags;
0446     NDRX_LOG(log_warn, "ATMI Server flags set to: %lx", G_libatmisrv_flags);
0447 }
0448 
0449 /**
0450  * In case if fails to generate exit request, exit is performed immediately
0451  * otherwise shutdown is requested to main thread
0452  */
0453 expublic void tpexit(void)
0454 {
0455     int ret = EXSUCCEED;
0456     command_call_t call;
0457 
0458     API_ENTRY;
0459     
0460     memset(&call, 0, sizeof(call));
0461     
0462     if (NULL==G_server_conf.service_array)
0463     {
0464         userlog("tpexit() - not a server");
0465         EXFAIL_OUT(ret);
0466     }
0467     else
0468     {
0469         userlog("tpexit requested");
0470     }
0471     
0472     G_shutdown_req=EXTRUE;
0473     
0474     if (EXSUCCEED!=(ret=cmd_generic_call_2(NDRXD_COM_SRVSTOP_RQ, NDRXD_SRC_SERVER,
0475                             NDRXD_CALL_TYPE_GENERIC,
0476                             &call, sizeof(call),
0477                             G_server_conf.service_array[ATMI_SRV_ADMIN_Q]->listen_q,
0478                             G_server_conf.service_array[ATMI_SRV_ADMIN_Q]->q_descr,
0479                             (mqd_t)EXFAIL,
0480                             G_server_conf.service_array[ATMI_SRV_ADMIN_Q]->listen_q,
0481                             0, NULL,
0482                             NULL,
0483                             NULL,
0484                             NULL,
0485                             EXFALSE,
0486                             EXFALSE,
0487                             NULL, NULL, TPNOTIME|TPNOBLOCK, NULL)))
0488     {
0489         NDRX_LOG(log_error, "Failed to send shutdown notification to admin Q - exiting");    
0490         exit(EXFAIL);
0491     }
0492     
0493 out:
0494     
0495     if (EXSUCCEED==ret)
0496     {
0497         NDRX_LOG(log_warn, "tpexit - shutdown enqueued...");
0498     }
0499 }
0500 
0501 
0502 /* vim: set ts=4 sw=4 et smartindent: */