OSDN Git Service

Module bug fix.
[ultramonkey-l7/ultramonkey-l7-v2.git] / module / protocol / protomod_ip.c
index 0d649fd..b642a74 100644 (file)
@@ -34,7 +34,7 @@
 #include "module_http.h"
 
 #define SERVICE_ARG_MAXSIZE    (512)
-#define IP_SERVICE_NUMBER (128)
+#define IP_SERVICE_NUMBER      (128)
 #define X_FORWARDED_FOR_LENGTH (48)
 
 #define HASH_TABLE_BITS 8
 struct l7vs_ip_service {
     handle_t service_handle;
     struct sockaddr_in dest[HASH_TABLE_SIZE];
+    int expire[HASH_TABLE_SIZE];
+    int timeout;
     int forwarded_for;
     int reschedule;
 };
 
 struct  l7vs_ip_service_arg {
+    int timeout;
     int forwarded_for;
     int reschedule;
 };
@@ -58,8 +61,10 @@ 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   select_dest(struct l7vs_service*, struct l7vs_conn*,
+        char*, size_t*, struct l7vs_dest**);
+static int   analyze_cldata(struct l7vs_service*, struct l7vs_conn*,
+        char*, size_t*);
 static int   analyze_rsdata(struct l7vs_service*, struct l7vs_conn*,
         char*, size_t*);
 static int   destroy(handle_t);
@@ -79,12 +84,13 @@ struct l7vs_ip_service *ip_service_list[IP_SERVICE_NUMBER];
 
 static struct l7vs_protomod ip_protomod = {
     NULL,           /* handle */
-    "ip",      /* modname */
+    "ip",           /* modname */
     0,              /* refcnt */
     1,              /* fast schedule */
     create,         /* create function */
     compare,        /* compare function */
-    match_cldata,   /* match_cldata function */
+    select_dest,    /* select_dest function */
+    analyze_cldata, /* analyze_cldata function */
     analyze_rsdata, /* analyze_rsdata function */
     destroy,        /* destroy function */
     fini,           /* fini function */
@@ -104,7 +110,7 @@ static struct l7vs_protomod ip_protomod = {
 
 /*!
  * Protocol module initialize function. This function run when dlopen and dlsym at first time.
- * @param[in] handle dlopen's handle
+ * @param[in] handle    dlopen's handle
  * @return l7vs_protomod struct
  */
 extern "C" struct l7vs_protomod *
@@ -192,8 +198,8 @@ fini(void)
 
 /*!
  * Create ip service struct.
- * @param[in] ip_arg    ip service argument struct
- * @param[in] service_handle a unique service ID
+ * @param[in] ip_arg            ip service argument struct
+ * @param[in] service_handle    a unique service ID
  * @retval 0  successfully create ip service.
  * @retval -1 some errors occur.
  */
@@ -251,6 +257,8 @@ create(void *ip_arg, handle_t service_handle)
 
     /* set service handle */
     ip_service->service_handle = service_handle;
+    /* set timeout */
+    ip_service->timeout = ip_service_arg->timeout;
     /* set x-forwarded-for flag */
     ip_service->forwarded_for = ip_service_arg->forwarded_for;
     /* set reschedule  */
@@ -271,7 +279,7 @@ create_out:
 
 /*!
  * Create ip service argument struct.
- * @param[out] srv_arg service argument struct
+ * @param[out] srv_arg  service argument struct
  * @return ip service argument struct
  */
 static void *
@@ -334,8 +342,8 @@ create_sa_out:
 
 /*!
  * Compare two service.
- * @param[in] srv_handle1 one of a unique service ID
- * @param[in] srv_handle2 one of a unique service ID
+ * @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.
  */
@@ -350,12 +358,6 @@ compare(handle_t srv_handle1, handle_t srv_handle2)
         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,258,
             "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 ------*/
-
-    /*-------- DEBUG LOG --------*/
-    if (ip_protomod.get_log_level != NULL &&
-        LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,259,
             "out_function: int compare(handle_t srv_handle1, handle_t srv_handle2):return_value=%d",
             return_value);
@@ -367,37 +369,32 @@ compare(handle_t srv_handle1, handle_t srv_handle2)
 
 /*!
  * Do not check the request packet.
- * @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
+ * @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
  * @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)
+select_dest(struct l7vs_service *srv, struct l7vs_conn *conn,
+      char *request, size_t *len, struct l7vs_dest **dest)
 {
     struct l7vs_ip_service *ip_service;
     struct l7vs_dest destination;
     int ret;
-    int offset_length;
-    char *x_forwarded_value;
-    char *next_line = NULL;
-    char x_forwarded_for_header[X_FORWARDED_FOR_LENGTH];
-    size_t uri_len = 0;
     int return_value = 0;
     unsigned int hash;
+    time_t now;
 
     /*-------- DEBUG LOG --------*/
     if (ip_protomod.get_log_level != NULL &&
         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
-        char srv_str[DEBUG_STR_LEN] = {0};
+        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 len_str[DEBUG_STR_LEN]  = {0};
         l7vs_service_c_str(srv_str, srv);
         l7vs_conn_c_str(conn_str, conn);
         if (dest != NULL) {
@@ -413,10 +410,10 @@ match_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
             strncpy(len_str, "NULL", DEBUG_STR_LEN);
         }
         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,260,
-            "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=&(%d)",
-            srv_str, conn_str, request, len_str, dest_str, *tcps);
+            "in_function: int select_dest(struct l7vs_service* srv, struct l7vs_conn* conn, "
+            "char* request, size_t* len, struct l7vs_dest** dest):srv=&(%s), conn=&(%s), "
+            "request=\"%s\", len=&(%s), dest=&(&(%s))",
+            srv_str, conn_str, request, len_str, dest_str);
     }
     /*------ DEBUG LOG END ------*/
 
@@ -424,32 +421,27 @@ match_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
     if (srv == NULL) {
         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,221, "Arg(srv) is NULL pointer.");
         return_value = -1;
-        goto match_cldata_out;
+        goto select_dest_out;
     }
     if (srv->pm == NULL) {
         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,222, "Arg(srv->pm) is NULL pointer.");
         return_value = -1;
-        goto match_cldata_out;
+        goto select_dest_out;
     }
     if (request == NULL) {
         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,223, "Arg(request) is NULL pointer.");
         return_value = -1;
-        goto match_cldata_out;
+        goto select_dest_out;
     }
     if (len == NULL) {
         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,224, "Arg(len) is NULL pointer.");
         return_value = -1;
-        goto match_cldata_out;
+        goto select_dest_out;
     }
     if (dest == NULL) {
         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,225, "Arg(dest) is NULL pointer.");
         return_value = -1;
-        goto match_cldata_out;
-    }
-    if (tcps == NULL) {
-        PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,226, "Arg(tcps) is NULL pointer.");
-        return_value = -1;
-        goto match_cldata_out;
+        goto select_dest_out;
     }
 
     /* search service that has such a service ID */
@@ -468,7 +460,7 @@ match_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
     if (ip_service == NULL) {
         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,227, "Could not find such service handle's ip service.");
         return_value = -1;
-        goto match_cldata_out;
+        goto select_dest_out;
     }
 
     /* initialize protocol module ... clear destination list */
@@ -476,15 +468,124 @@ match_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
     if (ret != 0){
         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,228, "Could not initialize protomod.");
         return_value = -1;
-        goto match_cldata_out;
+        goto select_dest_out;
     }
 
+    now  = time(NULL);
     hash = l7vs_ip_service_calc_hash(conn);
