--- /dev/null
+/*
+ * @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 );
+}