OSDN Git Service

Module bug fix.
[ultramonkey-l7/ultramonkey-l7-v2.git] / module / protocol / protomod_ip.c
1 /*
2  * @file  protomod_ip.c
3  * @brief protocol module of any protocol.
4  * @brief this module never keep session persistence.
5  *
6  * L7VSD: Linux Virtual Server for Layer7 Load Balancing
7  * Copyright (C) 2008  NTT COMWARE Corporation.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22  * 02110-1301 USA
23  *
24  **********************************************************************/
25
26 #define __STDC_LIMIT_MACROS
27 #include <stdlib.h>
28 #include <time.h>
29 #include <getopt.h>
30 #include "l7vs_service.h"
31 #include "l7vs_conn.h"
32 #include "l7vs_dest.h"
33 #include "l7vs_module.h"
34 #include "module_http.h"
35
36 #define SERVICE_ARG_MAXSIZE    (512)
37 #define IP_SERVICE_NUMBER      (128)
38 #define X_FORWARDED_FOR_LENGTH (48)
39
40 #define HASH_TABLE_BITS 8
41 #define HASH_TABLE_SIZE (1 << HASH_TABLE_BITS)
42 /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
43 #define GOLDEN_RATIO_PRIME 0x9e370001UL
44
45 struct l7vs_ip_service {
46     handle_t service_handle;
47     struct sockaddr_in dest[HASH_TABLE_SIZE];
48     int expire[HASH_TABLE_SIZE];
49     int timeout;
50     int forwarded_for;
51     int reschedule;
52 };
53
54 struct  l7vs_ip_service_arg {
55     int timeout;
56     int forwarded_for;
57     int reschedule;
58 };
59
60 static void  fini(void);
61 static int   create(void*, handle_t);
62 static void* create_sa(struct l7vs_service_arg*);
63 static int   compare(handle_t, handle_t);
64 static int   select_dest(struct l7vs_service*, struct l7vs_conn*,
65         char*, size_t*, struct l7vs_dest**);
66 static int   analyze_cldata(struct l7vs_service*, struct l7vs_conn*,
67         char*, size_t*);
68 static int   analyze_rsdata(struct l7vs_service*, struct l7vs_conn*,
69         char*, size_t*);
70 static int   destroy(handle_t);
71 static void  destroy_sa(void**);
72 static int   service_arg(struct l7vs_service_arg_multi*, handle_t);
73 static int   parse(void*, int, char**);
74
75 static struct l7vs_ip_service *l7vs_protomod_ip_search_service(handle_t);
76 static struct l7vs_ip_service *l7vs_protomod_ip_create_service();
77 static struct l7vs_ip_service *l7vs_protomod_ip_create_temp_service();
78
79 static void  l7vs_ip_service_c_str(char*, struct l7vs_ip_service*);
80 static void  l7vs_ip_service_arg_c_str(char*, struct l7vs_ip_service_arg*);
81 unsigned int l7vs_ip_service_calc_hash(struct l7vs_conn*);
82
83 struct l7vs_ip_service *ip_service_list[IP_SERVICE_NUMBER];
84
85 static struct l7vs_protomod ip_protomod = {
86     NULL,           /* handle */
87     "ip",           /* modname */
88     0,              /* refcnt */
89     1,              /* fast schedule */
90     create,         /* create function */
91     compare,        /* compare function */
92     select_dest,    /* select_dest function */
93     analyze_cldata, /* analyze_cldata function */
94     analyze_rsdata, /* analyze_rsdata function */
95     destroy,        /* destroy function */
96     fini,           /* fini function */
97     create_sa,      /* create_sa function */
98     service_arg,    /* service_arg function */
99     parse,          /* parse function */
100     destroy_sa,     /* destroy_sa function */
101     NULL,           /* initialize function */
102     NULL,           /* finalize function */
103     NULL,           /* get_log_level function */
104     NULL,           /* put_log_debug function */
105     NULL,           /* put_log_info function */
106     NULL,           /* put_log_warn function */
107     NULL,           /* put_log_error function */
108     NULL            /* put_log_fatal function */
109 };
110
111 /*!
112  * Protocol module initialize function. This function run when dlopen and dlsym at first time.
113  * @param[in] handle    dlopen's handle
114  * @return l7vs_protomod struct
115  */
116 extern "C" struct l7vs_protomod *
117 init(void *handle)
118 {
119     struct l7vs_protomod* return_value = NULL;
120
121     /*-------- DEBUG LOG --------*/
122     if (ip_protomod.get_log_level != NULL &&
123         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
124         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,249,
125                 "in_function: struct l7vs_protomod* init(void* handle): handle=%p", handle);
126     }
127     /*------ DEBUG LOG END ------*/
128
129     /* check null */
130     if (handle == NULL) {
131         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,217, "Arg(handle) is NULL pointer.");
132         goto init_out;
133     }
134
135     /* initialize ip service list */
136     memset(ip_service_list, 0, sizeof(struct l7vs_ip_service *) * IP_SERVICE_NUMBER);
137     /* set dlopen's handle */
138     ip_protomod.handle = handle;
139
140     return_value = &ip_protomod;
141
142 init_out:
143     /*-------- DEBUG LOG --------*/
144     if (ip_protomod.get_log_level != NULL &&
145         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
146         char protomod_str[DEBUG_STR_LEN] = {0};
147         l7vs_protomod_c_str(protomod_str, &ip_protomod);
148         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,250,
149             "out_function: struct l7vs_protomod* init(void* handle): return=&(%s)", protomod_str);
150     }
151     /*------ DEBUG LOG END ------*/
152     return return_value;
153 }
154
155 /*!
156  * Protocol module finalize function. free all ip service list just in case.
157  * @param   void
158  * @return  void
159  */
160 static void
161 fini(void)
162 {
163     /* ip service list counter */
164     int service_number = 0;
165
166     /*-------- DEBUG LOG --------*/
167     if (ip_protomod.get_log_level != NULL &&
168         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
169         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,251, "in_function: void fini(void)");
170     }
171     /*------ DEBUG LOG END ------*/
172
173     /* check all ip service list */
174     for (service_number = 0; service_number < IP_SERVICE_NUMBER; ++service_number) {
175         /* if pointer that does not point NULL exists ... */
176         if (ip_service_list[service_number] != NULL) {
177             /*-------- DEBUG LOG --------*/
178             if (ip_protomod.get_log_level != NULL &&
179                 LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
180                 PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,58, "free: %p",
181                     ip_service_list[service_number]);
182             }
183             /*------ DEBUG LOG END ------*/
184
185             /* free and points NULL */
186             free(ip_service_list[service_number]);
187             ip_service_list[service_number] = NULL;
188         }
189     }
190
191     /*-------- DEBUG LOG --------*/
192     if (ip_protomod.get_log_level != NULL &&
193         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
194         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,252, "out_function: void fini(void)");
195     }
196     /*------ DEBUG LOG END ------*/
197 }
198
199 /*!
200  * Create ip service struct.
201  * @param[in] ip_arg            ip service argument struct
202  * @param[in] service_handle    a unique service ID
203  * @retval 0  successfully create ip service.
204  * @retval -1 some errors occur.
205  */
206 static int
207 create(void *ip_arg, handle_t service_handle)
208 {
209     struct l7vs_ip_service *ip_service;
210     struct l7vs_ip_service_arg *ip_service_arg;
211     int return_value = 0;
212
213     /*-------- DEBUG LOG --------*/
214     if (ip_protomod.get_log_level != NULL &&
215         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
216         char ip_arg_str[DEBUG_STR_LEN] = {0};
217         l7vs_ip_service_arg_c_str(ip_arg_str, (struct l7vs_ip_service_arg*) ip_arg);
218         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,253,
219             "in_function: int create(void* ip_arg, handle_t service_handle):ip_arg=&(%s), "
220             "service_handle=%d", ip_arg_str, service_handle);
221     }
222     /*------ DEBUG LOG END ------*/
223
224     /* check null */
225     if (ip_arg == NULL) {
226         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,218, "Arg(ip_arg) is NULL pointer.");
227         return_value = -1;
228         goto create_out;
229     }
230
231
232     if (service_handle != TEMP_SERVICEHANDLE) {
233         /* search empty ip service list and create ip service */
234         ip_service = l7vs_protomod_ip_create_service();
235     } else {
236         /* create temporary ip service */
237         ip_service = l7vs_protomod_ip_create_temp_service();
238     }
239
240     /*-------- DEBUG LOG --------*/
241     if (ip_protomod.get_log_level != NULL &&
242         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
243         char ip_str[DEBUG_STR_LEN] = {0};
244         l7vs_ip_service_c_str(ip_str, ip_service);
245         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,254, "pointer assign: ip_service=&(%s)",
246             ip_str);
247     }
248     /*------ DEBUG LOG END ------*/
249
250     if (ip_service == NULL) {
251         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,219, "Could not make ip service.");
252         return_value = -1;
253         goto create_out;
254     }
255
256     ip_service_arg = (struct l7vs_ip_service_arg *) ip_arg;
257
258     /* set service handle */
259     ip_service->service_handle = service_handle;
260     /* set timeout */
261     ip_service->timeout = ip_service_arg->timeout;
262     /* set x-forwarded-for flag */
263     ip_service->forwarded_for = ip_service_arg->forwarded_for;
264     /* set reschedule  */
265     ip_service->reschedule = ip_service_arg->reschedule;
266
267 create_out:
268     /*-------- DEBUG LOG --------*/
269     if (ip_protomod.get_log_level != NULL &&
270         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
271         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,255,
272             "out_function: int create(void* ip_arg, handle_t service_handle):return_value=%d",
273             return_value);
274     }
275     /*------ DEBUG LOG END ------*/
276
277     return return_value;
278 }
279
280 /*!
281  * Create ip service argument struct.
282  * @param[out] srv_arg  service argument struct
283  * @return ip service argument struct
284  */
285 static void *
286 create_sa(struct l7vs_service_arg *srv_arg)
287 {
288     struct l7vs_ip_service_arg *ip_service_arg;
289
290     /*-------- DEBUG LOG --------*/
291     if (ip_protomod.get_log_level != NULL &&
292         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
293         char service_arg_str[DEBUG_STR_LEN] = {0};
294         l7vs_service_arg_c_str(service_arg_str, srv_arg);
295         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,256,
296             "in_function: void* create_sa(struct l7vs_service_arg* srv_arg):srv_arg=&(%s)",
297             service_arg_str);
298     }
299     /*------ DEBUG LOG END ------*/
300
301     /* check null */
302     if (srv_arg == NULL) {
303         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,220, "Arg(srv_arg) is NULL pointer.");
304         ip_service_arg = NULL;
305         goto create_sa_out;
306     }
307
308     /* create ip service argument struct */
309     ip_service_arg = (struct l7vs_ip_service_arg *) calloc(1, sizeof(struct l7vs_ip_service_arg));
310
311     /*-------- DEBUG LOG --------*/
312     if (ip_protomod.get_log_level != NULL &&
313         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
314         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,59, "calloc: addr=%p, size=%ld",
315             ip_service_arg, (unsigned long int) sizeof(struct l7vs_ip_service_arg));
316     }
317     /*------ DEBUG LOG END ------*/
318
319     if (ip_service_arg == NULL) {
320         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,53, "Could not allocate memory.");
321         goto create_sa_out;
322     }
323
324     /* set ip service argument size and protomod name "ip" */
325     srv_arg->len = sizeof(struct l7vs_ip_service_arg);
326     strcpy(srv_arg->protomod, ip_protomod.modname);
327
328 create_sa_out:
329     /*-------- DEBUG LOG --------*/
330     if (ip_protomod.get_log_level != NULL &&
331         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
332         char ip_service_arg_str[DEBUG_STR_LEN] = {0};
333         l7vs_ip_service_arg_c_str(ip_service_arg_str, ip_service_arg);
334         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,257,
335             "out_function: void* create_sa(struct l7vs_service_arg* srv_arg):return_value=&(%s)",
336             ip_service_arg_str);
337     }
338     /*------ DEBUG LOG END ------*/
339
340     return (void *) ip_service_arg;
341 }
342
343 /*!
344  * Compare two service.
345  * @param[in] srv_handle1   one of a unique service ID
346  * @param[in] srv_handle2   one of a unique service ID
347  * @retval 0  they matched perfectly.
348  * @retval -1 they are different.
349  */
350 static int
351 compare(handle_t srv_handle1, handle_t srv_handle2)
352 {
353     int return_value = 0;
354
355     /*-------- DEBUG LOG --------*/
356     if (ip_protomod.get_log_level != NULL &&
357         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
358         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,258,
359             "in_function: int compare(handle_t srv_handle1, handle_t srv_handle2):"
360             "srv_handle1=%u, srv_handle2=%u", srv_handle1, srv_handle2);
361         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,259,
362             "out_function: int compare(handle_t srv_handle1, handle_t srv_handle2):return_value=%d",
363             return_value);
364     }
365     /*------ DEBUG LOG END ------*/
366
367     return return_value;
368 }
369
370 /*!
371  * Do not check the request packet.
372  * @param[in]  srv      service struct include service handle, protocol module and schedule module.
373  * @param[in]  conn     connection data.
374  * @param[in]  request  packet data from client
375  * @param[in]  len      length of packet data
376  * @param[out] dest     destination (real server) list
377  * @retval 0  successfully check packet data
378  * @retval -1 some errors occur.
379  */
380 static int
381 select_dest(struct l7vs_service *srv, struct l7vs_conn *conn,
382       char *request, size_t *len, struct l7vs_dest **dest)
383 {
384     struct l7vs_ip_service *ip_service;
385     struct l7vs_dest destination;
386     int ret;
387     int return_value = 0;
388     unsigned int hash;
389     time_t now;
390
391     /*-------- DEBUG LOG --------*/
392     if (ip_protomod.get_log_level != NULL &&
393         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
394         char srv_str[DEBUG_STR_LEN]  = {0};
395         char conn_str[DEBUG_STR_LEN] = {0};
396         char dest_str[DEBUG_STR_LEN] = {0};
397         char len_str[DEBUG_STR_LEN]  = {0};
398         l7vs_service_c_str(srv_str, srv);
399         l7vs_conn_c_str(conn_str, conn);
400         if (dest != NULL) {
401             l7vs_dest_c_str(dest_str, *dest);
402         }
403         else {
404             strncpy(dest_str, "NULL", DEBUG_STR_LEN);
405         }
406         if (len != NULL) {
407             snprintf(len_str, DEBUG_STR_LEN, "%lu", (unsigned long int) *len);
408         }
409         else {
410             strncpy(len_str, "NULL", DEBUG_STR_LEN);
411         }
412         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,260,
413             "in_function: int select_dest(struct l7vs_service* srv, struct l7vs_conn* conn, "
414             "char* request, size_t* len, struct l7vs_dest** dest):srv=&(%s), conn=&(%s), "
415             "request=\"%s\", len=&(%s), dest=&(&(%s))",
416             srv_str, conn_str, request, len_str, dest_str);
417     }
418     /*------ DEBUG LOG END ------*/
419
420     /* check null */
421     if (srv == NULL) {
422         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,221, "Arg(srv) is NULL pointer.");
423         return_value = -1;
424         goto select_dest_out;
425     }
426     if (srv->pm == NULL) {
427         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,222, "Arg(srv->pm) is NULL pointer.");
428         return_value = -1;
429         goto select_dest_out;
430     }
431     if (request == NULL) {
432         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,223, "Arg(request) is NULL pointer.");
433         return_value = -1;
434         goto select_dest_out;
435     }
436     if (len == NULL) {
437         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,224, "Arg(len) is NULL pointer.");
438         return_value = -1;
439         goto select_dest_out;
440     }
441     if (dest == NULL) {
442         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,225, "Arg(dest) is NULL pointer.");
443         return_value = -1;
444         goto select_dest_out;
445     }
446
447     /* search service that has such a service ID */
448     ip_service = l7vs_protomod_ip_search_service(srv->handle);
449
450     /*-------- DEBUG LOG --------*/
451     if (ip_protomod.get_log_level != NULL &&
452         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
453         char ip_str[DEBUG_STR_LEN] = {0};
454         l7vs_ip_service_c_str(ip_str, ip_service);
455         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,261, "pointer assign: ip_service=&(%s)",
456             ip_str);
457     }
458     /*------ DEBUG LOG END ------*/
459
460     if (ip_service == NULL) {
461         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,227, "Could not find such service handle's ip service.");
462         return_value = -1;
463         goto select_dest_out;
464     }
465
466     /* initialize protocol module ... clear destination list */
467     ret = srv->pm->initialize(srv, conn, request, *len, dest);
468     if (ret != 0){
469         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,228, "Could not initialize protomod.");
470         return_value = -1;
471         goto select_dest_out;
472     }
473
474     now  = time(NULL);
475     hash = l7vs_ip_service_calc_hash(conn);
476     if (   ip_service->dest[hash].sin_addr.s_addr
477         && ip_service->dest[hash].sin_port
478         && (ip_service->timeout == 0 || now < ip_service->expire[hash])
479         ) {
480         destination.addr.sin_addr.s_addr = ip_service->dest[hash].sin_addr.s_addr;
481         destination.addr.sin_port = ip_service->dest[hash].sin_port;
482         *dest = &destination;
483     }
484
485     /* finalize */
486     ret = srv->pm->finalize(srv, conn, request, *len, dest, ip_service->reschedule);
487     if (ret != 0){
488         PUT_LOG_INFO(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,17, "Could not finalize protomod. (Realserver decision failure)");
489         return_value = -1;
490         goto select_dest_out;
491     }
492
493 select_dest_out:
494     /*-------- DEBUG LOG --------*/
495     if (ip_protomod.get_log_level != NULL &&
496         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
497         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,262,
498             "out_function: int select_dest(struct l7vs_service* srv, struct l7vs_conn* conn, "
499             "char* request, size_t* len, struct l7vs_dest** dest):return_value=%d",
500             return_value);
501     }
502     /*------ DEBUG LOG END ------*/
503
504     return return_value;
505 }
506
507 /*!
508  * Analyze and modify client packet
509  * @param[in]  srv      service struct include service handle, protocol module and schedule module.
510  * @param[in]  conn     connection data.
511  * @param[in]  request  packet data from client
512  * @param[in]  len      length of packet data
513  * @retval 0  successfully check packet data
514  * @retval -1 some errors occur.
515  */
516 static int
517 analyze_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
518       char *request, size_t *len)
519 {
520     struct l7vs_ip_service *ip_service;
521     struct l7vs_dest destination;
522     int    offset_length;
523     char*  x_forwarded_value;
524     char*  next_line = NULL;
525     char   x_forwarded_for_header[X_FORWARDED_FOR_LENGTH];
526     size_t uri_len = 0;
527     int    return_value = 0;
528
529     /*-------- DEBUG LOG --------*/
530     if (ip_protomod.get_log_level != NULL &&
531         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
532         char srv_str[DEBUG_STR_LEN]  = {0};
533         char conn_str[DEBUG_STR_LEN] = {0};
534         char len_str[DEBUG_STR_LEN]  = {0};
535         l7vs_service_c_str(srv_str, srv);
536         l7vs_conn_c_str(conn_str, conn);
537         if (len != NULL) {
538             snprintf(len_str, DEBUG_STR_LEN, "%lu", (unsigned long int) *len);
539         }
540         else {
541             strncpy(len_str, "NULL", DEBUG_STR_LEN);
542         }
543         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,260,
544             "in_function: int analyze_cldata(struct l7vs_service* srv, struct l7vs_conn* conn, "
545             "char* request, size_t* len):srv=&(%s), conn=&(%s), request=\"%s\", len=&(%s)",
546             srv_str, conn_str, request, len_str);
547     }
548     /*------ DEBUG LOG END ------*/
549
550     /* check null */
551     if (srv == NULL) {
552         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,221, "Arg(srv) is NULL pointer.");
553         return_value = -1;
554         goto analyze_cldata_out;
555     }
556     if (srv->pm == NULL) {
557         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,222, "Arg(srv->pm) is NULL pointer.");
558         return_value = -1;
559         goto analyze_cldata_out;
560     }
561     if (request == NULL) {
562         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,223, "Arg(request) is NULL pointer.");
563         return_value = -1;
564         goto analyze_cldata_out;
565     }
566     if (len == NULL) {
567         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,224, "Arg(len) is NULL pointer.");
568         return_value = -1;
569         goto analyze_cldata_out;
570     }
571
572     /* search service that has such a service ID */
573     ip_service = l7vs_protomod_ip_search_service(srv->handle);
574
575     /*-------- DEBUG LOG --------*/
576     if (ip_protomod.get_log_level != NULL &&
577         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
578         char ip_str[DEBUG_STR_LEN] = {0};
579         l7vs_ip_service_c_str(ip_str, ip_service);
580         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,261, "pointer assign: ip_service=&(%s)",
581             ip_str);
582     }
583     /*------ DEBUG LOG END ------*/
584
585     if (ip_service == NULL) {
586         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,227, "Could not find such service handle's ip service.");
587         return_value = -1;
588         goto analyze_cldata_out;
589     }
590
591     /* set X-Forwarded-For field */
592     if (ip_service->forwarded_for) {
593         uri_len = *len;
594         /* check request */
595         if (http_check_request_method(request, &uri_len) == NULL)
596             goto analyze_cldata_out;
597
598         x_forwarded_value = http_search_header_field(request, "X-Forwarded-For");
599
600         /* already exists X-Forwarded-For field */
601         if (x_forwarded_value) {
602             next_line = http_skip_header_line(x_forwarded_value);
603             /* backtrack to look up insert point */
604             if (next_line) {
605                 next_line--; // *next_line == '\n'
606                 if (*(next_line - 1) == '\r') {
607                     next_line--;
608                 }
609                 /* append client IP address */
610                 snprintf(x_forwarded_for_header, X_FORWARDED_FOR_LENGTH, ", %s", inet_ntoa(conn->caddr.sin_addr));
611             }
612         }
613
614         /* not exists X-Forwarded-For field */
615         if (!next_line) {
616             /* construct new X-Forwarded-For header item */
617             snprintf(x_forwarded_for_header, X_FORWARDED_FOR_LENGTH, "X-Forwarded-For: %s\r\n", inet_ntoa(conn->caddr.sin_addr));
618     
619             next_line = http_skip_header_line(request);
620         }
621
622         /* when insert point exist */
623         if (next_line != NULL) {
624             offset_length = (int) (next_line - request);
625     
626             /* insert X-Forwarded-For header field */
627             http_insert_field(request, offset_length, x_forwarded_for_header, *len);
628         
629             /* add header length */
630             *len += strlen(x_forwarded_for_header);
631         }
632     }
633
634 analyze_cldata_out:
635     /*-------- DEBUG LOG --------*/
636     if (ip_protomod.get_log_level != NULL &&
637         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
638         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,262,
639             "out_function: int analyze_cldata(struct l7vs_service* srv, struct l7vs_conn* conn, "
640             "char* request, size_t* len):return_value=%d", return_value);
641     }
642     /*------ DEBUG LOG END ------*/
643
644     return return_value;
645 }
646
647 /*!
648  * Calculate source IP address's hash value and regist it with destination IP address.
649  * @param[in] srv       service struct include service handle, protocol module and schedule module.
650  * @param[in] conn      connection data.
651  * @param[in] response  packet data from real server
652  * @param[in] len       length of packet data. it will be lengthened.
653  * @retval 0  successfully check packet data.
654  * @retval -1 some errors occur.
655  */
656 static int
657 analyze_rsdata(struct l7vs_service *srv, struct l7vs_conn *conn,
658     char *response, size_t *len)
659 {
660     struct l7vs_ip_service *ip_service;
661     unsigned int hash;
662     int return_value = 0;
663     time_t now = 0;
664
665     /*-------- DEBUG LOG --------*/
666     if (ip_protomod.get_log_level != NULL &&
667         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
668         char srv_str[DEBUG_STR_LEN]  = {0};
669         char conn_str[DEBUG_STR_LEN] = {0};
670         char len_str[DEBUG_STR_LEN]  = {0};
671         l7vs_service_c_str(srv_str, srv);
672         l7vs_conn_c_str(conn_str, conn);
673         if (len != NULL) {
674             snprintf(len_str, DEBUG_STR_LEN, "%lu", (unsigned long int) *len);
675         }
676         else {
677             strncpy(len_str, "NULL", DEBUG_STR_LEN);
678         }
679         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,263,
680             "in_function: int analyze_rsdata(struct l7vs_service* srv, struct l7vs_conn* conn, "
681             "char* response, size_t* len):srv=&(%s), conn=&(%s), response=\"%s\", len=&(%s)",
682             srv_str, conn_str, response, len_str);
683     }
684     /*------ DEBUG LOG END ------*/
685
686     /* check null */
687     if (srv == NULL) {
688         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,229, "Arg(srv) is NULL pointer.");
689         return_value = -1;
690         goto analyze_rsdata_out;
691     }
692     if (conn == NULL) {
693         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,230, "Arg(conn) is NULL pointer.");
694         return_value = -1;
695         goto analyze_rsdata_out;
696     }
697     if (conn->dest == NULL) {
698         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,231, "Arg(conn->dest) is NULL pointer.");
699         return_value = -1;
700         goto analyze_rsdata_out;
701     }
702     if (response == NULL) {
703         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,232, "Arg(response) is NULL pointer.");
704         return_value = -1;
705         goto analyze_rsdata_out;
706     }
707     if (len == NULL) {
708         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,233, "Arg(len) is NULL pointer.");
709         return_value = -1;
710         goto analyze_rsdata_out;
711     }
712
713     /* sorry flag check */
714     if (conn->sorry_conn_flag == 1) {
715         /*-------- DEBUG LOG --------*/
716         if (ip_protomod.get_log_level != NULL &&
717             LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
718             PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,264, "Response from sorry server.");
719         }
720         /*------ DEBUG LOG END ------*/
721         goto analyze_rsdata_out;
722     }
723
724     /* search service that has such a service ID */
725     ip_service = l7vs_protomod_ip_search_service(srv->handle);
726
727     /*-------- DEBUG LOG --------*/
728     if (ip_protomod.get_log_level != NULL &&
729         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
730         char ip_str[DEBUG_STR_LEN];
731         l7vs_ip_service_c_str(ip_str, ip_service);
732         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,265, "pointer assign: ip_service=&(%s)",
733             ip_str);
734     }
735     /*------ DEBUG LOG END ------*/
736
737     if (ip_service == NULL) {
738         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,234,
739             "Could not find such service handle's ip service.");
740         return_value = -1;
741         goto analyze_rsdata_out;
742     }
743
744     hash = l7vs_ip_service_calc_hash(conn);
745     memcpy(&ip_service->dest[hash], &conn->dest->addr, sizeof(struct sockaddr_in));
746     if (ip_service->timeout)
747         now = time(NULL);
748     ip_service->expire[hash] = now + ip_service->timeout;
749
750 analyze_rsdata_out:
751     /*-------- DEBUG LOG --------*/
752     if (ip_protomod.get_log_level != NULL &&
753         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
754         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,266,
755             "out_function: int analyze_rsdata(struct l7vs_service* srv, struct l7vs_conn* conn, "
756             "char* response, size_t* len):return_value=%d", return_value);
757     }
758     /*------ DEBUG LOG END ------*/
759
760     return return_value;
761 }
762
763 /*!
764  * Destroy ip service
765  * @param[in] srv_handle    a unique service ID
766  * @retval 0  successfully check packet data.
767  * @retval -1 some errors occur.
768  */
769 static int
770 destroy(handle_t srv_handle)
771 {
772     /* ip service list counter */
773     int service_number = 0;
774     int free_flag = 0;
775     int return_value = 0;
776
777     /*-------- DEBUG LOG --------*/
778     if (ip_protomod.get_log_level != NULL &&
779         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
780         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,267,
781             "in_function: int destroy(handle_t srv_handle):srv_handle=%u",
782             srv_handle);
783     }
784     /*------ DEBUG LOG END ------*/
785
786     /* check all ip service list */
787     for (service_number = 0; service_number < IP_SERVICE_NUMBER; ++service_number) {
788         /* found ip service that has srv_handle */
789         if (ip_service_list[service_number] != NULL && 
790             ip_service_list[service_number]->service_handle == srv_handle) {
791
792             /* free and NULL */
793             free(ip_service_list[service_number]);
794             ip_service_list[service_number] = NULL;
795
796             free_flag = 1;
797             break;
798         }
799     }
800     
801     /* ip service was not found */
802     if (free_flag == 0) {
803         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,235, "Could not find such service handle's ip service.");
804         return_value = -1;
805         goto destroy_out;
806     }
807
808 destroy_out:
809     /*-------- DEBUG LOG --------*/
810     if (ip_protomod.get_log_level != NULL &&
811         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
812         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,268,
813             "out_function: int destroy(handle_t srv_handle):return_value=%d",
814             srv_handle);
815     }
816     /*------ DEBUG LOG END ------*/
817
818     return return_value;
819 }
820
821 /*!
822  * Destroy ip service argument
823  * @param[in] ip_arg    ip service argument
824  * @return void
825  */
826 static void
827 destroy_sa(void **ip_arg)
828 {
829     /*-------- DEBUG LOG --------*/
830     if (ip_protomod.get_log_level != NULL &&
831         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
832         char ip_arg_str[DEBUG_STR_LEN] = {0};
833         if (ip_arg != NULL) {
834             l7vs_ip_service_arg_c_str(ip_arg_str, (struct l7vs_ip_service_arg*) *ip_arg);
835         }
836         else {
837             strncpy(ip_arg_str, "NULL", DEBUG_STR_LEN);
838         }
839         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,269,
840             "in_function: void destroy_sa(void** ip_arg):ip_arg=&(&(%s))",
841             ip_arg_str);
842     }
843     /*------ DEBUG LOG END ------*/
844
845     /* check null */
846     if (ip_arg == NULL) {
847         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,236, "Arg(ip_arg) is NULL pointer.");
848     }
849     else if (*ip_arg == NULL) {
850         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,237, "Arg(*ip_arg) is NULL pointer.");
851     }
852     else {
853         /*-------- DEBUG LOG --------*/
854         if (ip_protomod.get_log_level != NULL &&
855             LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
856             PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,60, "free: %p",
857                 *ip_arg);
858         }
859         /*------ DEBUG LOG END ------*/
860
861         /* free and NULL */
862         free((struct l7vs_ip_service_arg*) *ip_arg);
863         *ip_arg = NULL;
864     }
865
866     /*-------- DEBUG LOG --------*/
867     if (ip_protomod.get_log_level != NULL &&
868         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
869         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,270,
870             "out_function: void destroy_sa(void** ip_arg)");
871     }
872     /*------ DEBUG LOG END ------*/
873 }
874
875 /*!
876  * Create strings for service list of l7vsadm
877  * @param[out] srv_arg      service argument struct
878  * @param[in]  srv_handle   a unique service ID
879  * @retval 0  successfully create strings
880  * @retval -1 some errors occur.
881  */
882 static int
883 service_arg(struct l7vs_service_arg_multi *srv_arg_mt, handle_t srv_handle)
884 {
885     struct l7vs_ip_service *ip_service;
886     struct l7vs_ip_service_arg c_sarg;
887     char   ip_argument[SERVICE_ARG_MAXSIZE];
888     int    return_value = 0;
889
890     /*-------- DEBUG LOG --------*/
891     if (ip_protomod.get_log_level != NULL &&
892         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
893         char srv_arg_mt_str[DEBUG_STR_LEN] = {0};
894         l7vs_service_arg_multi_c_str(srv_arg_mt_str, srv_arg_mt);
895         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,271,
896             "in_function: int service_arg(struct l7vs_service_arg_multi* srv_arg_mt, "
897             "handle_t srv_handle):srv_arg_mt=&(%s), srv_handle=%u",
898             srv_arg_mt_str, srv_handle);
899     }
900     /*------ DEBUG LOG END ------*/
901
902     /* check null */
903     if (srv_arg_mt == NULL) {
904         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,238, "Arg(srv_arg_mt) is NULL pointer.");
905         return_value = -1;
906         goto service_arg_out;
907     }
908
909     /* search service that has such a service ID */
910     ip_service = l7vs_protomod_ip_search_service(srv_handle);
911
912     /*-------- DEBUG LOG --------*/
913     if (ip_protomod.get_log_level != NULL &&
914         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
915         char ip_str[DEBUG_STR_LEN] = {0};
916         l7vs_ip_service_c_str(ip_str, ip_service);
917         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,272, "pointer assign: ip_service=&(%s)",
918             ip_str);
919     }
920     /*------ DEBUG LOG END ------*/
921
922     if (ip_service == NULL) {
923         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,239, "Could not find such service handle's ip service.");
924         return_value = -1;
925         goto service_arg_out;
926     }
927
928     /* initialize argument strings */
929     memset(ip_argument, 0, SERVICE_ARG_MAXSIZE);
930
931     /* set ip args to service argument struct */
932     srv_arg_mt->srv_arg.reschedule = ip_service->reschedule;
933
934     /* create long argument (l7vsadm option -L/-l) */
935     strncpy(srv_arg_mt->srv_arg.protomod_key_string, "", 256);
936
937     /* create verbose argument (l7vsadm option -V/-v) */
938     if (ip_service->forwarded_for) {
939         snprintf(ip_argument, SERVICE_ARG_MAXSIZE, "--timeout %d --forwarded-for", ip_service->timeout);
940     } else {
941         snprintf(ip_argument, SERVICE_ARG_MAXSIZE, "--timeout %d", ip_service->timeout);
942     }
943     strncpy(srv_arg_mt->srv_arg.protomod_opt_string, ip_argument, 512);
944
945     c_sarg.reschedule = ip_service->reschedule;
946
947     memcpy(srv_arg_mt->protomod_arg, &c_sarg, sizeof(struct l7vs_ip_service_arg));
948
949     /*-------- DEBUG LOG --------*/
950     if (ip_protomod.get_log_level != NULL &&
951         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
952         char ip_arg_str[DEBUG_STR_LEN] = {0};
953         l7vs_ip_service_arg_c_str(ip_arg_str, &c_sarg);
954         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,273,
955             "pointer assign: srv_arg_mt->protomod_arg=&(%s)", ip_arg_str);
956     }
957     /*------ DEBUG LOG END ------*/
958
959 service_arg_out:
960     /*-------- DEBUG LOG --------*/
961     if (ip_protomod.get_log_level != NULL &&
962         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
963         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,274,
964             "out_function: int service_arg(struct l7vs_service_arg_multi* srv_arg_mt, "
965             "handle_t srv_handle):return_value=%d", return_value);
966     }
967     /*------ DEBUG LOG END ------*/
968
969     return return_value;
970 }
971
972 /*!
973  * Parse l7vsadm options to ip argument
974  * @param[out] ip_arg   ip service argument struct
975  * @param[in]  argc     number of l7vsadm argument
976  * @param[in]  argv     l7vsadm argument list
977  * @retval 0  successfully parse argument
978  * @retval -1 some errors occur.
979  */
980 static int
981 parse(void *ip_arg, int argc, char *argv[])
982 {
983     struct l7vs_ip_service_arg *ip_service_arg;
984     static struct option opt[] = {
985         {"timeout",       required_argument, NULL, 'T'},
986         {"forwarded-for", no_argument,       NULL, 'F'},
987         {"reschedule",    no_argument,       NULL, 'R'},
988         {"no-reschedule", no_argument,       NULL, 'N'},
989         {NULL,            0,                 NULL, 0  }
990     };
991     int c;
992     int return_value       = 0;
993     int timeout_flag       = 0;
994     int forwarded_for_flag = 0;
995     int reschedule_flag    = 0;
996     unsigned long buffer;
997
998     /*-------- DEBUG LOG --------*/
999     if (ip_protomod.get_log_level != NULL &&
1000         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1001         int i;
1002         char argv_str[DEBUG_STR_LEN]   = {0};
1003         char ip_arg_str[DEBUG_STR_LEN] = {0};
1004         l7vs_ip_service_arg_c_str(ip_arg_str, (struct l7vs_ip_service_arg*) ip_arg);
1005         argv_str[0] = '\0';
1006         if (argv == NULL)
1007             snprintf(argv_str, DEBUG_STR_LEN, "NULL");
1008         else {
1009             for (i = 0; i < argc; i++) {
1010                 snprintf(argv_str, DEBUG_STR_LEN, "%sargv[%d]=\"%s\", ", argv_str, i, argv[i]);
1011             }
1012             i = strnlen(argv_str, DEBUG_STR_LEN);
1013             if (i > 1)
1014                 argv_str[i - 2] = '\0';
1015         }
1016         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,275,
1017             "in_function: int parse(void* ip_arg, int argc, char* argv[]):ip_arg=&(%s), "
1018             "argc=%d, %s", ip_arg_str, argc, argv_str);
1019     }
1020     /*------ DEBUG LOG END ------*/
1021
1022     /* check null */
1023     if (ip_arg == NULL) {
1024         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,240, "Arg(ip_arg) is NULL pointer.");
1025         return_value = -1;
1026         goto parse_out;
1027     }
1028     if (argv == NULL) {
1029         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,241, "Arg(argv) is NULL pointer.");
1030         return_value = -1;
1031         goto parse_out;
1032     }
1033
1034     ip_service_arg = (struct l7vs_ip_service_arg *) ip_arg;
1035     optind = 0;
1036
1037     /* check all argument */
1038     while ((c = getopt_long(argc, argv, "T:FRN", opt, NULL)) != -1) {
1039         switch (c) {
1040         /* --timeout / -T */
1041         case 'T':
1042             if (sscanf(optarg, "%lu", &buffer) == 0) {
1043                 PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,107,
1044                     "-T/--timeout option value '%s' is invalid.", optarg);
1045                 return_value = -1;
1046                 goto parse_out;
1047             }
1048             if (buffer > INT_MAX) {
1049                 PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,108,
1050                     "-T/--timeout option value '%s' is too large.", optarg);
1051                 return_value = -1;
1052                 goto parse_out;
1053             }
1054             else
1055                 ip_service_arg->timeout = buffer;
1056             timeout_flag++;
1057             break;
1058         /* --forwarded-for / -F */
1059         case 'F':
1060             /* x-forwarded-for on */
1061             ip_service_arg->forwarded_for = 1;
1062             forwarded_for_flag++;
1063             break;
1064         /* --reschedule / -R */
1065         case 'R':
1066             /* reschedule on */
1067             ip_service_arg->reschedule = 1;
1068             reschedule_flag++;
1069             break;
1070         /* --no-reschedule / -N */
1071         case 'N':
1072             /* reschedule off */
1073             ip_service_arg->reschedule = 0;
1074             reschedule_flag++;
1075             break;
1076         /* else error */
1077         default:
1078             PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,242, "Option error.");
1079             return_value = -1;
1080             goto parse_out;
1081         }
1082     }
1083
1084     /* when set both -R and -N at the same time */
1085     if (reschedule_flag > 1) {
1086         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,243,
1087             "You have to choose either of reschdule or no-reschedule.");
1088         return_value = -1;
1089         goto parse_out;
1090     }
1091     /* same option */
1092     if (timeout_flag > 1) {
1093         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,113,
1094             "Cannot set multiple option '--timeout/-T'.");
1095         return_value = -1;
1096         goto parse_out;
1097     }
1098     /* set default options */
1099     if (timeout_flag == 0) {
1100         ip_service_arg->timeout = 3600;
1101     }
1102     /* set default no reschedule */
1103     if (reschedule_flag == 0) {
1104         ip_service_arg->reschedule = 0;
1105     }
1106     /* set default no forwarded_for */
1107     if (forwarded_for_flag == 0) {
1108         ip_service_arg->forwarded_for = 0;
1109     }
1110
1111 parse_out:
1112     /*-------- DEBUG LOG --------*/
1113     if (ip_protomod.get_log_level != NULL &&
1114         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1115         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,276,
1116             "out_function: int parse(void* ip_arg, int argc, char* argv[]):return_value=%d",
1117             return_value);
1118     }
1119     /*------ DEBUG LOG END ------*/
1120
1121     return return_value;
1122 }
1123
1124 /*!
1125  * Search ip service from ip service list using service handle
1126  * @param[in]   service_handle  a unique service ID
1127  * @return ip service struct when service was found. NULL when service was not found.
1128  */
1129 static struct l7vs_ip_service *
1130 l7vs_protomod_ip_search_service(handle_t service_handle)
1131 {
1132     /* ip service list counter */
1133     int service_number = 0;
1134     struct l7vs_ip_service* return_value = NULL;
1135
1136     /*-------- DEBUG LOG --------*/
1137     if (ip_protomod.get_log_level != NULL &&
1138         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1139         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,277,
1140             "in_function: struct l7vs_ip_service* l7vs_protomod_ip_search_service(handle_t service_handle):"
1141             "service_handle=%d", service_handle);
1142     }
1143     /*------ DEBUG LOG END ------*/
1144
1145     /* check all ip service list */
1146     for (service_number = 0; service_number < IP_SERVICE_NUMBER; ++service_number) {
1147         /* found the service has same service handle */
1148         if (ip_service_list[service_number] != NULL && 
1149             ip_service_list[service_number]->service_handle == service_handle) {
1150             return ip_service_list[service_number];
1151         }
1152     }
1153     
1154     /*-------- DEBUG LOG --------*/
1155     if (ip_protomod.get_log_level != NULL &&
1156         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1157         char ssl_str[DEBUG_STR_LEN] = {0};
1158         l7vs_ip_service_c_str(ssl_str, return_value);
1159         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,278,
1160             "out_function: struct l7vs_ip_service* l7vs_protomod_ip_search_service(handle_t service_handle):"
1161             "return_value=&(%s)", ssl_str);
1162     }
1163     /*------ DEBUG LOG END ------*/
1164
1165     return return_value;
1166 }
1167
1168 /*!
1169  * Create ip service.
1170  * @param void
1171  * @return ip service struct when create a service. NULL when cannot create service.
1172  */
1173 static struct l7vs_ip_service *
1174 l7vs_protomod_ip_create_service()
1175 {
1176     /* ip service list counter */
1177     int service_number = 0;
1178     struct l7vs_ip_service* return_value = NULL;
1179
1180     /*-------- DEBUG LOG --------*/
1181     if (ip_protomod.get_log_level != NULL &&
1182         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1183         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,279,
1184             "in_function: struct l7vs_ip_service* l7vs_protomod_ip_create_service()");
1185     }
1186     /*------ DEBUG LOG END ------*/
1187
1188     /* check all ip service list */
1189     for (service_number = 0; service_number < IP_SERVICE_NUMBER - 1; ++service_number) {
1190         /* if pointer that does not point NULL exists ... */
1191         if (ip_service_list[service_number] == NULL) {
1192             /* create a service at empty pointer */
1193             ip_service_list[service_number] = (struct l7vs_ip_service *) calloc(1, sizeof(struct l7vs_ip_service));
1194
1195             /*-------- DEBUG LOG --------*/
1196             if (ip_protomod.get_log_level != NULL &&
1197                 LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
1198                 PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,61, "calloc: addr=%p, size=%ld",
1199                     ip_service_list[service_number], (unsigned long int) sizeof(struct l7vs_ip_service));
1200             }
1201             /*------ DEBUG LOG END ------*/
1202
1203             if (ip_service_list[service_number] == NULL) {
1204                 PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,54, "Could not allocate memory.");
1205                 goto create_service_out;
1206             }
1207             return_value = ip_service_list[service_number];
1208             goto create_service_out;
1209         }
1210     }
1211     
1212     /* all service list is full */
1213     PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,244, "ip service list is full.");
1214
1215 create_service_out:
1216     /*-------- DEBUG LOG --------*/
1217     if (ip_protomod.get_log_level != NULL &&
1218         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1219         char ssl_str[DEBUG_STR_LEN] = {0};
1220         l7vs_ip_service_c_str(ssl_str, return_value);
1221         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,280,
1222             "out_function: struct l7vs_ip_service* l7vs_protomod_ip_create_service():"
1223             "return_value=&(%s)", ssl_str);
1224     }
1225     /*------ DEBUG LOG END ------*/
1226
1227     return return_value;
1228 }
1229
1230 /*!
1231  * Create temporary ip service.
1232  * @param  void
1233  * @return ip service struct when create a service. NULL when cannot create service.
1234  */
1235 static struct l7vs_ip_service *
1236 l7vs_protomod_ip_create_temp_service()
1237 {
1238     struct l7vs_ip_service* return_value = NULL;
1239
1240     /*-------- DEBUG LOG --------*/
1241     if (ip_protomod.get_log_level != NULL &&
1242         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1243         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,281,
1244             "in_function: struct l7vs_ip_service* l7vs_protomod_ip_create_temp_service()");
1245     }
1246     /*------ DEBUG LOG END ------*/
1247
1248     /* if pointer that does not point NULL exists ... */
1249     if (ip_service_list[IP_SERVICE_NUMBER - 1] != NULL) {
1250         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,245, "Temporary ip service is being used by other process.");
1251         goto create_temp_service_out;
1252     }
1253
1254     /* create temp service */
1255     ip_service_list[IP_SERVICE_NUMBER - 1] = (struct l7vs_ip_service *) calloc(1, sizeof(struct l7vs_ip_service));
1256
1257     /*-------- DEBUG LOG --------*/
1258     if (ip_protomod.get_log_level != NULL &&
1259         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
1260         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,62, "calloc: addr=%p, size=%ld",
1261             ip_service_list[IP_SERVICE_NUMBER - 1], (unsigned long int) sizeof(struct l7vs_ip_service));
1262     }
1263     /*------ DEBUG LOG END ------*/
1264
1265     if (ip_service_list[IP_SERVICE_NUMBER - 1] == NULL) {
1266         PUT_LOG_ERROR(ip_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,55, "Could not allocate memory");
1267         goto create_temp_service_out;
1268     }
1269
1270     return_value = ip_service_list[IP_SERVICE_NUMBER - 1];
1271
1272 create_temp_service_out:
1273     /*-------- DEBUG LOG --------*/
1274     if (ip_protomod.get_log_level != NULL &&
1275         LOG_LV_DEBUG == ip_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1276         char ssl_str[DEBUG_STR_LEN] = {0};
1277         l7vs_ip_service_c_str(ssl_str, return_value);
1278         PUT_LOG_DEBUG(ip_protomod, LOG_CAT_L7VSD_PROTOCOL,282,
1279             "out_function: struct l7vs_ip_service* l7vs_protomod_ip_create_service():"
1280             "return_value=&(%s)", ssl_str);
1281     }
1282     /*------ DEBUG LOG END ------*/
1283
1284     return return_value;
1285 }
1286
1287 /*!
1288  * Serialize struct l7vs_ip_service for debug log.
1289  * @param[out]  buf     serialized string
1290  * @param[in]   ip      l7vs_ip_service struct
1291  */
1292 static void l7vs_ip_service_c_str(char* buf, struct l7vs_ip_service* ip) {
1293     if (ip == NULL) {
1294         snprintf(buf, DEBUG_STR_LEN, "NULL");
1295     }
1296     else {
1297         snprintf(buf, DEBUG_STR_LEN, "service_handle=%d, timeout=%d, forwarded_for=%d, reschedule=%d",
1298             ip->service_handle, ip->timeout, ip->forwarded_for, ip->reschedule);
1299     }
1300 }
1301
1302 /*!
1303  * Serialize struct l7vs_ip_service_arg for debug log.
1304  * @param[out]  buf     serialized string
1305  * @param[in]   ip_arg  l7vs_ip_service_arg struct
1306  */
1307 void l7vs_ip_service_arg_c_str(char* buf, struct l7vs_ip_service_arg* ip_arg) {
1308     if (ip_arg == NULL) {
1309         snprintf(buf, DEBUG_STR_LEN, "NULL");
1310     }
1311     else {
1312         snprintf(buf, DEBUG_STR_LEN, "timeout=%d, forwarded_for=%d, reschedule=%d",
1313             ip_arg->timeout, ip_arg->forwarded_for, ip_arg->reschedule);
1314     }
1315 }
1316
1317 unsigned int l7vs_ip_service_calc_hash(struct l7vs_conn* conn) {
1318     unsigned int hash = ntohl(conn->caddr.sin_addr.s_addr) * GOLDEN_RATIO_PRIME;
1319     return hash >> 32 - HASH_TABLE_BITS;
1320 }
1321 // vim:et:ts=4:foldmethod=marker:foldmarker=LOG\ -,LOG\ END\ -: