OSDN Git Service

Initial commit from 2.1.2-1
[ultramonkey-l7/ultramonkey-l7-v2.git] / module / protocol / protomod_pfilter.c
diff --git a/module/protocol/protomod_pfilter.c b/module/protocol/protomod_pfilter.c
new file mode 100644 (file)
index 0000000..9697067
--- /dev/null
@@ -0,0 +1,1261 @@
+/*
+ * @file  protomod_pfilter.c
+ * @brief protocol module of HTTP.
+ * @brief this module provide session persistence by URL.
+ *
+ * L7VSD: Linux Virtual Server for Layer7 Load Balancing
+ * Copyright (C) 2008  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
+ *
+ **********************************************************************/
+
+#define        __STDC_LIMIT_MACROS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <getopt.h>
+#include "l7vs_service.h"
+#include "l7vs_conn.h"
+#include "l7vs_dest.h"
+#include "l7vs_module.h"
+#include <fnmatch.h>
+
+#include <iostream>
+#ifdef USE_BOOST_XPRESSIVE
+    #include <boost/xpressive/xpressive.hpp>
+#else
+    #include <boost/regex.hpp>
+#endif
+
+#define SERVICE_ARG_MAXSIZE    (512)
+#define PATTERN_MATCH_MAXSIZE  (128)
+#define URL_SERVICE_NUMBER     (128)
+#define X_FORWARDED_FOR_LENGTH (48)
+
+struct l7vs_pfilter_service {
+       handle_t service_handle;
+       char pattern_match[PATTERN_MATCH_MAXSIZE];
+       int read_byte;
+#ifdef USE_BOOST_XPRESSIVE
+       boost::xpressive::sregex regex;
+#else
+       boost::regex regex;
+#endif
+       int reschedule;
+};
+
+struct  l7vs_pfilter_service_arg {
+       char pattern_match[PATTERN_MATCH_MAXSIZE];
+       int read_byte;
+       int reschedule;
+};
+
+static void  fini(void);
+static int   create(void*, handle_t);
+static void* create_sa(struct l7vs_service_arg*);
+static int   compare(handle_t, handle_t);
+static int   match_cldata(struct l7vs_service*, struct l7vs_conn*,
+       char*, size_t*, struct l7vs_dest**, int*);
+static int   analyze_rsdata(struct l7vs_service*, struct l7vs_conn*,
+       char*, size_t*);
+static int   destroy(handle_t);
+static void  destroy_sa(void**);
+static int   service_arg(struct l7vs_service_arg_multi*, handle_t);
+static int   parse(void*, int, char**);
+
+static struct l7vs_pfilter_service *l7vs_protomod_pfilter_search_service(handle_t);
+static struct l7vs_pfilter_service *l7vs_protomod_pfilter_create_service();
+static struct l7vs_pfilter_service *l7vs_protomod_pfilter_create_temp_service();
+
+static void l7vs_pfilter_service_c_str(char*, struct l7vs_pfilter_service*);
+static void l7vs_pfilter_service_arg_c_str(char*, struct l7vs_pfilter_service_arg*);
+
+struct l7vs_pfilter_service *pfilter_service_list[URL_SERVICE_NUMBER];
+
+static struct l7vs_protomod pfilter_protomod = {
+       NULL,           /* handle */
+       "pfilter",          /* modname */
+       0,              /* refcnt */
+       0,              /* fast schedule */
+       create,         /* create function */
+       compare,        /* compare function */
+       match_cldata,   /* match_cldata function */
+       analyze_rsdata, /* analyze_rsdata function */
+       destroy,        /* destroy function */
+       fini,           /* fini function */
+       create_sa,      /* create_sa function */
+       service_arg,    /* service_arg function */
+       parse,          /* parse function */
+       destroy_sa,     /* destroy_sa function */
+       NULL,           /* initialize function */
+       NULL,           /* finalize function */
+       NULL,           /* get_log_level function */
+       NULL,           /* put_log_debug function */
+       NULL,           /* put_log_info function */
+       NULL,           /* put_log_warn function */
+       NULL,           /* put_log_error function */
+       NULL            /* put_log_fatal function */
+};
+
+/*!
+ * Protocol module initialize function. This function run when dlopen and dlsym at first time.
+ * @param[in] handle dlopen's handle
+ * @return l7vs_protomod struct
+ */
+extern "C" struct l7vs_protomod *
+init(void *handle)
+{
+       struct l7vs_protomod* return_value = NULL;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,283,
+                   "in_function: struct l7vs_protomod* init(void* handle): handle=%p", handle);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (handle == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,246, "Arg(handle) is NULL pointer.");
+               goto init_out;
+       }
+
+       /* initialize pfilter service list */
+       memset(pfilter_service_list, 0, sizeof(struct l7vs_pfilter_service *) * URL_SERVICE_NUMBER);
+       /* set dlopen's handle */
+       pfilter_protomod.handle = handle;
+
+       return_value = &pfilter_protomod;
+
+init_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char protomod_str[DEBUG_STR_LEN] = {0};
+               l7vs_protomod_c_str(protomod_str, &pfilter_protomod);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,284,
+                   "out_function: struct l7vs_protomod* init(void* handle): return=&(%s)", protomod_str);
+       }
+       /*------ DEBUG LOG END ------*/
+       return return_value;
+}
+
+/*!
+ * Protocol module finalize function. free all pfilter service list just in case.
+ * @param   void
+ * @return  void
+ */
+static void
+fini(void)
+{
+       /* pfilter service list counter */
+       int service_number = 0;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,285, "in_function: void fini(void)");
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check all pfilter service list */
+       for (service_number = 0; service_number < URL_SERVICE_NUMBER; ++service_number) {
+               /* if pointer that does not point NULL exists ... */
+               if (pfilter_service_list[service_number] != NULL) {
+
+                       /*-------- DEBUG LOG --------*/
+                       if (pfilter_protomod.get_log_level != NULL &&
+                           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+                               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,63, "free: %p",
+                                   pfilter_service_list[service_number]);
+                       }
+                       /*------ DEBUG LOG END ------*/
+
+                       /* free and points NULL */
+                       free(pfilter_service_list[service_number]);
+                       pfilter_service_list[service_number] = NULL;
+               }
+       }
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,286, "out_function: void fini(void)");
+       }
+       /*------ DEBUG LOG END ------*/
+}
+
+/*!
+ * Create pfilter service struct.
+ * @param  pfilter_arg    pfilter service argument struct
+ * @param  service_handle a unique service ID
+ * @retval 0  successfully create pfilter service.
+ * @retval -1 some errors occur.
+ */
+static int
+create(void *pfilter_arg, handle_t service_handle)
+{
+       struct l7vs_pfilter_service *pfilter_service;
+       struct l7vs_pfilter_service_arg *pfilter_service_arg;
+       int return_value = 0;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char pfilter_arg_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_arg_c_str(pfilter_arg_str, (struct l7vs_pfilter_service_arg*) pfilter_arg);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,287,
+                   "in_function: int create(void* pfilter_arg, handle_t service_handle):pfilter_arg=&(%s), "
+                   "service_handle=%d", pfilter_arg_str, service_handle);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (pfilter_arg == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,247, "Arg(pfilter_arg) is NULL pointer.");
+               return_value = -1;
+               goto create_out;
+       }
+
+       if (service_handle != TEMP_SERVICEHANDLE) {
+               /* search empty pfilter service list and create pfilter service */
+               pfilter_service = l7vs_protomod_pfilter_create_service();
+       } else {
+               /* create temporary pfilter service */
+               pfilter_service = l7vs_protomod_pfilter_create_temp_service();
+       }
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char pfilter_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_c_str(pfilter_str, pfilter_service);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,288, "pointer assign: pfilter_service=&(%s)",
+                   pfilter_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       if (pfilter_service == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,248, "Could not make pfilter service.");
+               return_value = -1;
+               goto create_out;
+       }
+
+       pfilter_service_arg = (struct l7vs_pfilter_service_arg *) pfilter_arg;
+
+       /* set service handle, pattern match and reschedule flag */
+       pfilter_service->service_handle = service_handle;
+       strncpy(pfilter_service->pattern_match, pfilter_service_arg->pattern_match, PATTERN_MATCH_MAXSIZE);
+       pfilter_service->read_byte = pfilter_service_arg->read_byte;
+       if (pfilter_service_arg->pattern_match) {
+               try {
+#ifdef USE_BOOST_XPRESSIVE
+                       pfilter_service->regex = boost::xpressive::sregex::compile(pfilter_service_arg->pattern_match);
+#else
+                       pfilter_service->regex.assign(pfilter_service_arg->pattern_match);
+#endif
+               }
+               catch (...) {
+                       PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,249, "Regex pattern error.");
+                       return_value = -1;
+                       goto create_out;
+               }
+       }
+       pfilter_service->reschedule = pfilter_service_arg->reschedule;
+
+create_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,289,
+                   "out_function: int create(void* pfilter_arg, handle_t service_handle):return_value=%d",
+                   return_value);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Create pfilter service argument struct.
+ * @param[out] srv_arg service argument struct
+ * @return pfilter service argument struct
+ */
+static void *
+create_sa(struct l7vs_service_arg *srv_arg)
+{
+       struct l7vs_pfilter_service_arg *pfilter_service_arg;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char service_arg_str[DEBUG_STR_LEN] = {0};
+               l7vs_service_arg_c_str(service_arg_str, srv_arg);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,290,
+                   "in_function: void* create_sa(struct l7vs_service_arg* srv_arg):srv_arg=&(%s)",
+                   service_arg_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (srv_arg == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,250, "Arg(srv_arg) is NULL pointer.");
+               pfilter_service_arg = NULL;
+               goto create_sa_out;
+       }
+
+       /* create pfilter service argument struct */
+       pfilter_service_arg = (struct l7vs_pfilter_service_arg *) calloc(1, sizeof(struct l7vs_pfilter_service_arg));
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,64, "calloc: addr=%p, size=%ld",
+                   pfilter_service_arg, (unsigned long int) sizeof(struct l7vs_pfilter_service_arg));
+       }
+       /*------ DEBUG LOG END ------*/
+
+       if (pfilter_service_arg == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,56, "Could not allocate memory.");
+               goto create_sa_out;
+       }
+
+       /* set pfilter service argument size and protomod name "pfilter" */
+       srv_arg->len = sizeof(struct l7vs_pfilter_service_arg);
+       strcpy(srv_arg->protomod, pfilter_protomod.modname);
+
+create_sa_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char pfilter_service_arg_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_arg_c_str(pfilter_service_arg_str, pfilter_service_arg);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,291,
+                   "out_function: void* create_sa(struct l7vs_service_arg* srv_arg):return_value=&(%s)",
+                   pfilter_service_arg_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return (void*) pfilter_service_arg;
+}
+
+/*!
+ * Compare two service.
+ * @param[in] srv_handle1 one of a unique service ID
+ * @param[in] srv_handle2 one of a unique service ID
+ * @retval 0  they matched perfectly.
+ * @retval -1 they are different.
+ */
+static int
+compare(handle_t srv_handle1, handle_t srv_handle2)
+{
+       struct l7vs_pfilter_service *pfilter_srv1, *pfilter_srv2;
+       int return_value = 0;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,292,
+                   "in_function: int compare(handle_t srv_handle1, handle_t srv_handle2):"
+                   "srv_handle1=%u, srv_handle2=%u", srv_handle1, srv_handle2);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* search service that has such a service ID(1) */
+       pfilter_srv1 = l7vs_protomod_pfilter_search_service(srv_handle1);
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char pfilter_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_c_str(pfilter_str, pfilter_srv1);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,293, "pointer assign: pfilter_srv1=&(%s)",
+                   pfilter_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       if (pfilter_srv1 == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,251,
+                   "Could not find such service handle's pfilter service.");
+               return_value = -1;
+               goto compare_out;
+       }
+
+       /* search service that has such a service ID(2) */
+       pfilter_srv2 = l7vs_protomod_pfilter_search_service(srv_handle2);
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char pfilter_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_c_str(pfilter_str, pfilter_srv2);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,294, "pointer assign: pfilter_srv2=&(%s)",
+                   pfilter_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       if (pfilter_srv2 == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,252,
+                   "Could not find such service handle's pfilter service.");
+               return_value = -1;
+               goto compare_out;
+       }
+
+       /* compare two pattern match */
+       if (strcmp(pfilter_srv1->pattern_match, pfilter_srv2->pattern_match) != 0) {
+               return_value = -1;
+               goto compare_out;
+       }
+
+compare_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,295,
+                   "out_function: int compare(handle_t srv_handle1, handle_t srv_handle2):return_value=%d",
+                   return_value);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Check the client packet and determine a real server.
+ * @param[in]  srv service struct include service handle, protocol module and schedule module.
+ * @param[in]  conn connection data.
+ * @param[in]  request packet data from client
+ * @param[in]  len length of packet data
+ * @param[out] dest destination (real server) list
+ * @param[out] tcps TCP Splicer flag
+ * @retval 0  successfully check packet data
+ * @retval -1 some errors occur.
+ */
+static int
+match_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
+      char *request, size_t *len, struct l7vs_dest **dest, int *tcps)
+{
+       struct l7vs_pfilter_service *pfilter_service;
+       int ret;
+       int return_value = 0;
+    std::string packet_data;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char srv_str[DEBUG_STR_LEN] = {0};
+               char conn_str[DEBUG_STR_LEN] = {0};
+               char dest_str[DEBUG_STR_LEN] = {0};
+               char len_str[DEBUG_STR_LEN] = {0};
+               char tcps_str[DEBUG_STR_LEN] = {0};
+               l7vs_service_c_str(srv_str, srv);
+               l7vs_conn_c_str(conn_str, conn);
+               if (dest != NULL) {
+                       l7vs_dest_c_str(dest_str, *dest);
+               }
+               else {
+                       strncpy(dest_str, "NULL", DEBUG_STR_LEN);
+               }
+               if (len != NULL) {
+                       snprintf(len_str, DEBUG_STR_LEN, "%lu", (unsigned long int) *len);
+               }
+               else {
+                       strncpy(len_str, "NULL", DEBUG_STR_LEN);
+               }
+               if (tcps != NULL) {
+                       snprintf(tcps_str, DEBUG_STR_LEN, "%d", *tcps);
+               }
+               else {
+                       strncpy(tcps_str, "NULL", DEBUG_STR_LEN);
+               }
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,296,
+                   "in_function: int match_cldata(struct l7vs_service* srv, struct l7vs_conn* conn, "
+                   "char* request, size_t* len, struct l7vs_dest** dest, int* tcps):srv=&(%s), conn=&(%s), "
+                   "request=\"%s\", len=&(%s), dest=&(&(%s)), tcps=&(%s)",
+                   srv_str, conn_str, request, len_str, dest_str, tcps_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (srv == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,253, "Arg(srv) is NULL pointer.");
+               return_value = -1;
+               goto match_cldata_out;
+       }
+       if (srv->pm == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,254, "Arg(srv->pm) is NULL pointer.");
+               return_value = -1;
+               goto match_cldata_out;
+       }
+       if (request == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,255, "Arg(request) is NULL pointer.");
+               return_value = -1;
+               goto match_cldata_out;
+       }
+       if (len == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,256, "Arg(len) is NULL pointer.");
+               return_value = -1;
+               goto match_cldata_out;
+       }
+       if (dest == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,257, "Arg(dest) is NULL pointer.");
+               return_value = -1;
+               goto match_cldata_out;
+       }
+       if (tcps == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,258, "Arg(tcps) is NULL pointer.");
+               return_value = -1;
+               goto match_cldata_out;
+       }
+
+       /* search service that has such a service ID */
+       pfilter_service = l7vs_protomod_pfilter_search_service(srv->handle);
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char pfilter_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_c_str(pfilter_str, pfilter_service);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,297, "pointer assign: pfilter_service=&(%s)",
+                   pfilter_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       if (pfilter_service == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,259, "Could not find such service handle's pfilter service.");
+               return_value = -1;
+               goto match_cldata_out;
+       }
+
+       /* initialize protocol module ... clear destination list */
+       ret = srv->pm->initialize(srv, conn, request, *len, dest);
+       if (ret != 0) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,260, "Could not initialize protomod.");
+               return_value = -1;
+               goto match_cldata_out;
+       }
+
+       /* check pattern_match != 0 */
+       if (pfilter_service->pattern_match[0] == '\0') {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,261, "Pattern match is NULL pointer");
+               return_value = -1;
+               goto match_cldata_out;
+       }
+
+       /* check pattern match */
+       if (*len > pfilter_service->read_byte) {
+        packet_data = std::string(request, pfilter_service->read_byte);
+       }
+    else {
+        packet_data = std::string(request, *len);
+    }
+
+#ifdef USE_BOOST_XPRESSIVE
+       if ( boost::xpressive::regex_search(packet_data, pfilter_service->regex) ) {
+#else
+       if ( boost::regex_search(packet_data, pfilter_service->regex) ) {
+#endif
+               return_value = -1;
+               goto match_cldata_out;
+       }
+
+       *tcps = 0;
+
+       /* finalize */
+       ret = srv->pm->finalize(srv, conn, request, *len, dest, pfilter_service->reschedule);
+       if (ret != 0) {
+               PUT_LOG_INFO(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,18, "Could not finalize protomod. (Realserver decision failure)");
+               return_value = -1;
+               goto match_cldata_out;
+       }
+
+match_cldata_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,298,
+                   "out_function: int match_cldata(struct l7vs_service* srv, struct l7vs_conn* conn, "
+                   "char* request, size_t* len, struct l7vs_dest** dest, int* tcps):return_value=%d",
+                   return_value);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Check the real server packet and insert a Set-Cookie field.
+ * @param[in] srv service struct include service handle, protocol module and schedule module.
+ * @param[in] conn connection data.
+ * @param[in] response packet data from real server
+ * @param[in] len length of packet data. it will be lengthened.
+ * @retval 0  successfully check packet data.
+ * @retval -1 some errors occur.
+ */
+static int
+analyze_rsdata(struct l7vs_service *srv, struct l7vs_conn *conn,
+       char *response, size_t *len)
+{
+       int return_value = 0;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char srv_str[DEBUG_STR_LEN] = {0};
+               char conn_str[DEBUG_STR_LEN] = {0};
+               char len_str[DEBUG_STR_LEN] = {0};
+               l7vs_service_c_str(srv_str, srv);
+               l7vs_conn_c_str(conn_str, conn);
+               if (len != NULL) {
+                       snprintf(len_str, DEBUG_STR_LEN, "%lu", (unsigned long int) *len);
+               }
+               else {
+                       strncpy(len_str, "NULL", DEBUG_STR_LEN);
+               }
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,299,
+                   "in_function: int analyze_rsdata(struct l7vs_service* srv, struct l7vs_conn* conn, "
+                   "char* response, size_t* len):srv=&(%s), conn=&(%s), response=\"%s\", len=&(%s)",
+                   srv_str, conn_str, response, len_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (srv == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,262, "Arg(srv) is NULL pointer.");
+               return_value = -1;
+               goto analyze_rsdata_out;
+       }
+       if (conn == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,263, "Arg(conn) is NULL pointer.");
+               return_value = -1;
+               goto analyze_rsdata_out;
+       }
+       if (conn->dest == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,264, "Arg(conn->dest) is NULL pointer.");
+               return_value = -1;
+               goto analyze_rsdata_out;
+       }
+       if (response == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,265, "Arg(response) is NULL pointer.");
+               return_value = -1;
+               goto analyze_rsdata_out;
+       }
+       if (len == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,266, "Arg(len) is NULL pointer.");
+               return_value = -1;
+               goto analyze_rsdata_out;
+       }
+
+       /* sorry flag check */
+       if (conn->sorry_conn_flag == 1) {
+               /*-------- DEBUG LOG --------*/
+               if (pfilter_protomod.get_log_level != NULL &&
+                   LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+                       PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,300, "Response from sorry server.");
+               }
+               /*------ DEBUG LOG END ------*/
+               goto analyze_rsdata_out;
+       }
+
+analyze_rsdata_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,301,
+                   "out_function: int analyze_rsdata(struct l7vs_service* srv, struct l7vs_conn* conn, "
+                   "char* response, size_t* len):return_value=%d", return_value);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Destroy pfilter service
+ * @param[in] srv_handle a unique service ID
+ * @retval 0  successfully check packet data.
+ * @retval -1 some errors occur.
+ */
+static int
+destroy(handle_t srv_handle)
+{
+       /* pfilter service list counter */
+       int service_number = 0;
+       int free_flag = 0;
+       int return_value = 0;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,302,
+                   "in_function: int destroy(handle_t srv_handle):srv_handle=%u",
+                   srv_handle);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check all pfilter service list */
+       for (service_number = 0; service_number < URL_SERVICE_NUMBER; ++service_number) {
+               /* found pfilter service that has srv_handle */
+               if (pfilter_service_list[service_number] != NULL && 
+                   pfilter_service_list[service_number]->service_handle == srv_handle) {
+
+                       /*-------- DEBUG LOG --------*/
+                       if (pfilter_protomod.get_log_level != NULL &&
+                           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+                               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,65, "free: %p",
+                                   pfilter_service_list[service_number]);
+                       }
+                       /*------ DEBUG LOG END ------*/
+
+                       /* free and NULL */
+                       free(pfilter_service_list[service_number]);
+                       pfilter_service_list[service_number] = NULL;
+
+                       free_flag = 1;
+                       break;
+               }
+       }
+       
+       /* pfilter service was not found */
+       if (free_flag == 0) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,267, "Could not find such service handle's pfilter service.");
+               return_value = -1;
+               goto destroy_out;
+       }
+
+destroy_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,303,
+                   "out_function: int destroy(handle_t srv_handle):return_value=%d",
+                   srv_handle);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Destroy pfilter service argument
+ * @param[in] pfilter_arg pfilter service argument
+ * @return void
+ */
+static void
+destroy_sa(void **pfilter_arg)
+{
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char pfilter_arg_str[DEBUG_STR_LEN] = {0};
+               if (pfilter_arg != NULL) {
+                       l7vs_pfilter_service_arg_c_str(pfilter_arg_str, (struct l7vs_pfilter_service_arg*) *pfilter_arg);
+               }
+               else {
+                       strncpy(pfilter_arg_str, "NULL", DEBUG_STR_LEN);
+               }
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,304,
+                   "in_function: void destroy_sa(void** pfilter_arg):pfilter_arg=&(&(%s))",
+                   pfilter_arg_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (pfilter_arg == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,268, "Arg(pfilter_arg) is NULL pointer.");
+       }
+       else if (*pfilter_arg == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,269, "Arg(*pfilter_arg) is NULL pointer.");
+       }
+       else {
+               /*-------- DEBUG LOG --------*/
+               if (pfilter_protomod.get_log_level != NULL &&
+                   LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+                       PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,66, "free: %p",
+                           *pfilter_arg);
+               }
+               /*------ DEBUG LOG END ------*/
+
+               /* free and NULL */
+               free((struct l7vs_pfilter_service_arg*) *pfilter_arg);
+               *pfilter_arg = NULL;
+       }
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,305,
+                   "out_function: void destroy_sa(void** pfilter_arg)");
+       }
+       /*------ DEBUG LOG END ------*/
+}
+
+/*!
+ * Create strings for service list of l7vsadm
+ * @param  srv_arg service argument struct
+ * @param  srv_handle a unique service ID
+ * @retval 0  successfully create strings
+ * @retval -1 some errors occur.
+ */
+static int
+service_arg(struct l7vs_service_arg_multi *srv_arg_mt, handle_t srv_handle)
+{
+       struct l7vs_pfilter_service *pfilter_service;
+       struct l7vs_pfilter_service_arg c_sarg;
+       char pfilter_argument[SERVICE_ARG_MAXSIZE];
+       int return_value = 0;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char srv_arg_mt_str[DEBUG_STR_LEN] = {0};
+               l7vs_service_arg_multi_c_str(srv_arg_mt_str, srv_arg_mt);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,306,
+                   "in_function: int service_arg(struct l7vs_service_arg_multi* srv_arg_mt, "
+                   "handle_t srv_handle):srv_arg_mt=&(%s), srv_handle=%u",
+                   srv_arg_mt_str, srv_handle);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (srv_arg_mt == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,270, "Arg(srv_arg_mt) is NULL pointer.");
+               return_value = -1;
+               goto service_arg_out;
+       }
+
+       /* search service that has such a service ID */
+       pfilter_service = l7vs_protomod_pfilter_search_service(srv_handle);
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char pfilter_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_c_str(pfilter_str, pfilter_service);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,307, "pointer assign: pfilter_service=&(%s)",
+                   pfilter_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       if (pfilter_service == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,271, "Could not find such service handle's pfilter service.");
+               return_value = -1;
+               goto service_arg_out;
+       }
+
+       /* initialize argument strings */
+       memset(pfilter_argument, 0, SERVICE_ARG_MAXSIZE);
+
+       /* set pfilter args to service argument struct */
+       srv_arg_mt->srv_arg.reschedule = pfilter_service->reschedule;
+
+
+       /* create long argument (l7vsadm option -L/-l) */
+       snprintf(pfilter_argument, SERVICE_ARG_MAXSIZE, "--pattern-match %s", pfilter_service->pattern_match);
+       strncpy(srv_arg_mt->srv_arg.protomod_key_string, pfilter_argument, 256);
+
+       /* create verbose argument (l7vsadm option -V/-v) */
+       snprintf(pfilter_argument, SERVICE_ARG_MAXSIZE, "--pattern-match %s --read-byte %d", pfilter_service->pattern_match, pfilter_service->read_byte);
+       strncpy(srv_arg_mt->srv_arg.protomod_opt_string, pfilter_argument, 512);
+
+       strncpy(c_sarg.pattern_match, pfilter_service->pattern_match, PATTERN_MATCH_MAXSIZE);
+       c_sarg.reschedule = pfilter_service->reschedule;
+
+       memcpy(srv_arg_mt->protomod_arg, &c_sarg, sizeof(struct l7vs_pfilter_service_arg));
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char pfilter_arg_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_arg_c_str(pfilter_arg_str, &c_sarg);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,308,
+                   "pointer assign: srv_arg_mt->protomod_arg=&(%s)", pfilter_arg_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+service_arg_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,309,
+                   "out_function: int service_arg(struct l7vs_service_arg_multi* srv_arg_mt, "
+                   "handle_t srv_handle):return_value=%d", return_value);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Parse l7vsadm options to pfilter argument
+ * @param[out] pfilter_arg pfilter service argument struct
+ * @param[int] argc number of l7vsadm argument
+ * @param[int] argv l7vsadm argument list
+ * @retval 0  successfully parse argument
+ * @retval -1 some errors occur.
+ */
+static int
+parse(void *pfilter_arg, int argc, char *argv[])
+{
+       struct l7vs_pfilter_service_arg *pfilter_service_arg;
+       static struct option opt[] = {
+               {"pattern-match",   required_argument, NULL, 'P'},
+               {"read-byte",       required_argument, NULL, 'R'},
+               {NULL,              0,                 NULL, 0  }
+       };
+       int c;
+       unsigned long buffer;
+       int pattern_match_flag = 0;
+       int read_byte_flag = 0;
+       int return_value = 0;
+#ifndef USE_BOOST_XPRESSIVE
+       boost::regex regex;
+#endif
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               int i;
+               char argv_str[DEBUG_STR_LEN] = {0};
+               char pfilter_arg_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_arg_c_str(pfilter_arg_str, (struct l7vs_pfilter_service_arg*) pfilter_arg);
+               argv_str[0] = '\0';
+               if (argv == NULL)
+                       snprintf(argv_str, DEBUG_STR_LEN, "NULL");
+               else {
+                       for (i = 0; i < argc; i++) {
+                               snprintf(argv_str, DEBUG_STR_LEN, "%sargv[%d]=\"%s\", ", argv_str, i, argv[i]);
+                       }
+                       i = strnlen(argv_str, DEBUG_STR_LEN);
+                       if (i > 1)
+                               argv_str[i - 2] = '\0';
+               }
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,310,
+                   "in_function: int parse(void* pfilter_arg, int argc, char* argv[]):pfilter_arg=&(%s), "
+                   "argc=%d, %s", pfilter_arg_str, argc, argv_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check null */
+       if (pfilter_arg == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,272, "Arg(pfilter_arg) is NULL pointer.");
+               return_value = -1;
+               goto parse_out;
+       }
+       if (argv == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,273, "Arg(argv) is NULL pointer.");
+               return_value = -1;
+               goto parse_out;
+       }
+
+       pfilter_service_arg = (struct l7vs_pfilter_service_arg *) pfilter_arg;
+       optind = 0;
+
+       /* check all argument */
+       while ((c = getopt_long(argc, argv, "P:F", opt, NULL)) != -1) {
+               switch (c) {
+               /* --pattern-match / -P */
+               case 'P':
+                       /* check maximum length */
+                       if (strnlen(optarg, PATTERN_MATCH_MAXSIZE) >= PATTERN_MATCH_MAXSIZE) {
+                               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,274,
+                                   "-P/--pattern-match option value '%s' too long", optarg);
+                               return_value = -1;
+                               goto parse_out;
+                       }
+                       /* check minimum length */
+                       if (strnlen(optarg, PATTERN_MATCH_MAXSIZE) <= 0 ) {
+                               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,275,
+                                   "-P/--pattern-match option value '%s' invalid", optarg);
+                               return_value = -1;
+                               goto parse_out;
+                       }
+                       strncpy(pfilter_service_arg->pattern_match, optarg, PATTERN_MATCH_MAXSIZE);
+                       pattern_match_flag++;
+                       break;
+
+               /* --read_byte / -R */
+               case 'R':
+                       if (sscanf(optarg, "%lu", &buffer) == 0) {
+                               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,276,
+                                   "-R/--read-byte option value '%s' is invalid.", optarg);
+                               return_value = -1;
+                               goto parse_out;
+                       }
+                       if (buffer > INT32_MAX) {
+                               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,277,
+                                   "-R/--read-byte option value '%s' is too large.", optarg);
+                               return_value = -1;
+                               goto parse_out;
+                       }
+                       else
+                               pfilter_service_arg->read_byte = buffer;
+                       read_byte_flag++;
+                       break;
+
+               /* else error */
+               default:
+                       PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,278, "Option error.");
+                       return_value = -1;
+                       goto parse_out;
+               }
+       }
+
+       /* set default read byte */
+       if (read_byte_flag == 0) {
+               pfilter_service_arg->read_byte = 1024;
+       }
+
+       /* set default no reschedule */
+       pfilter_service_arg->reschedule = 0;
+
+       /* no pattern-match value */
+       if (pattern_match_flag == 0) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,279,
+                   "You have to set '--pattern-match' option.");
+               return_value = -1;
+               goto parse_out;
+       }
+       /* same option */
+       if (pattern_match_flag > 1) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,280,
+                   "Cannot set multiple option '--pattern-match/-P'.");
+               return_value = -1;
+               goto parse_out;
+       }
+       /* compile regex */
+    try {
+#ifdef USE_BOOST_XPRESSIVE
+       boost::xpressive::sregex::compile(pfilter_service_arg->pattern_match);
+#else
+        regex.assign(pfilter_service_arg->pattern_match);
+#endif
+    }
+    catch (...) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,281,
+                   "Regex pattern error.");
+               return_value = -1;
+               goto parse_out;
+    }
+
+parse_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,311,
+                   "out_function: int parse(void* pfilter_arg, int argc, char* argv[]):return_value=%d",
+                   return_value);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Search pfilter service from pfilter service list using service handle
+ * @param[in]  service_handle a unique service ID
+ * @return pfilter service struct when service was found. NULL when service was not found.
+ */
+static struct l7vs_pfilter_service *
+l7vs_protomod_pfilter_search_service(handle_t service_handle)
+{
+       /* pfilter service list counter */
+       int service_number = 0;
+       struct l7vs_pfilter_service* return_value = NULL;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,312,
+                   "in_function: struct l7vs_pfilter_service* l7vs_protomod_pfilter_search_service(handle_t service_handle):"
+                   "service_handle=%d", service_handle);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check all pfilter service list */
+       for (service_number = 0; service_number < URL_SERVICE_NUMBER; ++service_number) {
+               /* found the service has same service handle */
+               if (pfilter_service_list[service_number] != NULL && 
+                   pfilter_service_list[service_number]->service_handle == service_handle) {
+                       return_value = pfilter_service_list[service_number];
+                       break;
+               }
+       }
+       
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char ssl_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_c_str(ssl_str, return_value);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,313,
+                   "out_function: struct l7vs_pfilter_service* l7vs_protomod_pfilter_search_service(handle_t service_handle):"
+                   "return_value=&(%s)", ssl_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Create pfilter service.
+ * @param  void
+ * @return pfilter service struct when create a service. NULL when cannot create service.
+ */
+static struct l7vs_pfilter_service *
+l7vs_protomod_pfilter_create_service()
+{
+       struct l7vs_pfilter_service* return_value = NULL;
+       int service_number = 0;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,314,
+                   "in_function: struct l7vs_pfilter_service* l7vs_protomod_pfilter_create_service()");
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* check all pfilter service list */
+       for (service_number = 0; service_number < URL_SERVICE_NUMBER - 1; ++service_number) {
+               /* if pointer that does not point NULL exists ... */
+               if (pfilter_service_list[service_number] == NULL) {
+                       /* create a service at empty pointer */
+                       pfilter_service_list[service_number] = (struct l7vs_pfilter_service *) calloc(1, sizeof(struct l7vs_pfilter_service));
+
+                       /*-------- DEBUG LOG --------*/
+                       if (pfilter_protomod.get_log_level != NULL &&
+                           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+                               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,67, "calloc: addr=%p, size=%ld",
+                                   pfilter_service_list[service_number], (unsigned long int) sizeof(struct l7vs_pfilter_service));
+                       }
+                       /*------ DEBUG LOG END ------*/
+
+                       if (pfilter_service_list[service_number] == NULL) {
+                               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,57, "Could not allocate memory.");
+                               goto create_service_out;
+                       }
+                       return_value = pfilter_service_list[service_number];
+                       goto create_service_out;
+               }
+       }
+       
+       /* all service list is full */
+       PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,282, "pfilter service list is full.");
+
+create_service_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char ssl_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_c_str(ssl_str, return_value);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,315,
+                   "out_function: struct l7vs_pfilter_service* l7vs_protomod_pfilter_create_service():"
+                   "return_value=&(%s)", ssl_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Create temporary pfilter service.
+ * @param  void
+ * @return pfilter service struct when create a service. NULL when cannot create service.
+ */
+static struct l7vs_pfilter_service *
+l7vs_protomod_pfilter_create_temp_service()
+{
+       struct l7vs_pfilter_service* return_value = NULL;
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,316,
+                   "in_function: struct l7vs_pfilter_service* l7vs_protomod_pfilter_create_temp_service()");
+       }
+       /*------ DEBUG LOG END ------*/
+
+       /* if pointer that does not point NULL exists ... */
+       if (pfilter_service_list[URL_SERVICE_NUMBER - 1] != NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,283, "Temporary pfilter service is being used by other process.");
+               goto create_temp_service_out;
+       }
+
+       /* create temp service */
+       pfilter_service_list[URL_SERVICE_NUMBER - 1] = (struct l7vs_pfilter_service *) calloc(1, sizeof(struct l7vs_pfilter_service));
+
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,68, "calloc: addr=%p, size=%ld",
+                   pfilter_service_list[URL_SERVICE_NUMBER - 1], (unsigned long int) sizeof(struct l7vs_pfilter_service));
+       }
+       /*------ DEBUG LOG END ------*/
+
+       if (pfilter_service_list[URL_SERVICE_NUMBER - 1] == NULL) {
+               PUT_LOG_ERROR(pfilter_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,58, "Could not allocate memory");
+               goto create_temp_service_out;
+       }
+
+       return_value = pfilter_service_list[URL_SERVICE_NUMBER - 1];
+
+create_temp_service_out:
+       /*-------- DEBUG LOG --------*/
+       if (pfilter_protomod.get_log_level != NULL &&
+           LOG_LV_DEBUG == pfilter_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+               char ssl_str[DEBUG_STR_LEN] = {0};
+               l7vs_pfilter_service_c_str(ssl_str, return_value);
+               PUT_LOG_DEBUG(pfilter_protomod, LOG_CAT_L7VSD_PROTOCOL,317,
+                   "out_function: struct l7vs_pfilter_service* l7vs_protomod_pfilter_create_service():"
+                   "return_value=&(%s)", ssl_str);
+       }
+       /*------ DEBUG LOG END ------*/
+
+       return return_value;
+}
+
+/*!
+ * Serialize struct l7vs_pfilter_service for debug log.
+ * @param[out] buf   serialized string
+ * @param[in]  pfilter l7vs_pfilter_service struct
+ */
+static void l7vs_pfilter_service_c_str(char* buf, struct l7vs_pfilter_service* pfilter) {
+       if (pfilter == NULL) {
+               snprintf(buf, DEBUG_STR_LEN, "NULL");
+       }
+       else {
+               snprintf(buf, DEBUG_STR_LEN, "service_handle=%d, pattern_match=\"%s\", "
+                   "read_byte=%d, reschedule=%d", pfilter->service_handle, pfilter->pattern_match,
+                   pfilter->read_byte, pfilter->reschedule);
+       }
+}
+
+/*!
+ * Serialize struct l7vs_pfilter_service_arg for debug log.
+ * @param[out] buf       serialized string
+ * @param[in]  pfilter_arg l7vs_pfilter_service_arg struct
+ */
+void l7vs_pfilter_service_arg_c_str(char* buf, struct l7vs_pfilter_service_arg* pfilter_arg) {
+       if (pfilter_arg == NULL) {
+               snprintf(buf, DEBUG_STR_LEN, "NULL");
+       }
+       else {
+               snprintf(buf, DEBUG_STR_LEN, "pattern_match=\"%s\", read_byte=%d, reschedule=%d",
+                   pfilter_arg->pattern_match, pfilter_arg->read_byte, pfilter_arg->reschedule);
+       }
+}