-    if (ip_service->dest[hash].sin_addr.s_addr &&
-        ip_service->dest[hash].sin_port) {
+    if (   ip_service->dest[hash].sin_addr.s_addr
+        && ip_service->dest[hash].sin_port
+        && (ip_service->timeout == 0 || now < ip_service->expire[hash])
+        ) {
         destination.addr.sin_addr.s_addr = ip_service->dest[hash].sin_addr.s_addr;
         destination.addr.sin_port = ip_service->dest[hash].sin_port;
-           *dest = &destination;
+        *dest = &destination;
+    }
+
+    /* finalize */
+    ret = srv->pm->finalize(srv, conn, request, *len, dest, ip_service->reschedule);
+    if (ret != 0){
+        PUT_LOG_INFO(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,17, "Could not finalize protomod. (Realserver decision failure)");
+        return_value = -1;
+        goto select_dest_out;
+    }
+
+select_dest_out:
+    /*-------- DEBUG LOG --------*/
+    if (ip_protomod.get_log_level != NULL &&
+        LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+        PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,262,
+            "out_function: int select_dest(struct l7vs_service* srv, struct l7vs_conn* conn, "
+            "char* request, size_t* len, struct l7vs_dest** dest):return_value=%d",
+            return_value);
+    }
+    /*------ DEBUG LOG END ------*/
+
+    return return_value;
+}
+
+/*!
+ * Analyze and modify client packet
+ * @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
+ * @retval 0  successfully check packet data
+ * @retval -1 some errors occur.
+ */
+static int
+analyze_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
+      char *request, size_t *len)
+{
+    struct l7vs_ip_service *ip_service;
+    struct l7vs_dest destination;
+    int    offset_length;
+    char*  x_forwarded_value;
+    char*  next_line = NULL;
+    char   x_forwarded_for_header[X_FORWARDED_FOR_LENGTH];
+    size_t uri_len = 0;
+    int    return_value = 0;
+
+    /*-------- DEBUG LOG --------*/
+    if (ip_protomod.get_log_level != NULL &&
+        LOG_LV_DEBUG == ip_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(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,260,
+            "in_function: int analyze_cldata(struct l7vs_service* srv, struct l7vs_conn* conn, "
+            "char* request, size_t* len):srv=&(%s), conn=&(%s), request=\"%s\", len=&(%s)",
+            srv_str, conn_str, request, len_str);
+    }
+    /*------ DEBUG LOG END ------*/
+
+    /* check null */
+    if (srv == NULL) {
+        PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,221, "Arg(srv) is NULL pointer.");
+        return_value = -1;
+        goto analyze_cldata_out;
+    }
+    if (srv->pm == NULL) {
+        PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,222, "Arg(srv->pm) is NULL pointer.");
+        return_value = -1;
+        goto analyze_cldata_out;
+    }
+    if (request == NULL) {
+        PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,223, "Arg(request) is NULL pointer.");
+        return_value = -1;
+        goto analyze_cldata_out;
+    }
+    if (len == NULL) {
+        PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,224, "Arg(len) is NULL pointer.");
+        return_value = -1;
+        goto analyze_cldata_out;
+    }
+
+    /* search service that has such a service ID */
+    ip_service = l7vs_protomod_ip_search_service(srv->handle);
+
+    /*-------- DEBUG LOG --------*/
+    if (ip_protomod.get_log_level != NULL &&
+        LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+        char ip_str[DEBUG_STR_LEN] = {0};
+        l7vs_ip_service_c_str(ip_str, ip_service);
+        PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,261, "pointer assign: ip_service=&(%s)",
+            ip_str);
+    }
+    /*------ DEBUG LOG END ------*/
+
+    if (ip_service == NULL) {
+        PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,227, "Could not find such service handle's ip service.");
+        return_value = -1;
+        goto analyze_cldata_out;
     }
 
     /* set X-Forwarded-For field */
@@ -492,7 +593,7 @@ match_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
         uri_len = *len;
         /* check request */
         if (http_check_request_method(request, &uri_len) == NULL)
-            goto match_cldata_finalize;
+            goto analyze_cldata_out;
 
         x_forwarded_value = http_search_header_field(request, "X-Forwarded-For");
 
@@ -530,26 +631,13 @@ match_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
         }
     }
 
-match_cldata_finalize:
-    *tcps = 0;
-
-       /* finalize */
-    ret = srv->pm->finalize(srv, conn, request, *len, dest, ip_service->reschedule);
-
-    if (ret != 0){
-        PUT_LOG_INFO(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,17, "Could not finalize protomod. (Realserver decision failure)");
-        return_value = -1;
-        goto match_cldata_out;
-    }
-
-match_cldata_out:
+analyze_cldata_out:
     /*-------- DEBUG LOG --------*/
     if (ip_protomod.get_log_level != NULL &&
         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,262,
-            "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);
+            "out_function: int analyze_cldata(struct l7vs_service* srv, struct l7vs_conn* conn, "
+            "char* request, size_t* len):return_value=%d", return_value);
     }
     /*------ DEBUG LOG END ------*/
 
