OSDN Git Service

Initial commit from 2.1.2-1
[ultramonkey-l7/ultramonkey-l7-v2.git] / src / protomod.c
diff --git a/src/protomod.c b/src/protomod.c
new file mode 100644 (file)
index 0000000..d02eec3
--- /dev/null
@@ -0,0 +1,615 @@
+/*
+ * @file  protomod.c
+ * @brief the framework module of protocol module 
+ * @brief it proceeds common function of protocol module
+ *
+ * L7VSD: Linux Virtual Server for Layer7 Load Balancing
+ * Copyright (C) 2005  NTT COMWARE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ **********************************************************************/
+
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+#include <map>
+
+#include "l7vs_module.h"
+#include "l7vs_dest.h"
+#include "l7vs_service.h"
+#include "l7vs_sched.h"
+#include "l7vs_conn.h"
+#include "l7vs_replication.h"
+#include "logger_wrapper.h"
+
+#if defined(LOGGER_PROCESS_VSD)
+const LOG_CATEGORY_TAG log_cat_protocol = LOG_CAT_L7VSD_PROTOCOL;
+#else
+const LOG_CATEGORY_TAG log_cat_protocol = LOG_CAT_L7VSADM_PROTOCOL;
+#endif
+
+static struct l7vs_protomod *l7vs_protomod_load(char *modname);
+static void l7vs_protomod_unload(struct l7vs_protomod *pmod);
+static gint l7vs_protomod_cmp(struct l7vs_protomod *pmod, char *name);
+
+static int protomod_initialize(struct l7vs_service *srv, struct l7vs_conn *conn ,char *buf ,size_t len , struct l7vs_dest **dest);
+static int protomod_finalize(struct l7vs_service *srv, struct l7vs_conn *conn ,char *buf , size_t len , struct l7vs_dest **dest, int resched);
+static GList *l7vs_protomod_list = NULL;
+
+typedef        std::map<LOG_CATEGORY_TAG,LOG_CATEGORY_TAG> log_category_map;
+
+log_category_map               module_logcategory_map;
+static enum LOG_LEVEL_TAG protomod_getloglevel( const enum LOG_CATEGORY_TAG );
+static void protomod_log_debug( const enum LOG_CATEGORY_TAG,
+                               const unsigned int,
+                               char*,
+                               int,
+                               const char* );
+static void protomod_log_info( const enum LOG_CATEGORY_TAG,
+                               const unsigned int,
+                               char*,
+                               int,
+                               const char* );
+static void protomod_log_warn( const enum LOG_CATEGORY_TAG,
+                               const unsigned int,
+                               char*,
+                               int,
+                               const char* );
+static void protomod_log_error(        const enum LOG_CATEGORY_TAG,
+                               const unsigned int,
+                               char*,
+                               int,
+                               const char* );
+static void protomod_log_fatal(        const enum LOG_CATEGORY_TAG,
+                               const unsigned int,
+                               char*,
+                               int,
+                               const char* );
+
+/*!
+ * Protocol module get function.
+ * @param name [in] Protocol module name.
+ * @return Got protocol module.
+ */
+struct l7vs_protomod *
+l7vs_protomod_get(char *name)
+{
+       struct l7vs_protomod *pmod = NULL;
+
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,1,
+                   "in_function: struct l7vs_protomod* l7vs_protomod_get(char* name): name=\"%s\"", name);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (name == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,2,
+                   "Arg(name) is NULL pointer.");
+               goto get_out;
+       }
+
+       /* lookup from loaded module list */
+       pmod = l7vs_protomod_lookup(name);
+       if (pmod == NULL) {
+               /* load */
+               pmod = l7vs_protomod_load(name);
+               if (pmod == NULL) {
+                       LOGGER_PUT_LOG_ERROR(log_cat_protocol,3,
+                           "Protocol module not found (maybe module problem)");
+                       goto get_out;
+               }
+               pmod->refcnt = 0;
+       }
+
+       pmod->refcnt++;
+
+get_out:
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,2,
+                   "out_function: struct l7vs_protomod* l7vs_protomod_get(char* name): return_value=%p", pmod);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return pmod;
+}
+
+/*!
+ * Protocol module put function.
+ * @param pmod [in] Protocol module.
+ */
+void
+l7vs_protomod_put(struct l7vs_protomod *pmod)
+{
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,3,
+                   "in_function: void l7vs_protomod_put(struct l7vs_protomod* pmod): pmod=%p", pmod);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (pmod == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,4,
+                   "Arg(pmod) is NULL pointer.");
+               goto put_out;
+       }
+
+       if (--pmod->refcnt <= 0) {
+               l7vs_module_remove(&l7vs_protomod_list, pmod);
+               l7vs_protomod_unload(pmod);
+       }
+
+put_out:
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,4,
+                   "out_function: void l7vs_protomod_put(struct l7vs_protomod* pmod)");
+       }
+       /*------ DEBUG LOG END ------*/
+
+}
+
+/*!
+ * Protocol module load function.
+ * @param modname [in] Protocol module name.
+ * @retern Loaded protocol module struct.
+ */
+static struct l7vs_protomod *
+l7vs_protomod_load(char *modname)
+{
+       struct l7vs_protomod *pmod = NULL;
+
+#if defined(LOGGER_PROCESS_ADM)
+       if( module_logcategory_map.empty() ){//make category convert table
+               module_logcategory_map[LOG_CAT_L7VSD_PROTOCOL] = LOG_CAT_L7VSADM_PROTOCOL;
+               module_logcategory_map[LOG_CAT_L7VSD_SYSTEM_MEMORY] = LOG_CAT_L7VSADM_COMMON;
+       }
+#else
+       if( module_logcategory_map.empty() ){
+               module_logcategory_map[LOG_CAT_L7VSD_PROTOCOL] =LOG_CAT_L7VSD_PROTOCOL;
+               module_logcategory_map[LOG_CAT_L7VSD_SYSTEM_MEMORY] =LOG_CAT_L7VSD_SYSTEM_MEMORY;
+       }
+#endif
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG( log_cat_protocol,5,
+                   "in_function: struct l7vs_protomod* l7vs_protomod_load(char* modname): modname=\"%s\"", modname);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (modname == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,5,
+                   "Arg(modname) is NULL pointer.");
+               goto load_out;
+       }
+
+       pmod = (struct l7vs_protomod *)l7vs_module_load(modname, "protomod");
+
+       if (pmod == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,6,
+                   "Module load error.");
+               goto load_out;
+       }
+       pmod->initialize = protomod_initialize;
+       pmod->finalize = protomod_finalize;
+
+#if 0
+       pmod->get_log_level = logger_get_log_level;
+       pmod->put_log_debug = logger_put_log_debug;
+       pmod->put_log_info = logger_put_log_info;
+       pmod->put_log_warn = logger_put_log_warn;
+       pmod->put_log_error = logger_put_log_error;
+       pmod->put_log_debug = logger_put_log_debug;
+#endif
+       pmod->get_log_level     = protomod_getloglevel;
+       pmod->put_log_debug     = protomod_log_debug;
+       pmod->put_log_info      = protomod_log_info;
+       pmod->put_log_warn      = protomod_log_warn;
+       pmod->put_log_error     = protomod_log_error;
+       pmod->put_log_fatal     = protomod_log_fatal;
+
+#ifndef LOGGER_PROCESS_ADM
+       pmod->replication_pay_memory = l7vs_replication_pay_memory;
+#endif
+
+       l7vs_module_register(&l7vs_protomod_list, pmod);
+
+load_out:
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,6,
+                   "out_function: struct l7vs_protomod* l7vs_protomod_load(char* modname): return_value=%p", pmod);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return pmod;
+}
+
+/*!
+ * Protocol module unload function.
+ * @param pmod [in] Protocol module.
+ */
+static void 
+l7vs_protomod_unload(struct l7vs_protomod *pmod)
+{
+       void *h;
+
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,7,
+                   "in_function: void l7vs_protomod_unload(struct l7vs_protomod* pmod): pmod=%p", pmod);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (pmod == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,7,
+                   "Arg(pmod) is NULL pointer.");
+               goto unload_out;
+       }
+
+       h = pmod->handle;
+       if (pmod->fini != NULL) {
+               pmod->fini();
+       }
+       l7vs_module_unload(h);
+
+unload_out:
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,8,
+                   "out_function: void l7vs_protomod_unload(struct l7vs_protomod* pmod)");
+       }
+       /*------ DEBUG LOG END ------*/
+}
+
+/*!
+ * Protocol module lookup function.
+ * @param modname [in] Protocol module name.
+ * @retern Found protocol module struct.
+ */
+struct l7vs_protomod *
+l7vs_protomod_lookup(char *modname)
+{
+       struct l7vs_protomod* pmod = NULL;
+
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,9,
+                   "in_function: struct l7vs_protomod* l7vs_protomod_lookup(char* modname): "
+                   "modname=\"%s\"", modname);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (modname == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,8,
+                   "Arg(modname) is NULL pointer.");
+               goto lookup_out;
+       }
+
+       pmod = (struct l7vs_protomod *) l7vs_module_lookup(l7vs_protomod_list, modname,
+           (GCompareFunc) l7vs_protomod_cmp);
+
+lookup_out:
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,10,
+                   "out_function: struct l7vs_protomod* l7vs_protomod_load(char* modname): "
+                   "return_value=%p", pmod);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return pmod;
+}
+
+/*!
+ * Protocol module name compare function.
+ * @param pmod [in] Protocol module.
+ * @param name [in] Protocol module name.
+ * @retval 0 Match.
+ * @retval <0, >0 Not match.
+ */
+static gint
+l7vs_protomod_cmp(struct l7vs_protomod *pmod, char *name)
+{
+       gint return_value;
+
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,11,
+                   "in_function: gint l7vs_protomod_cmp(struct l7vs_protomod* pmod, char* name): "
+                   "pmod=%p, name=\"%s\"", pmod, name);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (pmod == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,9,
+                   "Arg(pmod) is NULL pointer.");
+               return_value = -1;
+               goto cmp_out;
+       }
+       if (name == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,10,
+                   "Arg(name) is NULL pointer.");
+               return_value = -1;
+               goto cmp_out;
+       }
+
+       return_value = strcmp(pmod->modname, name);
+
+cmp_out:
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,12,
+                   "out_function: gint l7vs_protomod_cmp(struct l7vs_protomod* pmod, char* name): "
+                   "return_value=%d", return_value);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Protocol module initialize function.
+ * @param srv  [in]  Virtual service struct.
+ * @param conn [in]  Client connection struct.
+ * @param buf  [in]  Client request payload.
+ * @param len  [in]  Length of client request payload.
+ * @param dest [out] Destination struct list.
+ * @retval 0  Success.
+ * @retval -1 Error.
+ */
+static int
+protomod_initialize(struct l7vs_service *srv, struct l7vs_conn *conn, char *buf, size_t len, struct l7vs_dest **dest)
+{
+       int return_value = 0;
+
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               char srv_str[DEBUG_STR_LEN] = {0};
+               char conn_str[DEBUG_STR_LEN] = {0};
+               char dest_str[DEBUG_STR_LEN] = {0};
+               l7vs_service_c_str(srv_str, srv);
+               l7vs_conn_c_str(conn_str, conn);
+               if (dest == NULL) {
+                       strncpy(dest_str, "NULL", DEBUG_STR_LEN);
+               }
+               else {
+                       l7vs_dest_c_str(dest_str, *dest);
+               }
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,13,
+                   "in_function: int protomod_initialize(struct l7vs_service* srv, struct l7vs_conn* conn, "
+                   "char* buf, size_t len, struct l7vs_dest** dest): srv=&(%s), conn=&(%s), buf=\"%s\", "
+                   "len=%ld, dest=&(&(%s))", srv_str, conn_str, buf, (long int)len, dest_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (dest == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,11,
+                   "Arg(dest) is NULL pointer.");
+               return_value = -1;
+               goto initialize_out;
+       }
+
+       /* clean up destination list */
+       *dest = NULL;
+
+initialize_out:
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,14,
+                   "out_function: int protomod_initialize(struct l7vs_service* srv, struct l7vs_conn* conn, "
+                   "char* buf, size_t len, struct l7vs_dest** dest): return_value=%d", return_value);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Protocol module finalize function.
+ * @param srv  [in]  Virtual service struct.
+ * @param conn [in]  Client connection struct.
+ * @param buf  [in]  Client request payload.
+ * @param len  [in]  Length of client request payload.
+ * @param dest [out] Destination struct list.
+ * @retval 0  Success.
+ * @retval -1 Error.
+ */
+static int
+protomod_finalize(struct l7vs_service *srv, struct l7vs_conn *conn, char *buf, size_t len, struct l7vs_dest **dest, int resched)
+{
+       GList *l;
+       struct l7vs_dest *d;
+       GList *active_dest = NULL;
+       int return_value = 0;
+
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               char srv_str[DEBUG_STR_LEN] = {0};
+               char conn_str[DEBUG_STR_LEN] = {0};
+               char dest_str[DEBUG_STR_LEN] = {0};
+               l7vs_service_c_str(srv_str, srv);
+               l7vs_conn_c_str(conn_str, conn);
+               if (dest == NULL) {
+                       strncpy(dest_str, "NULL", DEBUG_STR_LEN);
+               }
+               else {
+                       l7vs_dest_c_str(dest_str, *dest);
+               }
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,15,
+                   "in_function: int protomod_finalize(struct l7vs_service* srv, struct l7vs_conn* conn, "
+                   "char* buf, size_t len, struct l7vs_dest** dest, int resched): srv=&(%s), conn=&(%s), buf=\"%s\", "
+                   "len=%ld, dest=&(&(%s)), resched=%d", srv_str, conn_str, buf, (long int)len, dest_str, resched);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (srv == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,12,
+                   "Arg(srv) is NULL pointer.");
+               return_value = -1;
+               goto finalize_out;
+       }
+       if (dest == NULL) {
+               LOGGER_PUT_LOG_ERROR(log_cat_protocol,13,
+                   "Arg(dest) is NULL pointer.");
+               return_value = -1;
+               goto finalize_out;
+       }
+
+       // pick up active real server (weight > 0)
+       for (l = g_list_first(srv->dest_list); l != NULL; l = g_list_next(l)) {
+               d = (struct l7vs_dest*) l->data;
+               if (d->weight > 0) {
+                       active_dest = g_list_append(active_dest, l->data);
+               }
+       }
+
+       if((*dest) != NULL ){
+               // check dest whether it exists in active real server list
+               for( l = g_list_first(active_dest); l != NULL; l = g_list_next(l) ){
+                       d = (struct l7vs_dest*) l->data;
+                       if((d->addr.sin_addr.s_addr == (*dest)->addr.sin_addr.s_addr ) &&
+                          (d->addr.sin_port == (*dest)->addr.sin_port) ){
+                               *dest = d;
+                               goto finalize_out;
+                       }
+               }
+
+               // no reschedule
+               if( resched == 0 ){
+                       LOGGER_PUT_LOG_INFO(log_cat_protocol,1, "RealServer nonexistence.");
+                       return_value = -1;
+                       goto finalize_out;
+               }
+
+               // reschedule
+               *dest = srv->scheduler->schedule(srv, conn);
+
+               if( *dest == NULL ){
+                       LOGGER_PUT_LOG_INFO(log_cat_protocol,2, "RealServer nonexistence.");
+                       return_value = -1;
+                       goto finalize_out;
+               }
+       }
+       else{
+               // schedule
+               *dest = srv->scheduler->schedule(srv, conn);
+
+               if( *dest == NULL ){
+                       LOGGER_PUT_LOG_INFO(log_cat_protocol,3, "RealServer nonexistence.");
+                       return_value = -1;
+                       goto finalize_out;
+               }
+       }
+
+finalize_out:
+       g_list_free(active_dest);
+
+       /*-------- DEBUG LOG --------*/
+       if( LOG_LV_DEBUG == logger_get_log_level( log_cat_protocol ) ){
+               LOGGER_PUT_LOG_DEBUG(log_cat_protocol,16,
+                   "out_function: int protomod_finalize(struct l7vs_service* srv, struct l7vs_conn* conn, "
+                   "char* buf, size_t len, struct l7vs_dest** dest, int resched): return_value=%d", return_value);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+
+/**
+ * log getter local function
+ *
+ **/
+static enum LOG_LEVEL_TAG protomod_getloglevel( const enum LOG_CATEGORY_TAG cat ){
+       log_category_map::iterator itr = module_logcategory_map.find( cat );
+       if( itr != module_logcategory_map.end() ){
+               return logger_get_log_level( itr->second );
+       }
+       else{
+               itr = module_logcategory_map.begin();
+               return logger_get_log_level( itr->second );
+       }
+}
+
+static void protomod_log_debug( const enum LOG_CATEGORY_TAG cat,
+                               const unsigned int message_id,
+                               char* file,
+                               int line,
+                               const char* message ){
+       log_category_map::iterator itr = module_logcategory_map.find( cat );
+       if( itr == module_logcategory_map.end() )
+               itr = module_logcategory_map.begin();
+       logger_put_log_debug( itr->second, message_id, file, line, message );
+}
+
+static void protomod_log_info(  const enum LOG_CATEGORY_TAG cat,
+                               const unsigned int message_id,
+                               char* file,
+                               int   line,
+                               const char* message ){
+       log_category_map::iterator itr = module_logcategory_map.find( cat );
+       if( itr == module_logcategory_map.end() )
+               itr = module_logcategory_map.begin();
+       logger_put_log_info( itr->second, message_id, file, line, message );
+}
+
+static void protomod_log_warn( const enum LOG_CATEGORY_TAG cat,
+                               const unsigned int message_id,
+                               char* file,
+                               int   line,
+                               const char* message ){
+       log_category_map::iterator itr = module_logcategory_map.find( cat );
+       if( itr == module_logcategory_map.end() )
+               itr = module_logcategory_map.begin();
+       logger_put_log_warn( itr->second, message_id, file, line, message );
+}
+
+static void protomod_log_error( const enum LOG_CATEGORY_TAG cat,
+                                const unsigned int message_id,
+                                char* file,
+                                int   line,
+                                const char* message ){
+       log_category_map::iterator itr = module_logcategory_map.find( cat );
+       if( itr == module_logcategory_map.end() )
+               itr = module_logcategory_map.begin();
+       logger_put_log_error( itr->second, message_id, file, line, message );
+}
+
+static void protomod_log_fatal( const enum LOG_CATEGORY_TAG cat,
+                               const unsigned int message_id,
+                               char* file,
+                               int   line,
+                               const char* message ){
+       log_category_map::iterator itr = module_logcategory_map.find( cat );
+       if( itr == module_logcategory_map.end() )
+               itr = module_logcategory_map.begin();
+       logger_put_log_fatal( itr->second, message_id, file, line, message );
+}