@@ -557,11 +645,11 @@ match_cldata_out:
 }
 
 /*!
- * Do nothing.
- * @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.
+ * Calculate source IP address's hash value and regist it with destination IP address.
+ * @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.
  */
@@ -569,16 +657,17 @@ static int
 analyze_rsdata(struct l7vs_service *srv, struct l7vs_conn *conn,
     char *response, size_t *len)
 {
-       struct l7vs_ip_service *ip_service;
+    struct l7vs_ip_service *ip_service;
     unsigned int hash;
     int return_value = 0;
+    time_t now = 0;
 
     /*-------- DEBUG LOG --------*/
     if (ip_protomod.get_log_level != NULL &&
         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
-        char srv_str[DEBUG_STR_LEN] = {0};
+        char srv_str[DEBUG_STR_LEN]  = {0};
         char conn_str[DEBUG_STR_LEN] = {0};
-        char len_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) {
@@ -632,28 +721,31 @@ analyze_rsdata(struct l7vs_service *srv, struct l7vs_conn *conn,
         goto analyze_rsdata_out;
     }
 
-       /* search service that has such a service ID */
-       ip_service = l7vs_protomod_ip_search_service(srv->handle);
+    /* search service that has such a service ID */
+    ip_service = l7vs_protomod_ip_search_service(srv->handle);
 
-       /*-------- DEBUG LOG --------*/
-       if (ip_protomod.get_log_level != NULL &&
-           LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
-               char ip_str[DEBUG_STR_LEN];
-               l7vs_ip_service_c_str(ip_str, ip_service);
-               PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,265, "pointer assign: ip_service=&(%s)",
-                   ip_str);
-       }
-       /*------ DEBUG LOG END ------*/
+    /*-------- DEBUG LOG --------*/
+    if (ip_protomod.get_log_level != NULL &&
+        LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+        char ip_str[DEBUG_STR_LEN];
+        l7vs_ip_service_c_str(ip_str, ip_service);
+        PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,265, "pointer assign: ip_service=&(%s)",
+            ip_str);
+    }
+    /*------ DEBUG LOG END ------*/
 
-       if (ip_service == NULL) {
-               PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,234,
-                   "Could not find such service handle's ip service.");
-               return_value = -1;
-               goto analyze_rsdata_out;
-       }
+    if (ip_service == NULL) {
+        PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,234,
+            "Could not find such service handle's ip service.");
+        return_value = -1;
+        goto analyze_rsdata_out;
+    }
 
     hash = l7vs_ip_service_calc_hash(conn);
     memcpy(&ip_service->dest[hash], &conn->dest->addr, sizeof(struct sockaddr_in));
+    if (ip_service->timeout)
+        now = time(NULL);
+    ip_service->expire[hash] = now + ip_service->timeout;
 
 analyze_rsdata_out:
     /*-------- DEBUG LOG --------*/
@@ -670,7 +762,7 @@ analyze_rsdata_out:
 
 /*!
  * Destroy ip service
- * @param[in] srv_handle a unique service ID
+ * @param[in] srv_handle    a unique service ID
  * @retval 0  successfully check packet data.
  * @retval -1 some errors occur.
  */
@@ -728,7 +820,7 @@ destroy_out:
 
 /*!
  * Destroy ip service argument
- * @param[in] ip_arg ip service argument
+ * @param[in] ip_arg    ip service argument
  * @return void
  */
 static void
@@ -782,8 +874,8 @@ destroy_sa(void **ip_arg)
 
 /*!
  * Create strings for service list of l7vsadm
- * @param[out] srv_arg service argument struct
- * @param[in]  srv_handle a unique service ID
+ * @param[out] srv_arg      service argument struct
+ * @param[in]  srv_handle   a unique service ID
  * @retval 0  successfully create strings
  * @retval -1 some errors occur.
  */
@@ -792,8 +884,8 @@ service_arg(struct l7vs_service_arg_multi *srv_arg_mt, handle_t srv_handle)
 {
     struct l7vs_ip_service *ip_service;
     struct l7vs_ip_service_arg c_sarg;
-    char ip_argument[SERVICE_ARG_MAXSIZE];
-    int return_value = 0;
+    char   ip_argument[SERVICE_ARG_MAXSIZE];
+    int    return_value = 0;
 
     /*-------- DEBUG LOG --------*/
     if (ip_protomod.get_log_level != NULL &&
@@ -843,10 +935,12 @@ service_arg(struct l7vs_service_arg_multi *srv_arg_mt, handle_t srv_handle)
     strncpy(srv_arg_mt->srv_arg.protomod_key_string, "", 256);
 
     /* create verbose argument (l7vsadm option -V/-v) */
-    strncpy(srv_arg_mt->srv_arg.protomod_opt_string, "", 512);
     if (ip_service->forwarded_for) {
-        strncpy(srv_arg_mt->srv_arg.protomod_opt_string, "--forwarded-for", 512);
+        snprintf(ip_argument, SERVICE_ARG_MAXSIZE, "--timeout %d --forwarded-for", ip_service->timeout);
+    } else {
+        snprintf(ip_argument, SERVICE_ARG_MAXSIZE, "--timeout %d", ip_service->timeout);
     }
+    strncpy(srv_arg_mt->srv_arg.protomod_opt_string, ip_argument, 512);
 
     c_sarg.reschedule = ip_service->reschedule;
 
@@ -877,9 +971,9 @@ service_arg_out:
 
 /*!
  * Parse l7vsadm options to ip argument
- * @param[out] ip_arg ip service argument struct
- * @param[in]  argc number of l7vsadm argument
- * @param[in]  argv l7vsadm argument list
+ * @param[out] ip_arg   ip service argument struct
+ * @param[in]  argc     number of l7vsadm argument
+ * @param[in]  argv     l7vsadm argument list
  * @retval 0  successfully parse argument
  * @retval -1 some errors occur.
  */
@@ -888,21 +982,24 @@ parse(void *ip_arg, int argc, char *argv[])
 {
     struct l7vs_ip_service_arg *ip_service_arg;
     static struct option opt[] = {
+        {"timeout",       required_argument, NULL, 'T'},
         {"forwarded-for", no_argument,       NULL, 'F'},
         {"reschedule",    no_argument,       NULL, 'R'},
         {"no-reschedule", no_argument,       NULL, 'N'},
         {NULL,            0,                 NULL, 0  }
     };
     int c;
-    int return_value = 0;
+    int return_value       = 0;
+    int timeout_flag       = 0;
     int forwarded_for_flag = 0;
-    int reschedule_flag = 0;
+    int reschedule_flag    = 0;
+    unsigned long buffer;
 
     /*-------- DEBUG LOG --------*/
     if (ip_protomod.get_log_level != NULL &&
         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
         int i;
-        char argv_str[DEBUG_STR_LEN] = {0};
+        char argv_str[DEBUG_STR_LEN]   = {0};
         char ip_arg_str[DEBUG_STR_LEN] = {0};
         l7vs_ip_service_arg_c_str(ip_arg_str, (struct l7vs_ip_service_arg*) ip_arg);
         argv_str[0] = '\0';
@@ -938,8 +1035,26 @@ parse(void *ip_arg, int argc, char *argv[])
     optind = 0;
 
     /* check all argument */
-    while ((c = getopt_long(argc, argv, "FRN", opt, NULL)) != -1) {
+    while ((c = getopt_long(argc, argv, "T:FRN", opt, NULL)) != -1) {
         switch (c) {
+        /* --timeout / -T */
+        case 'T':
+            if (sscanf(optarg, "%lu", &buffer) == 0) {
+                PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,107,
+                    "-T/--timeout option value '%s' is invalid.", optarg);
+                return_value = -1;
+                goto parse_out;
+            }
+            if (buffer > INT_MAX) {
+                PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,108,
+                    "-T/--timeout option value '%s' is too large.", optarg);
+                return_value = -1;
+                goto parse_out;
+            }
+            else
+                ip_service_arg->timeout = buffer;
+            timeout_flag++;
+            break;
         /* --forwarded-for / -F */
         case 'F':
             /* x-forwarded-for on */
@@ -952,14 +1067,12 @@ parse(void *ip_arg, int argc, char *argv[])
             ip_service_arg->reschedule = 1;
             reschedule_flag++;
             break;
-
         /* --no-reschedule / -N */
         case 'N':
             /* reschedule off */
             ip_service_arg->reschedule = 0;
             reschedule_flag++;
             break;
-
         /* else error */
         default:
             PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,242, "Option error.");
@@ -975,12 +1088,21 @@ parse(void *ip_arg, int argc, char *argv[])
         return_value = -1;
         goto parse_out;
     }
-
+    /* same option */
+    if (timeout_flag > 1) {
+        PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,113,
+            "Cannot set multiple option '--timeout/-T'.");
+        return_value = -1;
+        goto parse_out;
+    }
+    /* set default options */
+    if (timeout_flag == 0) {
+        ip_service_arg->timeout = 3600;
+    }
     /* set default no reschedule */
     if (reschedule_flag == 0) {
         ip_service_arg->reschedule = 0;
     }
-
     /* set default no forwarded_for */
     if (forwarded_for_flag == 0) {
         ip_service_arg->forwarded_for = 0;
@@ -1001,7 +1123,7 @@ parse_out:
 
 /*!
  * Search ip service from ip service list using service handle
- * @param[in] service_handle a unique service ID
+ * @param[in]   service_handle  a unique service ID
  * @return ip service struct when service was found. NULL when service was not found.
  */
 static struct l7vs_ip_service *
@@ -1164,31 +1286,31 @@ create_temp_service_out:
 
 /*!
  * Serialize struct l7vs_ip_service for debug log.
- * @param[out] buf   serialized string
- * @param[in]  ip l7vs_ip_service struct
+ * @param[out]  buf     serialized string
+ * @param[in]   ip      l7vs_ip_service struct
  */
 static void l7vs_ip_service_c_str(char* buf, struct l7vs_ip_service* ip) {
     if (ip == NULL) {
         snprintf(buf, DEBUG_STR_LEN, "NULL");
     }
     else {
-        snprintf(buf, DEBUG_STR_LEN, "service_handle=%d, forwarded_for=%d, reschedule=%d",
-            ip->service_handle, ip->forwarded_for, ip->reschedule);
+        snprintf(buf, DEBUG_STR_LEN, "service_handle=%d, timeout=%d, forwarded_for=%d, reschedule=%d",
+            ip->service_handle, ip->timeout, ip->forwarded_for, ip->reschedule);
     }
 }
 
 /*!
  * Serialize struct l7vs_ip_service_arg for debug log.
- * @param[out] buf       serialized string
- * @param[in]  ip_arg l7vs_ip_service_arg struct
+ * @param[out]  buf     serialized string
+ * @param[in]   ip_arg  l7vs_ip_service_arg struct
  */
 void l7vs_ip_service_arg_c_str(char* buf, struct l7vs_ip_service_arg* ip_arg) {
     if (ip_arg == NULL) {
         snprintf(buf, DEBUG_STR_LEN, "NULL");
     }
     else {
-        snprintf(buf, DEBUG_STR_LEN, "forwarded_for=%d, reschedule=%d",
-            ip_arg->forwarded_for, ip_arg->reschedule);
+        snprintf(buf, DEBUG_STR_LEN, "timeout=%d, forwarded_for=%d, reschedule=%d",
+            ip_arg->timeout, ip_arg->forwarded_for, ip_arg->reschedule);
     }
 }
 
@@ -1196,3 +1318,4 @@ unsigned int l7vs_ip_service_calc_hash(struct l7vs_conn* conn) {
     unsigned int hash = ntohl(conn->caddr.sin_addr.s_addr) * GOLDEN_RATIO_PRIME;
     return hash >> 32 - HASH_TABLE_BITS;
 }
+// vim:et:ts=4:foldmethod=marker:foldmarker=LOG\ -,LOG\ END\ -: