• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

UltraMonkey-L7 V3(multi-thread implementation)


Commit MetaInfo

Revisióna8e661bfc9c21b14db6f5b873ff60c8276c9bfbd (tree)
Tiempo2012-09-10 12:08:13
Autorhibari <l05102@shib...>
Commiterhibari

Log Message

Edit spec file for generate devel package. And add module sample files.

Cambiar Resumen

Diferencia incremental

--- a/configure.in
+++ b/configure.in
@@ -57,6 +57,7 @@ else
5757 AC_SUBST( libdir, [/usr/lib] )
5858 AC_SUBST( CXXFLAGS, -march=i686 )
5959 fi
60+AC_SUBST( includedir, [/usr/include] )
6061
6162 AC_ARG_WITH(
6263 l7vs-moddir,
@@ -67,6 +68,16 @@ AC_ARG_WITH(
6768 )
6869
6970 AC_ARG_WITH(
71+ l7vs-includedir,
72+ [ --with-l7vs-includedir=DIR l7vs headerfile is to be installed in DIR.
73+
74+ [default=INCLUDEDIR/l7vs]
75+],
76+ [ l7vs_includedir="$withval" ],
77+ [ l7vs_includedir="${includedir}/l7vs" ]
78+)
79+
80+AC_ARG_WITH(
7081 l7vsadm-sockdir,
7182 [ --with-l7vsadm-sockdir=DIR l7vsadm sockfile PATH.
7283 [default=/var/run/l7vs] ],
@@ -94,6 +105,7 @@ AC_SUBST(CC,g++)
94105 AC_SUBST(exec_prefix, [/usr] )
95106 AC_SUBST(l7vsadm_sockdir)
96107 AC_SUBST(l7vs_moddir)
108+AC_SUBST(l7vs_includedir)
97109 AC_SUBST(l7vs_max_buffer_size)
98110 AC_SUBST(l7vs_config)
99111 AC_SUBST(MANDIR)
--- /dev/null
+++ b/doc/moduledevel/sample/protocol/Makefile.am
@@ -0,0 +1,24 @@
1+AUTOMAKE_OPTIONS = foreign
2+L7VS_MODDIR = @l7vs_moddir@
3+L7VS_INCLUDEDIR = @l7vs_includedir@
4+MAX_BUFFER_SIZE = @l7vs_max_buffer_size@
5+
6+AM_CPPFLAGS = \
7+ -g -O2 -fno-strict-aliasing -Wall -Werror -fPIC -pthread \
8+ -I$(L7VS_INCLUDEDIR) \
9+ -DMAX_BUFFER_SIZE=$(MAX_BUFFER_SIZE)
10+
11+lib_LTLIBRARIES = \
12+ libprotomod_simple.la
13+
14+libprotomod_simple_la_SOURCES = \
15+ protocol_module_base.h \
16+ http_protocol_module_base.h \
17+ http_protocol_module_base.cpp \
18+ protocol_module_simple.cpp
19+
20+install:
21+ cp ./.libs/libprotomod_simple.so ./.libs/protomod_simple.so && \
22+ $(INSTALL) -m 755 -d $(L7VS_MODDIR)
23+ $(INSTALL) -m 755 -D \
24+ ./.libs/protomod_simple.so $(L7VS_MODDIR)
--- /dev/null
+++ b/doc/moduledevel/sample/protocol/README
@@ -0,0 +1,25 @@
1+Sample source of protocol module for UltraMonkey-L7 .
2+
3+== Files ==
4+./protocol
5+Makefile.am
6+configure.in
7+http_protocol_module_base.cpp
8+http_protocol_module_base.h
9+protocol_module_simple.cpp
10+protocol_module_simple.h
11+
12+== Set up ==
13+*please install um-l7 devel package before compile.
14+
15+cp -r ./protocol /path/to/develop
16+cd /path/to/develop/protocol
17+autoreconf -ifv
18+./configure
19+make
20+make install
21+
22+== How to use this module ==
23+l7vsadm -A -t IP:PORT -m simple
24+
25+
--- /dev/null
+++ b/doc/moduledevel/sample/protocol/configure.in
@@ -0,0 +1,89 @@
1+AC_PREREQ(2.59)
2+AC_INIT(l7vsd)
3+PACKAGENAME=ultramonkeyl7-mod-simple-1.0.0
4+VERSION=1.0.0
5+
6+AM_INIT_AUTOMAKE($PACKAGENAME, $VERSION, no-define )
7+AC_CONFIG_SRCDIR([config.h.in])
8+AC_CONFIG_HEADER([config.h])
9+
10+# Checks for programs.
11+AC_PROG_CXX
12+AC_PROG_LIBTOOL
13+AC_PROG_CPP
14+AC_PROG_INSTALL
15+AC_PROG_LN_S
16+AC_PROG_MAKE_SET
17+
18+# Checks for libraries.
19+AC_CHECK_LIB(dl, dlopen)
20+AC_CHECK_LIB(log4cxx, main, :,
21+ [AC_MSG_ERROR( l7vsd require log4cxx library. )] )
22+AC_CHECK_LIB(rt, main, :,
23+ [AC_MSG_ERROR( l7vsd require rt library. )] )
24+AC_CHECK_LIB(boost_thread-mt, main, :,
25+ [AC_MSG_ERROR( l7vsd require boost library. )] )
26+AC_CHECK_LIB(boost_system-mt, main, :,
27+ [AC_MSG_ERROR( l7vsd require boost library. )] )
28+
29+# Checks for header files.
30+AC_CHECK_HEADERS([limits.h unistd.h])
31+
32+# Checks for typedefs, structures, and compiler characteristics.
33+AC_HEADER_STDBOOL
34+AC_C_CONST
35+AC_C_INLINE
36+AC_TYPE_SIZE_T
37+AC_STRUCT_TM
38+
39+# Checks for library functions.
40+AC_HEADER_STDC
41+AC_FUNC_MKTIME
42+AC_FUNC_STRFTIME
43+AC_CHECK_FUNCS([gethostname localtime_r memset])
44+
45+# application-specific option
46+if test `uname -m` == "x86_64"; then
47+ AC_SUBST( libdir, [/usr/lib64] )
48+else
49+ AC_SUBST( libdir, [/usr/lib] )
50+ AC_SUBST( CXXFLAGS, -march=i686 )
51+fi
52+AC_SUBST( includedir, [/usr/include] )
53+
54+AC_ARG_WITH(
55+ l7vs-moddir,
56+ [ --with-l7vs-moddir=DIR l7vs module is to be installed in DIR.
57+ [default=LIBDIR/l7vs] ],
58+ [ l7vs_moddir="$withval" ],
59+ [ l7vs_moddir="${libdir}/l7vs" ]
60+)
61+
62+AC_ARG_WITH(
63+ l7vs-includedir,
64+ [ --with-l7vs-includedir=DIR l7vs headerfile is to be installed in DIR.
65+ [default=INCLUDEDIR/l7vs] ],
66+ [ l7vs_includedir="$withval" ],
67+ [ l7vs_includedir="${includedir}/l7vs" ]
68+)
69+
70+AC_ARG_WITH(
71+ l7vs-buffer-size,
72+ [ --with-l7vs-buffer-size=NUM l7vsd using heap buffer size.
73+ [default=4096] ],
74+ [ l7vs_max_buffer_size="$withval" ],
75+ [ l7vs_max_buffer_size=4096 ]
76+)
77+
78+
79+AC_SUBST(CC,g++)
80+AC_SUBST(exec_prefix, [/usr] )
81+AC_SUBST(l7vs_moddir)
82+AC_SUBST(l7vs_includedir)
83+AC_SUBST(l7vs_max_buffer_size)
84+AC_SUBST(MANDIR)
85+AC_SUBST(ultramonkeyl7_version,ultramonkeyl7-$VERSION)
86+
87+AC_CONFIG_FILES([Makefile])
88+
89+AC_OUTPUT
--- /dev/null
+++ b/doc/moduledevel/sample/protocol/http_protocol_module_base.cpp
@@ -0,0 +1,1296 @@
1+/*
2+ * @file http_protocol_module_base.cpp
3+ * @brief shared object http protocol module abstract class
4+ *
5+ * L7VSD: Linux Virtual Server for Layer7 Load Balancing
6+ * Copyright (C) 2009 NTT COMWARE Corporation.
7+ *
8+ * This program is free software; you can redistribute it and/or
9+ * modify it under the terms of the GNU Lesser General Public
10+ * License as published by the Free Software Foundation; either
11+ * version 2.1 of the License, or (at your option) any later version.
12+ *
13+ * This program is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+ * Lesser General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU Lesser General Public
19+ * License along with this library; if not, write to the Free Software
20+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21+ * 02110-1301 USA
22+ *
23+ **********************************************************************/
24+#include <boost/xpressive/xpressive.hpp>
25+
26+#include "http_protocol_module_base.h"
27+#include "utility.h"
28+
29+using namespace boost::xpressive;
30+
31+cregex method_regex
32+= (as_xpr("GET") | as_xpr("HEAD") | as_xpr("POST") |
33+ as_xpr("PUT") | as_xpr("PROPFIND") | as_xpr("PROPPATCH") |
34+ as_xpr("OPTIONS") | as_xpr("CONNECT") | as_xpr("COPY") |
35+ as_xpr("TRACE") | as_xpr("DELETE") | as_xpr("LOCK") |
36+ as_xpr("UNLOCK") | as_xpr("MOVE") | as_xpr("MKCOL")) >> _s >>
37+ +~_s >> _s >>
38+ "HTTP/" >> _d >> "." >> _d;
39+
40+cregex version_regex_request
41+= +alpha >> _s >>
42+ +~_s >> _s >>
43+ "HTTP/" >> (as_xpr("1.0") | as_xpr("1.1"));
44+
45+cregex version_regex_response
46+= "HTTP/" >> (as_xpr("1.0") | as_xpr("1.1")) >> _s >>
47+ repeat<3>(_d) >> _s >>
48+ *_;
49+
50+cregex status_code_regex_check
51+= "HTTP/" >> _d >> "." >> _d >> _s >>
52+ range('1', '3') >> repeat<2>(_d) >> _s >>
53+ *_;
54+
55+cregex method_and_version_regex
56+= (as_xpr("GET") | as_xpr("HEAD") | as_xpr("POST") |
57+ as_xpr("PUT") | as_xpr("PROPFIND") | as_xpr("PROPPATCH") |
58+ as_xpr("OPTIONS") | as_xpr("CONNECT") | as_xpr("COPY") |
59+ as_xpr("TRACE") | as_xpr("DELETE") | as_xpr("LOCK") |
60+ as_xpr("UNLOCK") | as_xpr("MOVE") | as_xpr("MKCOL")) >> _s >>
61+ +~_s >> _s >>
62+ "HTTP/" >> (as_xpr("1.0") | as_xpr("1.1"));
63+
64+cregex version_and_status_code_regex
65+= "HTTP/" >> (as_xpr("1.0") | as_xpr("1.1")) >> _s >>
66+ range('1', '3') >> repeat<2>(_d) >> _s >>
67+ *_;
68+
69+cregex uri_regex
70+= +alpha >> _s >>
71+ (s1 = *~_s) >> _s >>
72+ "HTTP/" >> _d >> "." >> _d;
73+
74+cregex status_code_regex_find
75+= "HTTP/" >> _d >> "." >> _d >> _s >>
76+ (s1 = repeat<3>(_d)) >> _s >>
77+ *_;
78+
79+cregex http_header_regex_cookie
80+= _ln >> (s1 = icase("cookie") >> ":" >> *~_ln);
81+
82+cregex http_header_regex_content_length
83+= _ln >> (s1 = icase("content-length") >> ":" >> *~_ln);
84+
85+cregex http_header_regex_x_forwarded_for
86+= _ln >> (s1 = icase("x-forwarded-for") >> ":" >> *~_ln);
87+
88+cregex http_header_regex_all
89+= _ln >> (s1 = *_ >> ~_ln) >> repeat<2>(_ln);
90+
91+cregex http_header_regex_none
92+= _ln >> (s1 = _ln);
93+
94+//! check http method function
95+//! @param const char* buffer
96+//! @param const size_t buffer_len
97+//! @return CHECK_RESULT_TAG http method is valid
98+l7vs::http_protocol_module_base::CHECK_RESULT_TAG
99+l7vs::http_protocol_module_base::check_http_method(const char *buffer,
100+ const size_t buffer_len)
101+{
102+
103+ //---------- DEBUG LOG START ------------------------------
104+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
105+ boost::format outform("function in : [check_http_method] : "
106+ "buffer_len = [%d]");
107+
108+ outform % buffer_len;
109+
110+ putLogDebug(0,
111+ outform.str(),
112+ __FILE__,
113+ __LINE__);
114+ }
115+ //---------- DEBUG LOG END ------------------------------
116+
117+ l7vs::http_protocol_module_base::CHECK_RESULT_TAG check_result = CHECK_OK;
118+
119+ size_t line_length = 0;
120+
121+ if (likely(buffer != NULL)) {
122+
123+ for (line_length = 0; line_length < buffer_len; line_length++) {
124+ if (unlikely(buffer[line_length] == '\r' || buffer[line_length] == '\n'))
125+ break;
126+ }
127+
128+ if (likely(line_length < buffer_len)) {
129+ char *target = const_cast<char *>(buffer);
130+ char backup_c = target[line_length];
131+ target[line_length] = '\0';
132+ (regex_match(target, method_regex))
133+ ? check_result = CHECK_OK
134+ : check_result = CHECK_NG;
135+ target[line_length] = backup_c;
136+ } else {
137+ check_result = CHECK_IMPOSSIBLE;
138+ }
139+ } else {
140+
141+ check_result = CHECK_NG;
142+
143+ }
144+
145+ //---------- DEBUG LOG START ------------------------------
146+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
147+ boost::format outform("function out : [check_http_method] : "
148+ "check_result = [%d]");
149+
150+ outform % check_result;
151+
152+ putLogDebug(1,
153+ outform.str(),
154+ __FILE__,
155+ __LINE__);
156+ }
157+ //---------- DEBUG LOG END ------------------------------
158+
159+ return check_result;
160+
161+}
162+
163+//! check http version function
164+//! @param const char* buffer
165+//! @param const size_t buffer_len
166+//! @return CHECK_RESULT_TAG http version 1.0 or 1.1
167+l7vs::http_protocol_module_base::CHECK_RESULT_TAG
168+l7vs::http_protocol_module_base::check_http_version(const char *buffer,
169+ const size_t buffer_len)
170+{
171+
172+ //---------- DEBUG LOG START ------------------------------
173+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
174+ boost::format outform("function in : [check_http_version] : "
175+ "buffer_len = [%d]");
176+
177+ outform % buffer_len;
178+
179+ putLogDebug(2,
180+ outform.str(),
181+ __FILE__,
182+ __LINE__);
183+ }
184+ //---------- DEBUG LOG END ------------------------------
185+
186+ l7vs::http_protocol_module_base::CHECK_RESULT_TAG check_result = CHECK_OK;
187+
188+ size_t line_length = 0;
189+
190+ if (likely(buffer != NULL)) {
191+ for (line_length = 0; line_length < buffer_len; line_length++) {
192+ if (unlikely(buffer[line_length] == '\r' || buffer[line_length] == '\n'))
193+ break;
194+ }
195+
196+ if (likely(line_length < buffer_len)) {
197+ char *target = const_cast<char *>(buffer);
198+ char backup_c = target[line_length];
199+ target[line_length] = '\0';
200+
201+ if (!regex_match(target, version_regex_request) &&
202+ !regex_match(target, version_regex_response)) check_result = CHECK_NG;
203+
204+ target[line_length] = backup_c;
205+
206+ } else {
207+ check_result = CHECK_IMPOSSIBLE;
208+ }
209+ } else {
210+ check_result = CHECK_NG;
211+ }
212+
213+ //---------- DEBUG LOG START ------------------------------
214+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
215+ boost::format outform("function out : [check_http_version] : "
216+ "check_result = [%d]");
217+
218+ outform % check_result;
219+
220+ putLogDebug(3,
221+ outform.str(),
222+ __FILE__,
223+ __LINE__);
224+ }
225+ //---------- DEBUG LOG END ------------------------------
226+
227+ return check_result;
228+
229+}
230+
231+//! check http status code function
232+//! @param const char* buffer
233+//! @param const size_t buffer_len
234+//! @return CHECK_RESULT_TAG status code is normal or error
235+l7vs::http_protocol_module_base::CHECK_RESULT_TAG
236+l7vs::http_protocol_module_base::check_status_code(const char *buffer,
237+ const size_t buffer_len)
238+{
239+
240+ //---------- DEBUG LOG START ------------------------------
241+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
242+ boost::format outform("function in : [check_status_code] : "
243+ "buffer_len = [%d]");
244+
245+ outform % buffer_len;
246+
247+ putLogDebug(4,
248+ outform.str(),
249+ __FILE__,
250+ __LINE__);
251+ }
252+ //---------- DEBUG LOG END ------------------------------
253+
254+ l7vs::http_protocol_module_base::CHECK_RESULT_TAG check_result = CHECK_OK;
255+
256+ size_t line_length = 0;
257+
258+ if (likely(buffer != NULL)) {
259+ for (line_length = 0; line_length < buffer_len; line_length++) {
260+ if (unlikely(buffer[line_length] == '\r' || buffer[line_length] == '\n')) {
261+ break;
262+ }
263+ }
264+
265+ if (likely(line_length < buffer_len)) {
266+ char *target = const_cast<char *>(buffer);
267+ char backup_c = target[line_length];
268+ target[line_length] = '\0';
269+ if (!regex_match(target, status_code_regex_check)) check_result = CHECK_NG;
270+ target[line_length] = backup_c;
271+ } else {
272+ check_result = CHECK_IMPOSSIBLE;
273+ }
274+ } else {
275+ check_result = CHECK_NG;
276+ }
277+
278+ //---------- DEBUG LOG START ------------------------------
279+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
280+ boost::format outform("function out : [check_status_code] : "
281+ "check_result = [%d]");
282+
283+ outform % check_result;
284+
285+ putLogDebug(5,
286+ outform.str(),
287+ __FILE__,
288+ __LINE__);
289+ }
290+ //---------- DEBUG LOG END ------------------------------
291+
292+ return check_result;
293+
294+}
295+
296+//! check http method and version function
297+//! @param const char* buffer
298+//! @param const size_t buffer_len
299+//! @return CHECK_RESULT_TAG http method and version is valid
300+l7vs::http_protocol_module_base::CHECK_RESULT_TAG
301+l7vs::http_protocol_module_base::check_http_method_and_version(
302+ const char *buffer,
303+ const size_t buffer_len)
304+{
305+
306+ //---------- DEBUG LOG START ------------------------------
307+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
308+ boost::format outform("function in : [check_http_method_and_version] : "
309+ "buffer_len = [%d]");
310+
311+ outform % buffer_len;
312+
313+ putLogDebug(6,
314+ outform.str(),
315+ __FILE__,
316+ __LINE__);
317+ }
318+ //---------- DEBUG LOG END ------------------------------
319+
320+ l7vs::http_protocol_module_base::CHECK_RESULT_TAG check_result = CHECK_OK;
321+
322+ size_t line_length = 0;
323+
324+ if (likely(buffer != NULL)) {
325+ for (line_length = 0; line_length < buffer_len; line_length++) {
326+ if (unlikely(buffer[line_length] == '\r' || buffer[line_length] == '\n')) {
327+ break;
328+ }
329+ }
330+ if (likely(line_length < buffer_len)) {
331+ char *target = const_cast<char *>(buffer);
332+ char backup_c = target[line_length];
333+ target[line_length] = '\0';
334+
335+ if (!regex_match(target, method_and_version_regex))
336+ check_result = CHECK_NG;
337+
338+ target[line_length] = backup_c;
339+ } else {
340+ check_result = CHECK_NG;
341+ }
342+ } else {
343+ check_result = CHECK_NG;
344+ }
345+
346+ //---------- DEBUG LOG START ------------------------------
347+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
348+ boost::format outform("function out : [check_http_method_and_version] : "
349+ "check_result = [%d]");
350+
351+ outform % check_result;
352+
353+ putLogDebug(7,
354+ outform.str(),
355+ __FILE__,
356+ __LINE__);
357+ }
358+ //---------- DEBUG LOG END ------------------------------
359+
360+ return check_result;
361+
362+}
363+
364+//! check http version and status code function
365+//! @param const char* buffer
366+//! @param const size_t buffer_len
367+//! @return CHECK_RESULT_TAG http version and status code is valid
368+l7vs::http_protocol_module_base::CHECK_RESULT_TAG
369+l7vs::http_protocol_module_base::check_http_version_and_status_code(
370+ const char *buffer,
371+ const size_t buffer_len)
372+{
373+
374+ //---------- DEBUG LOG START ------------------------------
375+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
376+ boost::format outform("function in : [check_http_version_and_status_code] : "
377+ "buffer_len = [%d]");
378+
379+ outform % buffer_len;
380+
381+ putLogDebug(8,
382+ outform.str(),
383+ __FILE__,
384+ __LINE__);
385+ }
386+ //---------- DEBUG LOG END ------------------------------
387+
388+ l7vs::http_protocol_module_base::CHECK_RESULT_TAG check_result = CHECK_OK;
389+
390+ size_t line_length = 0;
391+
392+ if (likely(buffer != NULL)) {
393+ for (line_length = 0; line_length < buffer_len; line_length++) {
394+ if (unlikely(buffer[line_length] == '\r' || buffer[line_length] == '\n')) {
395+ break;
396+ }
397+ }
398+
399+ if (likely(line_length < buffer_len)) {
400+ char *target = const_cast<char *>(buffer);
401+ char backup_c = target[line_length];
402+ target[line_length] = '\0';
403+ if (!regex_match(target, version_and_status_code_regex)) check_result = CHECK_NG;
404+ target[line_length] = backup_c;
405+ } else {
406+ check_result = CHECK_IMPOSSIBLE;
407+ }
408+ } else {
409+ check_result = CHECK_NG;
410+ }
411+
412+ //---------- DEBUG LOG START ------------------------------
413+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
414+ boost::format outform("function out : [check_http_version_and_status_code] : "
415+ "check_result = [%d]");
416+
417+ outform % check_result;
418+
419+ putLogDebug(9,
420+ outform.str(),
421+ __FILE__,
422+ __LINE__);
423+ }
424+ //---------- DEBUG LOG END ------------------------------
425+
426+ return check_result;
427+
428+}
429+
430+//! search uri function
431+//! @param const char* buffer
432+//! @param const size_t buffer_len
433+//! @param size_t& uri offset
434+//! @param size_t& uri length
435+//! @return bool find is true. not find is false
436+bool l7vs::http_protocol_module_base::find_uri(const char *buffer,
437+ const size_t buffer_len,
438+ size_t &uri_offset,
439+ size_t &uri_len)
440+{
441+
442+ //---------- DEBUG LOG START ------------------------------
443+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
444+ boost::format outform("function in : [find_uri] : "
445+ "buffer_len = [%d]");
446+
447+ outform % buffer_len;
448+
449+ putLogDebug(10,
450+ outform.str(),
451+ __FILE__,
452+ __LINE__);
453+ }
454+ //---------- DEBUG LOG END ------------------------------
455+
456+ bool find_result = true;
457+
458+ size_t line_length = 0;
459+
460+ match_results< const char * > result;
461+
462+ if (likely(buffer != NULL)) {
463+
464+ for (line_length = 0; line_length < buffer_len; line_length++) {
465+
466+ if (unlikely(buffer[line_length] == '\r' || buffer[line_length] == '\n')) {
467+
468+ break;
469+
470+ }
471+
472+ }
473+
474+ if (likely(line_length < buffer_len)) {
475+ char *target = const_cast<char *>(buffer);
476+ char backup_c = target[line_length];
477+ find_result = regex_search(target, result, uri_regex);
478+ if (find_result) {
479+ uri_offset = result.position(1);
480+ uri_len = result.length(1);
481+ }
482+ target[line_length] = backup_c;
483+ } else {
484+ find_result = false;
485+ }
486+ } else {
487+ find_result = false;
488+ }
489+
490+ //---------- DEBUG LOG START ------------------------------
491+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
492+ boost::format outform("function out : [find_uri] : "
493+ "find_result = [%d], "
494+ "uri_offset = [%d], "
495+ "uri_len = [%d]");
496+
497+ outform % find_result % uri_offset % uri_len;
498+
499+ putLogDebug(11,
500+ outform.str(),
501+ __FILE__,
502+ __LINE__);
503+ }
504+ //---------- DEBUG LOG END ------------------------------
505+
506+ return find_result;
507+
508+}
509+
510+//! search status function
511+//! @param const char* buffer
512+//! @param const size_t buffer_len
513+//! @param size_t& status offset
514+//! @param size_t& status length
515+//! @return bool find is true. not find is false
516+bool l7vs::http_protocol_module_base::find_status_code(const char *buffer,
517+ const size_t buffer_len,
518+ size_t &status_code_offset,
519+ size_t &status_code_len)
520+{
521+
522+ //---------- DEBUG LOG START ------------------------------
523+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
524+ boost::format outform("function in : [find_status_code] : "
525+ "buffer_len = [%d]");
526+
527+ outform % buffer_len;
528+
529+ putLogDebug(12,
530+ outform.str(),
531+ __FILE__,
532+ __LINE__);
533+ }
534+ //---------- DEBUG LOG END ------------------------------
535+
536+ bool find_result = true;
537+
538+ size_t line_length = 0;
539+
540+ match_results< const char * > result;
541+
542+ if (likely(buffer != NULL)) {
543+
544+ for (line_length = 0; line_length < buffer_len; line_length++) {
545+ if (unlikely(buffer[line_length] == '\r' || buffer[line_length] == '\n')) {
546+ break;
547+ }
548+ }
549+
550+ if (likely(line_length < buffer_len)) {
551+ char *target = const_cast<char *>(buffer);
552+ char backup_c = target[line_length];
553+ target[line_length] = '\0';
554+ find_result = regex_search(target, result, status_code_regex_find);
555+ if (find_result) {
556+ status_code_offset = result.position(1);
557+ status_code_len = result.length(1);
558+ }
559+ target[line_length] = backup_c;
560+ } else {
561+ find_result = false;
562+ }
563+ } else {
564+ find_result = false;
565+ }
566+
567+ //---------- DEBUG LOG START ------------------------------
568+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
569+ boost::format outform("function out : [find_status_code] : "
570+ "find_result = [%d], "
571+ "status_code_offset = [%d], "
572+ "status_code_len = [%d]");
573+
574+ outform % find_result % status_code_offset % status_code_len;
575+
576+ putLogDebug(13,
577+ outform.str(),
578+ __FILE__,
579+ __LINE__);
580+ }
581+ //---------- DEBUG LOG END ------------------------------
582+
583+ return find_result;
584+
585+}
586+
587+//! search http header function
588+//! @param const char* buffer
589+//! @param const size_t buffer_len
590+//! @param const string& header name
591+//! @param size_t& header offset
592+//! @param size_t& header length
593+//! @return bool find is true. not find is false
594+bool l7vs::http_protocol_module_base::find_http_header(const char *buffer,
595+ const size_t buffer_len,
596+ const std::string &http_header_name,
597+ size_t &http_header_offset,
598+ size_t &http_header_len)
599+{
600+
601+ //---------- DEBUG LOG START ------------------------------
602+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
603+ boost::format outform("function in : [find_http_header] : "
604+ "buffer_len = [%d], "
605+ "http_header_name = [%s]");
606+
607+ outform % buffer_len % http_header_name;
608+
609+ putLogDebug(14,
610+ outform.str(),
611+ __FILE__,
612+ __LINE__);
613+ }
614+ //---------- DEBUG LOG END ------------------------------
615+
616+ cregex http_header_regex;
617+
618+ bool find_result = true;
619+
620+ size_t count = 0;
621+ size_t header_begin = 0;
622+ size_t header_end = 0;
623+ size_t header_length = 0;
624+
625+ int header_begin_flag = 0;
626+ int header_end_flag = 0;
627+
628+ match_results< const char * > result;
629+
630+ if (likely(buffer != NULL)) {
631+
632+ for (count = 0; count < buffer_len; count++) {
633+
634+ if (unlikely(buffer[count] == '\r' || buffer[count] == '\n')) {
635+
636+ if (unlikely(header_begin_flag == 0)) {
637+
638+ header_begin = count;
639+ header_begin_flag = 1;
640+
641+ }
642+
643+ if (likely(count > 0)) {
644+
645+ if (unlikely((buffer[count-1] == '\r' && buffer[count] == '\r') ||
646+ (buffer[count-1] == '\n' && buffer[count] == '\n'))) {
647+
648+ header_end = count;
649+ header_end_flag = 1;
650+ break;
651+
652+ }
653+ }
654+
655+ if (likely(count > 2)) {
656+
657+ if (unlikely(buffer[count-3] == '\r' && buffer[count-2] == '\n' &&
658+ buffer[count-1] == '\r' && buffer[count] == '\n')) {
659+
660+ header_end = count;
661+ header_end_flag = 1;
662+ break;
663+
664+ }
665+ }
666+ }
667+ }
668+
669+ if (likely(header_begin_flag == 1 && header_end_flag == 1)) {
670+
671+ header_length = header_end - header_begin + 1;
672+ char *ptr = const_cast<char *>(buffer) + header_begin;
673+ char backup_c = *(ptr + header_length);
674+ *(ptr + header_length) = '\0';
675+
676+ if (http_header_name.length() > 0) {
677+ http_header_regex = _ln >> (s1 = icase(http_header_name) >> ":" >> *~_ln);
678+ find_result = regex_search(ptr , result, http_header_regex);
679+ if (find_result) {
680+ http_header_offset = result.position(1) + header_begin;
681+ http_header_len = result.length(1);
682+ }
683+ } else {
684+ http_header_regex = _ln >> (s1 = *_ >> ~_ln) >> repeat<2>(_ln);
685+ find_result = regex_search(ptr, result, http_header_regex);
686+ if (find_result) {
687+ http_header_offset = result.position(1) + header_begin;
688+ http_header_len = result.length(1);
689+ } else {
690+ http_header_regex = _ln >> (s1 = _ln);
691+ find_result = regex_search(ptr, result, http_header_regex);
692+ if (find_result) {
693+ http_header_offset = result.position(1) + header_begin;
694+ http_header_len = 0;
695+ }
696+ }
697+ }
698+ *(ptr + header_length) = backup_c;
699+ } else {
700+ find_result = false;
701+ }
702+ } else {
703+ find_result = false;
704+ }
705+
706+ //---------- DEBUG LOG START ------------------------------
707+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
708+ boost::format outform("function out : [find_http_header] : "
709+ "find_result = [%d], "
710+ "http_header_offset = [%d], "
711+ "http_header_len = [%d]");
712+
713+ outform % find_result % http_header_offset % http_header_len;
714+
715+ putLogDebug(15,
716+ outform.str(),
717+ __FILE__,
718+ __LINE__);
719+ }
720+ //---------- DEBUG LOG END ------------------------------
721+
722+ return find_result;
723+
724+}
725+
726+//! search http header Cookie function
727+//! @param const char* buffer
728+//! @param const size_t buffer_len
729+//! @param size_t& header offset
730+//! @param size_t& header length
731+//! @return bool find is true. not find is false
732+bool l7vs::http_protocol_module_base::find_http_header_cookie(
733+ const char *buffer,
734+ const size_t buffer_len,
735+ size_t &http_header_offset,
736+ size_t &http_header_len)
737+{
738+
739+ //---------- DEBUG LOG START ------------------------------
740+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
741+ boost::format outform("function in : [find_http_header_cookie] : "
742+ "buffer_len = [%d]");
743+
744+ outform % buffer_len;
745+
746+ putLogDebug(16,
747+ outform.str(),
748+ __FILE__,
749+ __LINE__);
750+ }
751+ //---------- DEBUG LOG END ------------------------------
752+
753+ bool find_result = true;
754+
755+ size_t count = 0;
756+ size_t header_begin = 0;
757+ size_t header_end = 0;
758+ size_t header_length = 0;
759+
760+ int header_begin_flag = 0;
761+ int header_end_flag = 0;
762+
763+ match_results< const char * > result;
764+
765+ if (likely(buffer != NULL)) {
766+ for (count = 0; count < buffer_len; count++) {
767+ if (unlikely(buffer[count] == '\r' || buffer[count] == '\n')) {
768+ if (unlikely(header_begin_flag == 0)) {
769+ header_begin = count;
770+ header_begin_flag = 1;
771+ }
772+ if (likely(count > 0)) {
773+ if (unlikely((buffer[count-1] == '\r' && buffer[count] == '\r') ||
774+ (buffer[count-1] == '\n' && buffer[count] == '\n'))) {
775+ header_end = count;
776+ header_end_flag = 1;
777+ break;
778+ }
779+ }
780+ if (likely(count > 2)) {
781+ if (unlikely(buffer[count-3] == '\r' && buffer[count-2] == '\n' &&
782+ buffer[count-1] == '\r' && buffer[count] == '\n')) {
783+ header_end = count;
784+ header_end_flag = 1;
785+ break;
786+
787+ }
788+ }
789+ }
790+ }
791+
792+ if (likely(header_begin_flag == 1 && header_end_flag == 1)) {
793+ header_length = header_end - header_begin + 1;
794+ char *ptr = const_cast<char *>(buffer) + header_begin;
795+ char backup_c = *(ptr + header_length);
796+ *(ptr + header_length) = '\0';
797+
798+ find_result = regex_search(ptr, result, http_header_regex_cookie);
799+ if (find_result) {
800+ http_header_offset = result.position(1) + header_begin;
801+ http_header_len = result.length(1);
802+ }
803+ *(ptr + header_length) = backup_c;
804+ } else {
805+ find_result = false;
806+ }
807+ } else {
808+ find_result = false;
809+ }
810+
811+ //---------- DEBUG LOG START ------------------------------
812+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
813+ boost::format outform("function out : [find_http_header_cookie] : "
814+ "find_result = [%d], "
815+ "http_header_offset = [%d], "
816+ "http_header_len = [%d]");
817+
818+ outform % find_result % http_header_offset % http_header_len;
819+
820+ putLogDebug(17,
821+ outform.str(),
822+ __FILE__,
823+ __LINE__);
824+ }
825+ //---------- DEBUG LOG END ------------------------------
826+
827+ return find_result;
828+
829+}
830+
831+//! search http header Content_Length function
832+//! @param const char* buffer
833+//! @param const size_t buffer_len
834+//! @param size_t& header offset
835+//! @param size_t& header length
836+//! @return bool find is true. not find is false
837+bool l7vs::http_protocol_module_base::find_http_header_content_length(
838+ const char *buffer,
839+ const size_t buffer_len,
840+ size_t &http_header_offset,
841+ size_t &http_header_len)
842+{
843+
844+ //---------- DEBUG LOG START ------------------------------
845+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
846+ boost::format outform("function in : [find_http_header_content_length] : "
847+ "buffer_len = [%d]");
848+
849+ outform % buffer_len;
850+
851+ putLogDebug(18,
852+ outform.str(),
853+ __FILE__,
854+ __LINE__);
855+ }
856+ //---------- DEBUG LOG END ------------------------------
857+
858+ bool find_result = true;
859+
860+ size_t count = 0;
861+ size_t header_begin = 0;
862+ size_t header_end = 0;
863+ size_t header_length = 0;
864+
865+ int header_begin_flag = 0;
866+ int header_end_flag = 0;
867+
868+ match_results< const char * > result;
869+
870+ if (likely(buffer != NULL)) {
871+ for (count = 0; count < buffer_len; count++) {
872+ if (unlikely(buffer[count] == '\r' || buffer[count] == '\n')) {
873+ if (unlikely(header_begin_flag == 0)) {
874+ header_begin = count;
875+ header_begin_flag = 1;
876+ }
877+ if (likely(count > 0)) {
878+ if (unlikely((buffer[count-1] == '\r' && buffer[count] == '\r') ||
879+ (buffer[count-1] == '\n' && buffer[count] == '\n'))) {
880+ header_end = count;
881+ header_end_flag = 1;
882+ break;
883+ }
884+ }
885+ if (likely(count > 2)) {
886+ if (unlikely(buffer[count-3] == '\r' && buffer[count-2] == '\n' &&
887+ buffer[count-1] == '\r' && buffer[count] == '\n')) {
888+ header_end = count;
889+ header_end_flag = 1;
890+ break;
891+ }
892+ }
893+ }
894+ }
895+
896+ if (likely(header_begin_flag == 1 && header_end_flag == 1)) {
897+ header_length = header_end - header_begin + 1;
898+
899+ char *ptr = const_cast<char *>(buffer) + header_begin;
900+ char backup_c = *(ptr + header_length);
901+ *(ptr + header_length) = '\0';
902+
903+ find_result = regex_search(ptr, result, http_header_regex_content_length);
904+ if (find_result) {
905+ http_header_offset = result.position(1) + header_begin;
906+ http_header_len = result.length(1);
907+ }
908+
909+ *(ptr + header_length) = backup_c;
910+ } else {
911+
912+ find_result = false;
913+
914+ }
915+ } else {
916+
917+ find_result = false;
918+
919+ }
920+
921+ //---------- DEBUG LOG START ------------------------------
922+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
923+ boost::format outform("function out : [find_http_header_content_length] : "
924+ "find_result = [%d], "
925+ "http_header_offset = [%d], "
926+ "http_header_len = [%d]");
927+
928+ outform % find_result % http_header_offset % http_header_len;
929+
930+ putLogDebug(19,
931+ outform.str(),
932+ __FILE__,
933+ __LINE__);
934+ }
935+ //---------- DEBUG LOG END ------------------------------
936+
937+ return find_result;
938+
939+}
940+
941+//! search http header X_Forwarded_For function
942+//! @param const char* buffer
943+//! @param const size_t buffer_len
944+//! @param size_t& header offset
945+//! @param size_t& header length
946+//! @return bool find is true. not find is false
947+bool l7vs::http_protocol_module_base::find_http_header_x_forwarded_for(
948+ const char *buffer,
949+ const size_t buffer_len,
950+ size_t &http_header_offset,
951+ size_t &http_header_len)
952+{
953+
954+ //---------- DEBUG LOG START ------------------------------
955+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
956+ boost::format outform("function in : [find_http_header_x_forwarded_for] : "
957+ "buffer_len = [%d]");
958+
959+ outform % buffer_len;
960+
961+ putLogDebug(20,
962+ outform.str(),
963+ __FILE__,
964+ __LINE__);
965+ }
966+ //---------- DEBUG LOG END ------------------------------
967+
968+ bool find_result = true;
969+
970+ size_t count = 0;
971+ size_t header_begin = 0;
972+ size_t header_end = 0;
973+ size_t header_length = 0;
974+
975+ int header_begin_flag = 0;
976+ int header_end_flag = 0;
977+
978+ match_results< const char * > result;
979+
980+ if (likely(buffer != NULL)) {
981+ for (count = 0; count < buffer_len; count++) {
982+ if (unlikely(buffer[count] == '\r' || buffer[count] == '\n')) {
983+ if (unlikely(header_begin_flag == 0)) {
984+ header_begin = count;
985+ header_begin_flag = 1;
986+ }
987+ if (likely(count > 0)) {
988+ if (unlikely((buffer[count-1] == '\r' && buffer[count] == '\r') ||
989+ (buffer[count-1] == '\n' && buffer[count] == '\n'))) {
990+ header_end = count;
991+ header_end_flag = 1;
992+ break;
993+ }
994+ }
995+
996+ if (likely(count > 2)) {
997+ if (unlikely(buffer[count-3] == '\r' && buffer[count-2] == '\n' &&
998+ buffer[count-1] == '\r' && buffer[count] == '\n')) {
999+ header_end = count;
1000+ header_end_flag = 1;
1001+ break;
1002+
1003+ }
1004+ }
1005+ }
1006+ }
1007+
1008+ if (likely(header_begin_flag == 1 && header_end_flag == 1)) {
1009+
1010+ header_length = header_end - header_begin + 1;
1011+ char *ptr = const_cast<char *>(buffer) + header_begin;
1012+ char backup_c = *(ptr + header_length);
1013+ *(ptr + header_length) = '\0';
1014+
1015+ find_result = regex_search(ptr, result, http_header_regex_x_forwarded_for);
1016+ if (find_result == true) {
1017+ http_header_offset = result.position(1) + header_begin;
1018+ http_header_len = result.length(1);
1019+ }
1020+
1021+ *(ptr + header_length) = backup_c;
1022+ } else {
1023+
1024+ find_result = false;
1025+
1026+ }
1027+ } else {
1028+
1029+ find_result = false;
1030+
1031+ }
1032+
1033+ //---------- DEBUG LOG START ------------------------------
1034+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
1035+ boost::format outform("function out : [find_http_header_x_forwarded_for] : "
1036+ "find_result = [%d], "
1037+ "http_header_offset = [%d], "
1038+ "http_header_len = [%d]");
1039+
1040+ outform % find_result % http_header_offset % http_header_len;
1041+
1042+ putLogDebug(21,
1043+ outform.str(),
1044+ __FILE__,
1045+ __LINE__);
1046+ }
1047+ //---------- DEBUG LOG END ------------------------------
1048+
1049+ return find_result;
1050+
1051+}
1052+
1053+//! search http header all function
1054+//! @param const char* buffer
1055+//! @param const size_t buffer_len
1056+//! @param size_t& header offset
1057+//! @param size_t& header length
1058+//! @return bool find is true. not find is false
1059+bool l7vs::http_protocol_module_base::find_http_header_all(
1060+ const char *buffer,
1061+ const size_t buffer_len,
1062+ size_t &http_header_offset,
1063+ size_t &http_header_len)
1064+{
1065+
1066+ //---------- DEBUG LOG START ------------------------------
1067+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
1068+ boost::format outform("function in : [find_http_header_all] : "
1069+ "buffer_len = [%d]");
1070+
1071+ outform % buffer_len;
1072+
1073+ putLogDebug(22,
1074+ outform.str(),
1075+ __FILE__,
1076+ __LINE__);
1077+ }
1078+ //---------- DEBUG LOG END ------------------------------
1079+
1080+ bool find_result = true;
1081+
1082+ size_t count = 0;
1083+ size_t header_begin = 0;
1084+ size_t header_end = 0;
1085+ size_t header_length = 0;
1086+
1087+ int header_begin_flag = 0;
1088+ int header_end_flag = 0;
1089+
1090+ match_results< const char * > result;
1091+
1092+ if (likely(buffer != NULL)) {
1093+ for (count = 0; count < buffer_len; count++) {
1094+ if (unlikely(buffer[count] == '\r' || buffer[count] == '\n')) {
1095+ if (unlikely(header_begin_flag == 0)) {
1096+ header_begin = count;
1097+ header_begin_flag = 1;
1098+ }
1099+
1100+ if (likely(count > 0)) {
1101+ if (unlikely((buffer[count-1] == '\r' && buffer[count] == '\r') ||
1102+ (buffer[count-1] == '\n' && buffer[count] == '\n'))) {
1103+ header_end = count;
1104+ header_end_flag = 1;
1105+ break;
1106+ }
1107+ }
1108+
1109+ if (likely(count > 2)) {
1110+ if (unlikely(buffer[count-3] == '\r' && buffer[count-2] == '\n' &&
1111+ buffer[count-1] == '\r' && buffer[count] == '\n')) {
1112+ header_end = count;
1113+ header_end_flag = 1;
1114+ break;
1115+ }
1116+ }
1117+ }
1118+ }
1119+
1120+ if (likely(header_begin_flag == 1 && header_end_flag == 1)) {
1121+ header_length = header_end - header_begin + 1;
1122+ char *ptr = const_cast<char *>(buffer) + header_begin;
1123+ char backup_c = *(ptr + header_length);
1124+ *(ptr + header_length) = '\0';
1125+
1126+ find_result = regex_search(ptr, result, http_header_regex_all);
1127+
1128+ if (find_result) {
1129+ http_header_offset = result.position(1) + header_begin;
1130+ http_header_len = result.length(1);
1131+ } else {
1132+ find_result = regex_search(ptr, result, http_header_regex_none);
1133+ if (find_result == true) {
1134+ http_header_offset = result.position(1) + header_begin;
1135+ http_header_len = 0;
1136+ }
1137+ }
1138+ *(ptr + header_length) = backup_c;
1139+ } else {
1140+
1141+ find_result = false;
1142+
1143+ }
1144+ } else {
1145+
1146+ find_result = false;
1147+
1148+ }
1149+
1150+ //---------- DEBUG LOG START ------------------------------
1151+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
1152+ boost::format outform("function out : [find_http_header_all] : "
1153+ "find_result = [%d], "
1154+ "http_header_offset = [%d], "
1155+ "http_header_len = [%d]");
1156+
1157+ outform % find_result % http_header_offset % http_header_len;
1158+
1159+ putLogDebug(23,
1160+ outform.str(),
1161+ __FILE__,
1162+ __LINE__);
1163+ }
1164+ //---------- DEBUG LOG END ------------------------------
1165+
1166+ return find_result;
1167+
1168+}
1169+
1170+//! check http get method
1171+//! @param const char* buffer
1172+//! @return bool get method is true. other is false
1173+bool l7vs::http_protocol_module_base::is_get_request(const char *buffer)
1174+{
1175+ //---------- DEBUG LOG START ------------------------------
1176+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
1177+ putLogDebug(24,
1178+ "function in : [is_get_request].",
1179+ __FILE__,
1180+ __LINE__);
1181+ }
1182+ //---------- DEBUG LOG END ------------------------------
1183+
1184+ bool check_result = false;
1185+
1186+ if (likely(buffer != NULL)) {
1187+ if (strncmp("GET", buffer, 3) == 0) {
1188+ check_result = true;
1189+ }
1190+ }
1191+
1192+ //---------- DEBUG LOG START ------------------------------
1193+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
1194+ boost::format outform("function out : [is_get_request] : "
1195+ "check_result = [%d]");
1196+
1197+ outform % check_result;
1198+
1199+ putLogDebug(25,
1200+ outform.str(),
1201+ __FILE__,
1202+ __LINE__);
1203+ }
1204+ //---------- DEBUG LOG END ------------------------------
1205+
1206+ return check_result;
1207+}
1208+
1209+//! check http post method
1210+//! @param const char* buffer
1211+//! @return bool post method is true. other is false
1212+bool l7vs::http_protocol_module_base::is_post_request(const char *buffer)
1213+{
1214+ //---------- DEBUG LOG START ------------------------------
1215+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
1216+ putLogDebug(26,
1217+ "function in : [is_post_request].",
1218+ __FILE__,
1219+ __LINE__);
1220+ }
1221+ //---------- DEBUG LOG END ------------------------------
1222+
1223+ bool check_result = false;
1224+
1225+ if (likely(buffer != NULL)) {
1226+ if (strncmp("POST", buffer, 4) == 0) {
1227+ check_result = true;
1228+ }
1229+ }
1230+
1231+ //---------- DEBUG LOG START ------------------------------
1232+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
1233+ boost::format outform("function out : [is_post_request] : "
1234+ "check_result = [%d]");
1235+
1236+ outform % check_result;
1237+
1238+ putLogDebug(27,
1239+ outform.str(),
1240+ __FILE__,
1241+ __LINE__);
1242+ }
1243+ //---------- DEBUG LOG END ------------------------------
1244+
1245+ return check_result;
1246+}
1247+
1248+//! increment http statistics
1249+//! @param const char* buffer
1250+void l7vs::http_protocol_module_base::increment_stats(const char *buffer)
1251+{
1252+ //---------- DEBUG LOG START ------------------------------
1253+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
1254+ boost::format outform("function in : [increment_stats] : "
1255+ "http_get_requests = [%d], "
1256+ "http_post_requests = [%d], "
1257+ "http_requests = [%d]");
1258+
1259+ outform % http_stats_info.http_get_requests.get() %
1260+ http_stats_info.http_post_requests.get() %
1261+ http_stats_info.http_requests.get();
1262+ putLogDebug(28,
1263+ outform.str(),
1264+ __FILE__,
1265+ __LINE__);
1266+ }
1267+ //---------- DEBUG LOG END ------------------------------
1268+
1269+ if (buffer != NULL && statistic == true) {
1270+ if (is_get_request(buffer)) {
1271+ http_stats_info.http_get_requests++;
1272+ } else if (is_post_request(buffer)) {
1273+ http_stats_info.http_post_requests++;
1274+ }
1275+
1276+ http_stats_info.http_requests++;
1277+ }
1278+
1279+ //---------- DEBUG LOG START ------------------------------
1280+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
1281+ boost::format outform("function out : [increment_stats] : "
1282+ "http_get_requests = [%d], "
1283+ "http_post_requests = [%d], "
1284+ "http_requests = [%d]");
1285+
1286+ outform % http_stats_info.http_get_requests.get() %
1287+ http_stats_info.http_post_requests.get() %
1288+ http_stats_info.http_requests.get();
1289+
1290+ putLogDebug(29,
1291+ outform.str(),
1292+ __FILE__,
1293+ __LINE__);
1294+ }
1295+ //---------- DEBUG LOG END ------------------------------
1296+}
--- /dev/null
+++ b/doc/moduledevel/sample/protocol/http_protocol_module_base.h
@@ -0,0 +1,164 @@
1+/*
2+ * @file http_protocol_module_base.h
3+ * @brief shared object http protocol module abstract class
4+ *
5+ * L7VSD: Linux Virtual Server for Layer7 Load Balancing
6+ * Copyright (C) 2009 NTT COMWARE Corporation.
7+ *
8+ * This program is free software; you can redistribute it and/or
9+ * modify it under the terms of the GNU Lesser General Public
10+ * License as published by the Free Software Foundation; either
11+ * version 2.1 of the License, or (at your option) any later version.
12+ *
13+ * This program is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+ * Lesser General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU Lesser General Public
19+ * License along with this library; if not, write to the Free Software
20+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21+ * 02110-1301 USA
22+ *
23+ **********************************************************************/
24+#ifndef HTTP_PROTOCOL_MODULE_BASE_H
25+#define HTTP_PROTOCOL_MODULE_BASE_H
26+
27+#include "protocol_module_base.h"
28+
29+namespace l7vs
30+{
31+
32+class http_protocol_module_base : public protocol_module_base
33+{
34+protected:
35+ //! @enum CHECK_RESULT_TAG
36+ //! @brief check tag is return to http protocol module.
37+ enum CHECK_RESULT_TAG {
38+ CHECK_OK = 0, //!< check ok
39+ CHECK_NG, //!< check NG
40+ CHECK_IMPOSSIBLE //!< check impossible
41+ };
42+
43+ //! check http method function
44+ //! @param const char* buffer
45+ //! @param const size_t buffer_len
46+ //! @return CHECK_RESULT_TAG http method is valid
47+ CHECK_RESULT_TAG check_http_method(const char *, const size_t);
48+
49+ //! check http version function
50+ //! @param const char* buffer
51+ //! @param const size_t buffer_len
52+ //! @return CHECK_RESULT_TAG http version 1.0 or 1.1
53+ CHECK_RESULT_TAG check_http_version(const char *, const size_t);
54+
55+ //! check http status code function
56+ //! @param const char* buffer
57+ //! @param const size_t buffer_len
58+ //! @return CHECK_RESULT_TAG status code is normal or error
59+ CHECK_RESULT_TAG check_status_code(const char *, const size_t);
60+
61+ //! check http method and version function
62+ //! @param const char* buffer
63+ //! @param const size_t buffer_len
64+ //! @return CHECK_RESULT_TAG http method and version is valid
65+ CHECK_RESULT_TAG check_http_method_and_version(const char *, const size_t);
66+
67+ //! check http version and status code function
68+ //! @param const char* buffer
69+ //! @param const size_t buffer_len
70+ //! @return CHECK_RESULT_TAG http version and status code is valid
71+ CHECK_RESULT_TAG check_http_version_and_status_code(const char *, const size_t);
72+
73+ //! search uri function
74+ //! @param const char* buffer
75+ //! @param const size_t buffer_len
76+ //! @param size_t& uri offset
77+ //! @param size_t& uri length
78+ //! @return bool find is true. not find is false
79+ bool find_uri(const char *, const size_t, size_t &, size_t &);
80+
81+ //! search status function
82+ //! @param const char* buffer
83+ //! @param const size_t buffer_len
84+ //! @param size_t& status offset
85+ //! @param size_t& status length
86+ //! @return bool find is true. not find is false
87+ bool find_status_code(const char *, const size_t, size_t &, size_t &);
88+
89+ //! search http header function
90+ //! @param const char* buffer
91+ //! @param const size_t buffer_len
92+ //! @param const string& header name
93+ //! @param size_t& header offset
94+ //! @param size_t& header length
95+ //! @return bool find is true. not find is false
96+ bool find_http_header(const char *, const size_t, const std::string &, size_t &, size_t &);
97+
98+ //! search http header Cookie function
99+ //! @param const char* buffer
100+ //! @param const size_t buffer_len
101+ //! @param size_t& header offset
102+ //! @param size_t& header length
103+ //! @return bool find is true. not find is false
104+ bool find_http_header_cookie(const char *, const size_t, size_t &, size_t &);
105+
106+ //! search http header Content_Length function
107+ //! @param const char* buffer
108+ //! @param const size_t buffer_len
109+ //! @param size_t& header offset
110+ //! @param size_t& header length
111+ //! @return bool find is true. not find is false
112+ bool find_http_header_content_length(const char *, const size_t, size_t &, size_t &);
113+
114+ //! search http header X_Forwarded_For function
115+ //! @param const char* buffer
116+ //! @param const size_t buffer_len
117+ //! @param size_t& header offset
118+ //! @param size_t& header length
119+ //! @return bool find is true. not find is false
120+ bool find_http_header_x_forwarded_for(const char *, const size_t, size_t &, size_t &);
121+
122+ //! search http header all function
123+ //! @param const char* buffer
124+ //! @param const size_t buffer_len
125+ //! @param size_t& header offset
126+ //! @param size_t& header length
127+ //! @return bool find is true. not find is false
128+ bool find_http_header_all(const char *, const size_t, size_t &, size_t &);
129+
130+ //! check http get method
131+ //! @param const char* buffer
132+ //! @return bool get method is true. other is false
133+ bool is_get_request(const char *buffer);
134+
135+ //! check http post method
136+ //! @param const char* buffer
137+ //! @return bool post method is true. other is false
138+ bool is_post_request(const char *buffer);
139+
140+ //! increment http statistics
141+ //! @param const char* buffer
142+ void increment_stats(const char *buffer);
143+
144+ //! http statistic information
145+ http_stats http_stats_info;
146+
147+public:
148+
149+ //! constructor
150+ http_protocol_module_base(std::string in_modulename) : protocol_module_base(in_modulename) {};
151+
152+ //! destructor
153+ virtual ~http_protocol_module_base() {};
154+
155+ //! get base statistic object.
156+ //! @return base statistic object.
157+ stats_base &get_stats() {
158+ return http_stats_info;
159+ }
160+};
161+
162+} // namespace l7vsd
163+
164+#endif //HTTP_PROTOCOL_MODULE_BASE_H
--- /dev/null
+++ b/doc/moduledevel/sample/protocol/protocol_module_simple.cpp
@@ -0,0 +1,2741 @@
1+/*
2+ * @file protocol_module_simple.cpp
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) 2009 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+#include <boost/xpressive/xpressive.hpp>
26+#include <vector>
27+#include <list>
28+#include <algorithm>
29+#include <iostream>
30+#include <boost/asio/ip/tcp.hpp>
31+#include <boost/format.hpp>
32+#include "protocol_module_simple.h"
33+#include "utility.h"
34+
35+namespace l7vs
36+{
37+const std::string protocol_module_simple::MODULE_NAME = "simple";
38+const int protocol_module_simple::THREAD_DIVISION_UP_STREAM = 0;
39+const int protocol_module_simple::THREAD_DIVISION_DOWN_STREAM = 1;
40+
41+const int protocol_module_simple::END_FLAG_OFF = 0;
42+const int protocol_module_simple::END_FLAG_ON = 1;
43+
44+const int protocol_module_simple::ACCEPT_END_FLAG_OFF = 0;
45+const int protocol_module_simple::ACCEPT_END_FLAG_ON = 1;
46+
47+const int protocol_module_simple::SORRY_FLAG_ON = 1;
48+const int protocol_module_simple::SORRY_FLAG_OFF = 0;
49+
50+const int protocol_module_simple::SORRYSERVER_SWITCH_FLAG_OFF = 0;
51+const int protocol_module_simple::SORRYSERVER_SWITCH_FLAG_ON = 1;
52+
53+const int protocol_module_simple::REALSERVER_SWITCH_FLAG_OFF = 0;
54+const int protocol_module_simple::REALSERVER_SWITCH_FLAG_ON = 1;
55+
56+const int protocol_module_simple::EDIT_DIVISION_NO_EDIT = 0;
57+const int protocol_module_simple::EDIT_DIVISION_EDIT = 1;
58+
59+const int protocol_module_simple::FORWARDED_FOR_OFF = 0;
60+const int protocol_module_simple::FORWARDED_FOR_ON = 1;
61+
62+const int protocol_module_simple::COLLECT_STATS_OFF = 0;
63+const int protocol_module_simple::COLLECT_STATS_ON = 1;
64+
65+//! constructor
66+protocol_module_simple::protocol_module_simple() :
67+ http_protocol_module_base(MODULE_NAME), forwarded_for(FORWARDED_FOR_OFF)
68+{
69+ sorry_uri.assign('\0');
70+ sorry_uri[0] = '/';
71+}
72+//! destructor
73+protocol_module_simple::~protocol_module_simple()
74+{
75+}
76+//! tcp protocol support check
77+//! @return tcp support is true
78+//! @return tcp not-support is false
79+bool protocol_module_simple::is_tcp()
80+{
81+ return true;
82+}
83+
84+//! udp protocol support check
85+//! @return udp support is true
86+//! @return udp not-support is false
87+bool protocol_module_simple::is_udp()
88+{
89+ return false;
90+}
91+
92+//! replication interval interrupt
93+//! timer thread call this function. from virtualservice.
94+void protocol_module_simple::replication_interrupt()
95+{
96+}
97+//! initialize function. called from module control. module loaded call
98+//! @param[in] realserver list iterator begin function object type
99+//! @param[in] realserver list iterator end function object type
100+//! @param[in] realserver list iterator next function object type
101+//! @param[in] realserver list mutex lock function object type.
102+//! @param[in] realserver list mutex unlock function object type
103+void protocol_module_simple::initialize(rs_list_itr_func_type inlist_begin,
104+ rs_list_itr_func_type inlist_end,
105+ rs_list_itr_next_func_type inlist_next,
106+ boost::function< void(void) > inlist_lock,
107+ boost::function< void(void) > inlist_unlock)
108+{
109+ //RealServer list begin function
110+ rs_list_begin = inlist_begin;
111+ //RealServer list end function
112+ rs_list_end = inlist_end;
113+ //RealServer list next function
114+ rs_list_next = inlist_next;
115+ //RealServer list lock function
116+ rs_list_lock = inlist_lock;
117+ //RealServer list unlock function
118+ rs_list_unlock = inlist_unlock;
119+}
120+
121+//! finalize called from module control. module unloaded call.
122+void protocol_module_simple::finalize()
123+{
124+ //RealServer list functions initialization
125+ //RealServer list begin function
126+ rs_list_begin.clear();
127+ //RealServer list end function
128+ rs_list_end.clear();
129+ //RealServer list next function
130+ rs_list_next.clear();
131+ //RealServer list lock function
132+ rs_list_lock.clear();
133+ //RealServer list unlock function
134+ rs_list_unlock.clear();
135+
136+ //Replication functions initialization
137+ //component memory allocate function
138+ replication_pay_memory.clear();
139+ //component memory lock function
140+ replication_area_lock.clear();
141+ //component memory unlock function
142+ replication_area_unlock.clear();
143+
144+ //ScheduleModule's functions initialization
145+ schedule_tcp.clear();
146+
147+ //logger functions initialization
148+ //log level getting function
149+ getloglevel.clear();
150+ //logger(Fatal)
151+ putLogFatal.clear();
152+ //logger(Error)
153+ putLogError.clear();
154+ //logger(Warn)
155+ putLogWarn.clear();
156+ //logger(Info)
157+ putLogInfo.clear();
158+ //logger(Debug)
159+ putLogDebug.clear();
160+}
161+
162+//! sorry support check
163+//! @return true sorry mode is supported.
164+//! @return false sorry mode is unsupported.
165+bool protocol_module_simple::is_use_sorry()
166+{
167+ return true;
168+}
169+
170+//! realserver list update event
171+void protocol_module_simple::handle_rslist_update()
172+{
173+}
174+
175+//! module parameter check.used by l7vsadm
176+//! @param[in] module parameter string list
177+//! @return result.flag true is parameter is no problem.
178+//! @return result.flag false is parameter is problem.
179+protocol_module_base::check_message_result protocol_module_simple::check_parameter(const std::vector <
180+ std::string > & args)
181+{
182+ using namespace boost::xpressive;
183+ //set check result true
184+ check_message_result check_result;
185+ check_result.flag = true;
186+
187+ typedef std::vector<std::string>::const_iterator vec_str_it;
188+
189+ try {
190+ vec_str_it it = args.begin();
191+ vec_str_it it_end = args.end();
192+ //loop option strings
193+ for (; it != it_end; ++it) {
194+ //set check result flag false
195+ check_result.flag = false;
196+ //set check result message
197+ check_result.message = "Option error.";
198+ putLogError(100005, check_result.message, __FILE__, __LINE__);
199+ //loop break
200+ break;
201+ }
202+ } catch (...) {
203+ check_result.flag = false;
204+ }
205+
206+ return check_result;
207+}
208+
209+//! parameter set
210+//! @param[in] module parameter string list
211+//! @return result.flag true is parameter is no problem.
212+//! @return result.flag false is parameter is problem.
213+protocol_module_base::check_message_result protocol_module_simple::set_parameter(const std::vector <
214+ std::string > & args)
215+{
216+ using namespace boost::xpressive;
217+ //set check result flag true
218+ check_message_result check_result;
219+ check_result.flag = true;
220+
221+ typedef std::vector<std::string>::const_iterator vec_str_it;
222+
223+ try {
224+ vec_str_it it = args.begin();
225+ vec_str_it it_end = args.end();
226+ for (; it != it_end; ++it) {
227+ //set check result flag false
228+ check_result.flag = false;
229+ //set check result message
230+ check_result.message = "Option error.";
231+
232+ putLogError(100013, check_result.message, __FILE__,
233+ __LINE__);
234+
235+ break;
236+ }
237+ } catch (...) {
238+ check_result.flag = false;
239+ }
240+
241+ return check_result;
242+}
243+
244+//! parameter add
245+//! @param[in] module parameter string list
246+//! @return result.flag true is parameter is no problem.
247+//! @return result.flag false is parameter is problem.
248+protocol_module_base::check_message_result protocol_module_simple::add_parameter(const std::vector <
249+ std::string > & args)
250+{
251+ check_message_result check_result;
252+ //set check result flag true
253+ check_result.flag = true;
254+
255+ //param list is not empty
256+ if (!args.empty()) {
257+ //set check result flag false
258+ check_result.flag = false;
259+ //set check result message
260+ check_result.message = "Cannot add option.";
261+ putLogError(100016, check_result.message, __FILE__, __LINE__);
262+ }
263+
264+ return check_result;
265+}
266+
267+//! get option info
268+//! @param[out] module parameter string
269+void protocol_module_simple::get_option_info(std::string &option)
270+{
271+}
272+
273+//! TCP/IP scheduled function registration.
274+//! @param[in] schedule module TCP/IP scheduled function object type
275+void protocol_module_simple::register_schedule(tcp_schedule_func_type inschedule)
276+{
277+ schedule_tcp = inschedule;
278+}
279+
280+//! UDP scheduled function registration
281+//! @param[in] schedule module UDP scheduled function object type
282+void protocol_module_simple::register_schedule(udp_schedule_func_type inschedule)
283+{
284+}
285+
286+//! called from session initialize use in upstream_thread
287+//! @param[in] upstream thread id.
288+//! @param[in] downstream thread id
289+//! @return session use EVENT mode.
290+protocol_module_base::EVENT_TAG protocol_module_simple::handle_session_initialize(
291+ const boost::thread::id up_thread_id, const boost::thread::id down_thread_id,
292+ const boost::asio::ip::tcp::endpoint &client_endpoint_tcp,
293+ const boost::asio::ip::udp::endpoint &client_endpoint_udp)
294+{
295+ EVENT_TAG status = FINALIZE;
296+
297+ //session thread initialization
298+ try {
299+ thread_data_ptr p_up(new session_thread_data_simple);
300+ p_up->thread_id = up_thread_id;
301+ p_up->thread_division = THREAD_DIVISION_UP_STREAM;
302+ p_up->pair_thread_id = down_thread_id;
303+ p_up->accept_end_flag = ACCEPT_END_FLAG_OFF;
304+ p_up->end_flag = END_FLAG_OFF;
305+ p_up->sorry_flag = SORRY_FLAG_OFF;
306+ p_up->sorryserver_switch_flag = SORRYSERVER_SWITCH_FLAG_OFF;
307+ p_up->realserver_switch_flag = REALSERVER_SWITCH_FLAG_OFF;
308+ p_up->last_status = INITIALIZE;
309+ p_up->client_endpoint_tcp = client_endpoint_tcp;
310+
311+ receive_data recv_data;
312+ p_up->receive_data_map[client_endpoint_tcp] = recv_data;
313+
314+ thread_data_ptr p_down(new session_thread_data_simple);
315+ p_down->thread_id = down_thread_id;
316+ p_down->thread_division = THREAD_DIVISION_DOWN_STREAM;
317+ p_down->pair_thread_id = up_thread_id;
318+ p_down->accept_end_flag = ACCEPT_END_FLAG_OFF;
319+ p_down->end_flag = END_FLAG_OFF;
320+ p_down->sorry_flag = SORRY_FLAG_OFF;
321+ p_down->sorryserver_switch_flag = SORRYSERVER_SWITCH_FLAG_OFF;
322+ p_down->realserver_switch_flag = REALSERVER_SWITCH_FLAG_OFF;
323+ p_down->last_status = INITIALIZE;
324+ p_down->client_endpoint_tcp = client_endpoint_tcp;
325+
326+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
327+
328+ session_thread_data_map[up_thread_id] = p_up;
329+ session_thread_data_map[down_thread_id] = p_down;
330+
331+ status = ACCEPT;
332+ } catch (...) {
333+ status = FINALIZE;
334+ }
335+
336+ return status;
337+}
338+//! called from session finalize use in upstream thread.
339+//! @param[in] upstream thread id.
340+//! @param[in] downstream thread id
341+//! @return session use EVENT mode.
342+protocol_module_base::EVENT_TAG protocol_module_simple::handle_session_finalize(
343+ const boost::thread::id up_thread_id, const boost::thread::id down_thread_id)
344+{
345+ EVENT_TAG status = STOP;
346+
347+ //session thread free
348+ try {
349+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
350+
351+ session_thread_data_map_it session_thread_data_it = session_thread_data_map.find(up_thread_id);
352+ if (session_thread_data_it != session_thread_data_map.end()) {
353+ thread_data_ptr p_up = session_thread_data_it->second;
354+ session_thread_data_map.erase(up_thread_id);
355+ }
356+
357+ session_thread_data_it = session_thread_data_map.find(down_thread_id);
358+ if (session_thread_data_it != session_thread_data_map.end()) {
359+ thread_data_ptr p_down = session_thread_data_it->second;
360+ session_thread_data_map.erase(down_thread_id);
361+ }
362+
363+ status = STOP;
364+ } catch (...) {
365+ status = STOP;
366+ }
367+
368+ return status;
369+}
370+
371+//! called from after session accept.in client socket use in upstream thread.
372+//! @param[in] upstream thread id.
373+//! @return session use EVENT mode.
374+protocol_module_base::EVENT_TAG protocol_module_simple::handle_accept(const boost::thread::id thread_id)
375+{
376+ EVENT_TAG status = FINALIZE;
377+ thread_data_ptr session_data;
378+ session_thread_data_map_it session_thread_it;
379+
380+ try {
381+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
382+
383+ session_thread_it = session_thread_data_map.find(thread_id);
384+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
385+ boost::format formatter("Invalid thread id. thread id : %d.");
386+ formatter % boost::this_thread::get_id();
387+ putLogError(100022, formatter.str(), __FILE__, __LINE__);
388+ throw - 1;
389+ }
390+
391+ session_data = session_thread_it->second;
392+
393+ //set accept end flag ON
394+ session_data->accept_end_flag = ACCEPT_END_FLAG_ON;
395+
396+ //sorry flag on
397+ if (session_data->sorry_flag == SORRY_FLAG_ON) {
398+ //set return status
399+ status = SORRYSERVER_SELECT;
400+ }
401+ //sorry flag off
402+ else {
403+ //set return status
404+ status = REALSERVER_SELECT;
405+ }
406+ } catch (...) {
407+ status = FINALIZE;
408+ }
409+
410+ return status;
411+}
412+
413+//! called from after session recv in client socket. use in upstream thread.
414+//! @param[in] upstream thread id
415+//! @param[in] receive buffer reference.
416+//! @param[in] receive length
417+//! @return session use EVENT mode.
418+protocol_module_base::EVENT_TAG protocol_module_simple::handle_client_recv(const boost::thread::id thread_id,
419+ const boost::array<char, MAX_BUFFER_SIZE>& recvbuffer, const size_t recvlen)
420+{
421+ EVENT_TAG status = FINALIZE;
422+ size_t data_remain_start = 0;
423+ size_t data_remain_size = 0;
424+ size_t request_data_remain_size = 0;
425+ size_t buffer_size = 0;
426+ std::string str_value;
427+ thread_data_ptr session_data;
428+ char *buffer1 = NULL;
429+ char *buffer2 = NULL;
430+ session_thread_data_map_it session_thread_it;
431+ receive_data_map_it receive_data_it;
432+
433+ // hibari add for debug
434+ boost::format formatter("handle_client_recv() => recvbuffer = %s");
435+ formatter % recvbuffer.data() ;
436+ putLogFatal(9999, formatter.str(), __FILE__, __LINE__);
437+ // hibari add end
438+
439+
440+ //parameter check
441+ if (recvlen > recvbuffer.size()) {
442+ std::cerr << "protocol_module_simple::handle_client_recv() : Data size bigger than buffer size." << std::endl;
443+ boost::format formatter("Data size bigger than buffer size. thread id : %d.");
444+ formatter % boost::this_thread::get_id();
445+ putLogError(100025, formatter.str(), __FILE__, __LINE__);
446+ return FINALIZE;
447+ }
448+
449+ try {
450+ {
451+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
452+
453+ session_thread_it = session_thread_data_map.find(thread_id);
454+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
455+ boost::format formatter("Invalid thread id. thread id : %d.");
456+ formatter % boost::this_thread::get_id();
457+ putLogError(100026, formatter.str(), __FILE__, __LINE__);
458+ throw - 1;
459+ }
460+
461+ session_data = session_thread_it->second;
462+ }
463+
464+ //end flag on
465+ if (session_data->end_flag == END_FLAG_ON) {
466+ status = CLIENT_RECV;
467+ }
468+ //end flag off
469+ else {
470+ receive_data_it = session_data->receive_data_map.find(session_data->client_endpoint_tcp);
471+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
472+ boost::format formatter("Invalid endpoint. thread id : %d.");
473+ formatter % boost::this_thread::get_id();
474+ putLogError(100027, formatter.str(), __FILE__, __LINE__);
475+ throw - 1;
476+ }
477+
478+ receive_data &recv_data = receive_data_it->second;
479+
480+ send_status_it it = recv_data.send_status_list.begin();
481+ send_status_it it_end = recv_data.send_status_list.end();
482+
483+ //status list check
484+ it = std::find_if(it, it_end, data_send_ok());
485+ if (unlikely(it != it_end)) {
486+ boost::format formatter("Sending data is not correct. thread id : %d.");
487+ formatter % boost::this_thread::get_id();
488+ putLogError(100028, formatter.str(), __FILE__, __LINE__);
489+ throw - 1;
490+ }
491+
492+ //status list check
493+ it = recv_data.send_status_list.begin();
494+ it = std::adjacent_find(it, it_end, data_send_repeated());
495+ if (unlikely(it != it_end)) {
496+ boost::format formatter("Sending data is not correct. thread id : %d.");
497+ formatter % boost::this_thread::get_id();
498+ putLogError(100029, formatter.str(), __FILE__, __LINE__);
499+ throw - 1;
500+ }
501+
502+ it = recv_data.send_status_list.begin();
503+ //get original status info
504+ while (it != it_end) {
505+ //item status is SEND_END
506+ if (it->status == SEND_END) {
507+ //erase from list
508+ recv_data.send_status_list.erase(it++);
509+ continue;
510+ }
511+ //item status is SEND_CONTINUE
512+ else if (it->status == SEND_CONTINUE) {
513+ it->send_offset += it->send_end_size;
514+ data_remain_start = it->send_offset;
515+ break;
516+ }
517+ //item status is SEND_NG
518+ else {
519+ data_remain_start = it->send_offset;
520+ data_remain_size = it->unsend_size;
521+ break;
522+ }
523+
524+ ++it;
525+ }
526+
527+ //receive buffer process
528+ //buffer rest size < request size
529+ if (recv_data.receive_buffer_rest_size < recvlen) {
530+ //buffer max size < remain size + request size
531+ //buffer is need reallocate
532+ if (recv_data.receive_buffer_max_size < data_remain_size + recvlen) {
533+ //the buffer's size that will be allocated is exceed the upper limit value
534+ if (MAX_SIMPLE_MODULE_BUFFER_SIZE < data_remain_size + recvlen) {
535+ std::cerr << "protocol_module_simple::handle_client_recv() : the buffer's size that will be allocated is exceed the upper limit value." << std::endl;
536+ boost::format formatter("The buffer's size that will be allocated is exceed the upper limit value. thread id : %d.");
537+ formatter % boost::this_thread::get_id();
538+ putLogError(100030, formatter.str(), __FILE__, __LINE__);
539+ return FINALIZE;
540+ }
541+
542+ buffer_size = (data_remain_size + recvlen) > MAX_BUFFER_SIZE ? (data_remain_size + recvlen) : MAX_BUFFER_SIZE;
543+ //receive_buffer1's memory allocate and initialization
544+ buffer1 = new char[buffer_size];
545+ memset(buffer1, 0, buffer_size);
546+ //receive_buffer2's memory allocate and initialization
547+ buffer2 = new char[buffer_size];
548+ memset(buffer2, 0, buffer_size);
549+
550+ //copy data from old buffer to new buffer
551+ memcpy(buffer1, recv_data.receive_buffer + data_remain_start, data_remain_size);
552+ memcpy(buffer1 + data_remain_size, recvbuffer.data(), recvlen);
553+ //free old buffer1 and old buffer2
554+ if (recv_data.receive_buffer1 != NULL) {
555+ delete[] recv_data.receive_buffer1;
556+ recv_data.receive_buffer1 = NULL;
557+ }
558+
559+ if (recv_data.receive_buffer2 != NULL) {
560+ delete[] recv_data.receive_buffer2;
561+ recv_data.receive_buffer2 = NULL;
562+ }
563+
564+ //set new buffer pointer
565+ recv_data.receive_buffer1 = buffer1;
566+ recv_data.receive_buffer2 = buffer2;
567+ recv_data.receive_buffer = recv_data.receive_buffer1;
568+ //set new buffer's max size
569+ recv_data.receive_buffer_max_size = buffer_size;
570+ }
571+ //buffer's max size >= remain data size + request size
572+ //buffer isn't need reallocate, but switch
573+ else {
574+ //pointer valid check
575+ if (unlikely(recv_data.receive_buffer1 == NULL || recv_data.receive_buffer2 == NULL)) {
576+ boost::format formatter("Invalid pointer. thread id : %d.");
577+ formatter % boost::this_thread::get_id();
578+ putLogError(100031, formatter.str(), __FILE__, __LINE__);
579+ throw - 1;
580+ }
581+ //using buffer is buffer1
582+ if (recv_data.receive_buffer == recv_data.receive_buffer1) {
583+ //buffer2 initialization
584+ memset(recv_data.receive_buffer2, 0, recv_data.receive_buffer_max_size);
585+ //copy data from buffer1 to buffer2
586+ memcpy(recv_data.receive_buffer2, recv_data.receive_buffer + data_remain_start, data_remain_size);
587+ memcpy(recv_data.receive_buffer2 + data_remain_size, recvbuffer.data(), recvlen);
588+ //set buffer2 as using buffer
589+ recv_data.receive_buffer = recv_data.receive_buffer2;
590+ }
591+ //using buffer is buffer2
592+ else {
593+ //buffer1 initialization
594+ memset(recv_data.receive_buffer1, 0, recv_data.receive_buffer_max_size);
595+ //copy data from buffer2 to buffer1
596+ memcpy(recv_data.receive_buffer1, recv_data.receive_buffer + data_remain_start, data_remain_size);
597+ memcpy(recv_data.receive_buffer1 + data_remain_size, recvbuffer.data(), recvlen);
598+ //set buffer1 as using buffer
599+ recv_data.receive_buffer = recv_data.receive_buffer1;
600+ }
601+ }
602+
603+ //set buffer's rest size
604+ recv_data.receive_buffer_rest_size = recv_data.receive_buffer_max_size - data_remain_size - recvlen;
605+
606+ //remain_size recalc
607+ data_remain_size += recvlen;
608+
609+ send_status_it it_begin = recv_data.send_status_list.begin();
610+ send_status_it it_end = recv_data.send_status_list.end();
611+
612+ //offset recalc
613+ for (; it_begin != it_end; ++it_begin) {
614+ it_begin->send_offset -= data_remain_start;
615+ }
616+ }
617+ //buffer's rest size >= request size
618+ else {
619+ //pointer valid check
620+ if (unlikely(recv_data.receive_buffer == NULL)) {
621+ boost::format formatter("Invalid pointer. thread id : %d.");
622+ formatter % boost::this_thread::get_id();
623+ putLogError(100032, formatter.str(), __FILE__, __LINE__);
624+ throw - 1;
625+ }
626+ //copy data from parameter to using buffer
627+ memcpy(recv_data.receive_buffer + recv_data.receive_buffer_max_size - recv_data.receive_buffer_rest_size,
628+ recvbuffer.data(), recvlen);
629+ //buffer's rest size recalc
630+ recv_data.receive_buffer_rest_size -= recvlen;
631+ //remain data size recalc
632+ data_remain_size += recvlen;
633+ }
634+
635+ it = recv_data.send_status_list.begin();
636+ it_end = recv_data.send_status_list.end();
637+
638+ //set request rest size
639+ request_data_remain_size = recvlen;
640+
641+ //original status process
642+ for (; it != it_end; ++it) {
643+ //status is SEND_CONTINUE
644+ if (it->status == SEND_CONTINUE) {
645+ //send rest size > request size
646+ if (it->send_rest_size > request_data_remain_size) {
647+ //send possible size recalc
648+ it->send_possible_size = request_data_remain_size;
649+ //send rest size recalc
650+ it->send_rest_size -= request_data_remain_size;
651+ //send end size recalc
652+ it->send_end_size = 0;
653+ //request size recalc
654+ request_data_remain_size = 0;
655+ }
656+ //send rest size <= request size
657+ else {
658+ //send possible size recalc
659+ it->send_possible_size = it->send_rest_size;
660+ //send rest size recalc
661+ request_data_remain_size -= it->send_rest_size;
662+ //send end size recalc
663+ it->send_end_size = 0;
664+ //request size recalc
665+ it->send_rest_size = 0;
666+ }
667+ //set edit_division flag off
668+ it->edit_division = EDIT_DIVISION_NO_EDIT;
669+ //set status SEND_OK
670+ it->status = SEND_OK;
671+ }
672+ //status is SEND_NG
673+ else if (it->status == SEND_NG) {
674+ //set edit_division flag off
675+ it->edit_division = EDIT_DIVISION_NO_EDIT;
676+ //send_rest_size recalc
677+ it->send_rest_size = it->unsend_size + request_data_remain_size;
678+
679+ //recalc fields value according to send_rest_size and request rest size
680+ if (it->send_rest_size > it->unsend_size + request_data_remain_size) {
681+ it->send_possible_size = it->unsend_size + request_data_remain_size;
682+ it->send_rest_size -= (it->unsend_size + request_data_remain_size);
683+ it->send_end_size = 0;
684+ it->unsend_size = 0;
685+ request_data_remain_size = 0;
686+ } else {
687+ it->send_possible_size = it->send_rest_size;
688+ request_data_remain_size = it->unsend_size + request_data_remain_size - it->send_rest_size;
689+ it->send_end_size = 0;
690+ it->unsend_size = 0;
691+ it->send_rest_size = 0;
692+ }
693+
694+ //change status from SEND_NG to SEND_OK
695+ it->status = SEND_OK;
696+ }
697+ //no request rest data to process
698+ if (request_data_remain_size <= 0) {
699+ break;
700+ }
701+ }
702+ //there are still rest data need to process
703+ //new status created and add to status list
704+ while (request_data_remain_size > 0) {
705+ //new status created
706+ send_status new_send_state;
707+
708+ new_send_state.edit_division = EDIT_DIVISION_NO_EDIT;
709+ new_send_state.send_end_size = 0;
710+ new_send_state.send_offset = 0;
711+ new_send_state.send_possible_size = 0;
712+ new_send_state.unsend_size = 0;
713+ new_send_state.send_rest_size = 0;
714+ //status initialize to SEND_NG
715+ new_send_state.status = SEND_NG;
716+ //add new status to status_list
717+ recv_data.send_status_list.push_back(new_send_state);
718+ std::list<send_status>::reverse_iterator new_send_it = recv_data.send_status_list.rbegin();
719+ //calc offset
720+ new_send_it->send_offset = recv_data.receive_buffer_max_size - recv_data.receive_buffer_rest_size
721+ - request_data_remain_size;
722+
723+ new_send_it->edit_division = EDIT_DIVISION_NO_EDIT;
724+ new_send_it->send_rest_size = request_data_remain_size;
725+
726+ //recalc fields value according to send_rest_size and request rest size
727+ if (new_send_it->send_rest_size > request_data_remain_size) {
728+ new_send_it->send_possible_size = request_data_remain_size;
729+ new_send_it->send_rest_size -= request_data_remain_size;
730+ new_send_it->send_end_size = 0;
731+ request_data_remain_size = 0;
732+ } else {
733+ new_send_it->send_possible_size = new_send_it->send_rest_size;
734+ request_data_remain_size -= new_send_it->send_rest_size;
735+ new_send_it->send_end_size = 0;
736+ new_send_it->send_rest_size = 0;
737+ }
738+
739+ //change status from SEND_NG to SEND_OK
740+ new_send_it->status = SEND_OK;
741+ }
742+
743+ //search for send_possible item in status list
744+ send_status_it it_find = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(),
745+ data_send_possible());
746+ //the data that can be sent possible is exist
747+ if (it_find != recv_data.send_status_list.end()) {
748+ //sorry flag is on
749+ if (session_data->sorry_flag == SORRY_FLAG_ON) {
750+ status = SORRYSERVER_CONNECT;
751+ }
752+ //sorry flag is off
753+ else {
754+ status = REALSERVER_CONNECT;
755+ }
756+ }
757+ //the data that can be sent possible is not exist
758+ else {
759+ status = CLIENT_RECV;
760+ }
761+ }
762+ } catch (...) {
763+ status = FINALIZE;
764+ }
765+
766+ return status;
767+}
768+
769+//! called from after realserver select.use in upstream thread.
770+//! @param[in] upstream thread id
771+//! @param[out] realserver TCP endpoint
772+//! @return session use EVENT mode.
773+protocol_module_base::EVENT_TAG protocol_module_simple::handle_realserver_select(
774+ const boost::thread::id thread_id, boost::asio::ip::tcp::endpoint &rs_endpoint)
775+{
776+ EVENT_TAG status = FINALIZE;
777+ boost::asio::ip::tcp::endpoint tmp_endpoint;
778+ thread_data_ptr session_data;
779+ session_thread_data_map_it session_thread_it;
780+ session_thread_data_map_it session_thread_it_end;
781+ receive_data_map_it receive_data_it;
782+
783+ if (schedule_tcp.empty()) {
784+ std::cerr << "protocol_module_simple::handle_realserver_select() : Schedule_tcp function is empty." << std::endl;
785+ boost::format formatter("Schedule_tcp function is empty. thread id : %d.");
786+ formatter % boost::this_thread::get_id();
787+ putLogError(100037, formatter.str(), __FILE__, __LINE__);
788+ return FINALIZE;
789+ }
790+
791+ try {
792+ {
793+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
794+
795+ session_thread_it = session_thread_data_map.find(thread_id);
796+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
797+ boost::format formatter("Invalid thread id. thread id : %d.");
798+ formatter % boost::this_thread::get_id();
799+ putLogError(100038, formatter.str(), __FILE__, __LINE__);
800+ throw - 1;
801+ }
802+
803+ session_data = session_thread_it->second;
804+ }
805+
806+ //call schedule_module's schedule function, get realserver endpoint
807+ {
808+ rs_list_scoped_lock scoped_lock(rs_list_lock, rs_list_unlock);
809+ schedule_tcp(thread_id, rs_list_begin, rs_list_end, rs_list_next, rs_endpoint);
810+ }
811+
812+ //endpoint decide
813+ if (rs_endpoint != tmp_endpoint) {
814+ //save rs endpoint
815+ session_data->target_endpoint = rs_endpoint;
816+ status = REALSERVER_CONNECT;
817+ } else {
818+ //set end flag on
819+ session_data->sorry_flag = SORRY_FLAG_ON;
820+ status = SORRYSERVER_SELECT;
821+ }
822+ } catch (...) {
823+ status = FINALIZE;
824+ }
825+
826+ return status;
827+}
828+
829+//! called from after realserver select
830+//! @param[in] upstream thread id
831+//! @param[out] realserver UDP endpoint
832+//! @param[out] sendbuffer reference
833+//! @param[out] send data length
834+//! @return session use EVENT mode.
835+protocol_module_base::EVENT_TAG protocol_module_simple::handle_realserver_select(
836+ const boost::thread::id thread_id, boost::asio::ip::udp::endpoint &rs_endpoint, boost::array < char,
837+ MAX_BUFFER_SIZE > & sendbuffer, size_t &datalen)
838+{
839+ return STOP;
840+}
841+//! called from after realserver connect
842+//! @param[in] upstream thread id
843+//! @param[out] sendbuffer reference
844+//! @param[out] send data length
845+//! @return session use EVENT mode.
846+protocol_module_base::EVENT_TAG protocol_module_simple::handle_realserver_connect(
847+ const boost::thread::id thread_id, boost::array<char, MAX_BUFFER_SIZE>& sendbuffer, size_t &datalen)
848+{
849+ EVENT_TAG status = FINALIZE;
850+ size_t send_buffer_remian_size = 0;
851+ size_t copy_size = 0;
852+ const int send_buffer_end_size = sendbuffer.max_size();
853+ thread_data_ptr session_data;
854+
855+ try {
856+ session_thread_data_map_mutex.lock();
857+
858+ //thread id check
859+ session_thread_data_map_it session_thread_it = session_thread_data_map.find(thread_id);
860+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
861+ boost::format formatter("Invalid thread id. thread id : %d.");
862+ formatter % boost::this_thread::get_id();
863+ putLogError(100042, formatter.str(), __FILE__, __LINE__);
864+ session_thread_data_map_mutex.unlock();
865+ throw - 1;
866+ }
867+
868+ session_data = session_thread_it->second;
869+
870+ //endpoint check
871+ receive_data_map_it receive_data_it = session_data->receive_data_map.find(session_data->client_endpoint_tcp);
872+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
873+ boost::format formatter("Invalid endpoint. thread id : %d.");
874+ formatter % boost::this_thread::get_id();
875+ putLogError(100043, formatter.str(), __FILE__, __LINE__);
876+ session_thread_data_map_mutex.unlock();
877+ throw - 1;
878+ }
879+
880+ //receive_buffer pointer check
881+ receive_data &recv_data = receive_data_it->second;
882+ if (unlikely(recv_data.receive_buffer == NULL)) {
883+ session_thread_data_map_mutex.unlock();
884+ return CLIENT_RECV;
885+ }
886+
887+ //send list check
888+ send_status_it it = recv_data.send_status_list.begin();
889+ send_status_it it_end = recv_data.send_status_list.end();
890+ it = find_if(it, it_end, data_send_possible());
891+ if (unlikely(it == it_end)) {
892+ boost::format formatter("Sending possible data is not existed. thread id : %d.");
893+ formatter % boost::this_thread::get_id();
894+ putLogError(100045, formatter.str(), __FILE__, __LINE__);
895+ session_thread_data_map_mutex.unlock();
896+ throw - 1;
897+ }
898+ session_thread_data_map_mutex.unlock();
899+
900+ //send buffer rest size initialization
901+ send_buffer_remian_size = send_buffer_end_size;
902+
903+ //copy data as large as possible
904+ //send_possible_size is larger
905+ if (send_buffer_remian_size >= it->send_possible_size) {
906+ copy_size = it->send_possible_size;
907+ //copy data by send_possible size
908+ memcpy(sendbuffer.data(), recv_data.receive_buffer + it->send_offset, copy_size);
909+ it->send_end_size = copy_size;
910+ it->send_possible_size = 0;
911+ send_buffer_remian_size -= copy_size;
912+ }
913+ //buffer rest size is larger
914+ else {
915+ //copy data by buffer rest size
916+ memcpy(sendbuffer.data(), recv_data.receive_buffer + it->send_offset, send_buffer_remian_size);
917+ it->send_end_size = send_buffer_remian_size;
918+ it->send_possible_size -= send_buffer_remian_size;
919+ send_buffer_remian_size = 0;
920+ }
921+
922+ //set copied data length
923+ datalen = send_buffer_end_size - send_buffer_remian_size;
924+ status = REALSERVER_SEND;
925+ } catch (...) {
926+ status = FINALIZE;
927+ }
928+
929+ return status;
930+}
931+
932+//! called from after realserver connection fail
933+//! @param[in] upstream thread id
934+//! @param[in] fail realserver endpoint reference
935+//! @return session use EVENT mode.
936+protocol_module_base::EVENT_TAG protocol_module_simple::handle_realserver_connection_fail(
937+ const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &rs_endpoint)
938+{
939+ EVENT_TAG status = FINALIZE;
940+ thread_data_ptr session_data;
941+ session_thread_data_map_it session_thread_it;
942+
943+ try {
944+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
945+
946+ session_thread_it = session_thread_data_map.find(thread_id);
947+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
948+ boost::format formatter("Invalid thread id. thread id : %d.");
949+ formatter % boost::this_thread::get_id();
950+ putLogError(100049, formatter.str(), __FILE__, __LINE__);
951+ throw - 1;
952+ }
953+
954+ session_data = session_thread_it->second;
955+
956+ //set end flag ON
957+ session_data->end_flag = END_FLAG_ON;
958+ status = CLIENT_DISCONNECT;
959+ } catch (...) {
960+ status = FINALIZE;
961+ }
962+
963+ return status;
964+}
965+//! called from after realserver send.
966+//! @param[in] upstream thread id
967+//! @return session use EVENT mode.
968+protocol_module_base::EVENT_TAG protocol_module_simple::handle_realserver_send(
969+ const boost::thread::id thread_id)
970+{
971+ EVENT_TAG status = FINALIZE;
972+ thread_data_ptr session_data;
973+ session_thread_data_map_it session_thread_it;
974+ receive_data_map_it receive_data_it;
975+
976+ try {
977+ {
978+ boost::mutex::scoped_lock sclock(session_thread_data_map_mutex);
979+
980+ //thread_id check
981+ session_thread_it = session_thread_data_map.find(thread_id);
982+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
983+ boost::format formatter("Invalid thread id. thread id : %d.");
984+ formatter % boost::this_thread::get_id();
985+ putLogError(100052, formatter.str(), __FILE__, __LINE__);
986+ throw - 1;
987+ }
988+
989+ session_data = session_thread_it->second;
990+ }
991+
992+ //endpoint check
993+ receive_data_it = session_data->receive_data_map.find(session_data->client_endpoint_tcp);
994+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
995+ boost::format formatter("Invalid endpoint. thread id : %d.");
996+ formatter % boost::this_thread::get_id();
997+ putLogError(100053, formatter.str(), __FILE__, __LINE__);
998+ throw - 1;
999+ }
1000+
1001+ receive_data &recv_data = receive_data_it->second;
1002+
1003+ send_status_it it = recv_data.send_status_list.begin();
1004+ send_status_it it_end = recv_data.send_status_list.end();
1005+
1006+ //status list check
1007+ it = std::adjacent_find(it, it_end, data_send_list_incorrect());
1008+ if (unlikely(it != it_end)) {
1009+ boost::format formatter("Sending possible data is invalid. thread id : %d.");
1010+ formatter % boost::this_thread::get_id();
1011+ putLogError(100054, formatter.str(), __FILE__, __LINE__);
1012+ throw - 1;
1013+ }
1014+
1015+ //status list check
1016+ it = recv_data.send_status_list.begin();
1017+ it = std::find_if(it, it_end, data_send_ok());
1018+ if (unlikely(it == it_end)) {
1019+ boost::format formatter("Sending possible data is not existed. thread id : %d.");
1020+ formatter % boost::this_thread::get_id();
1021+ putLogError(100055, formatter.str(), __FILE__, __LINE__);
1022+ throw - 1;
1023+ }
1024+
1025+ //sending possible data is exist
1026+ if (it->send_possible_size > 0) {
1027+ //status remain SEND_OK
1028+ it->status = SEND_OK;
1029+ //offset recalc
1030+ it->send_offset += it->send_end_size;
1031+
1032+ //insert_position recalc
1033+ for (std::list<edit_data>::iterator list_it = it->edit_data_list.begin(); list_it
1034+ != it->edit_data_list.end(); ++list_it) {
1035+ list_it->insert_posission -= it->send_end_size;
1036+ }
1037+
1038+ //send_end_size recalc
1039+ it->send_end_size = 0;
1040+ }
1041+ //sending possible data is not exist
1042+ else {
1043+ //can receive from client continue
1044+ if (it->send_rest_size > 0) {
1045+ //change status from SEND_OK to SEND_CONTINUE
1046+ it->status = SEND_CONTINUE;
1047+ }
1048+ //can not receive from client continue
1049+ else {
1050+ //change status from SEND_OK to SEND_END
1051+ it->status = SEND_END;
1052+ }
1053+ }
1054+
1055+ it = recv_data.send_status_list.begin();
1056+ it = find_if(it, it_end, data_send_ok());
1057+ //send_ok item is exist
1058+ if (it != it_end) {
1059+ status = REALSERVER_CONNECT;
1060+ }
1061+ //send_ok item is exist
1062+ else {
1063+ status = CLIENT_RECV;
1064+ }
1065+ } catch (...) {
1066+ status = FINALIZE;
1067+ }
1068+
1069+ return status;
1070+}
1071+
1072+//! called from after sorryserver select
1073+//! @param[in] upstream thread id
1074+//! @param[in] sorryserver endpoint reference
1075+//! @return session use EVENT mode.
1076+protocol_module_base::EVENT_TAG protocol_module_simple::handle_sorryserver_select(
1077+ const boost::thread::id thread_id, boost::asio::ip::tcp::endpoint &sorry_endpoint)
1078+{
1079+ EVENT_TAG status = FINALIZE;
1080+ boost::asio::ip::tcp::endpoint client_endpoint;
1081+
1082+ thread_data_ptr session_data;
1083+ session_thread_data_map_it session_thread_it;
1084+ receive_data_map_it receive_data_it;
1085+
1086+ try {
1087+ boost::mutex::scoped_lock sclock(session_thread_data_map_mutex);
1088+
1089+ session_thread_it = session_thread_data_map.find(thread_id);
1090+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
1091+ boost::format formatter("Invalid thread id. thread id : %d.");
1092+ formatter % boost::this_thread::get_id();
1093+ putLogError(100058, formatter.str(), __FILE__, __LINE__);
1094+ throw - 1;
1095+ }
1096+
1097+ session_data = session_thread_it->second;
1098+ //set sorry_endpoint
1099+ session_data->target_endpoint = sorry_endpoint;
1100+
1101+ //endpoint check
1102+ receive_data_it = session_data->receive_data_map.find(session_data->client_endpoint_tcp);
1103+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
1104+ boost::format formatter("Invalid endpoint. thread id : %d.");
1105+ formatter % boost::this_thread::get_id();
1106+ putLogError(100059, formatter.str(), __FILE__, __LINE__);
1107+ throw - 1;
1108+ }
1109+
1110+ status = SORRYSERVER_CONNECT;
1111+ } catch (...) {
1112+ status = FINALIZE;
1113+ }
1114+
1115+ return status;
1116+}
1117+
1118+//! called from after sorryserver connect
1119+//! @param[in] upstream thread id
1120+//! @param[out] send buffer reference.
1121+//! @param[out] send length
1122+//! @return session use EVENT mode.
1123+protocol_module_base::EVENT_TAG protocol_module_simple::handle_sorryserver_connect(
1124+ const boost::thread::id thread_id, boost::array<char, MAX_BUFFER_SIZE>& sendbuffer, size_t &datalen)
1125+{
1126+ EVENT_TAG status = FINALIZE;
1127+ size_t send_buffer_remian_size = 0;
1128+ size_t copy_size = 0;
1129+ const int send_buffer_end_size = sendbuffer.max_size();
1130+ thread_data_ptr session_data;
1131+ session_thread_data_map_it session_thread_it;
1132+ receive_data_map_it receive_data_it;
1133+
1134+ try {
1135+ {
1136+ boost::mutex::scoped_lock sclock(session_thread_data_map_mutex);
1137+
1138+ //thread id check
1139+ session_thread_it = session_thread_data_map.find(thread_id);
1140+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
1141+ boost::format formatter("Invalid thread id. thread id : %d.");
1142+ formatter % boost::this_thread::get_id();
1143+ putLogError(100063, formatter.str(), __FILE__, __LINE__);
1144+ throw - 1;
1145+ }
1146+
1147+ session_data = session_thread_it->second;
1148+ }
1149+
1150+ //endpoint check
1151+ receive_data_it = session_data->receive_data_map.find(session_data->client_endpoint_tcp);
1152+ if (unlikely(receive_data_it
1153+ == session_data->receive_data_map.end())) {
1154+ boost::format formatter("Invalid endpoint. thread id : %d.");
1155+ formatter % boost::this_thread::get_id();
1156+ putLogError(100064, formatter.str(), __FILE__, __LINE__);
1157+ throw - 1;
1158+ }
1159+
1160+ //receive_buffer pointer check
1161+ receive_data &recv_data = receive_data_it->second;
1162+ if (unlikely(recv_data.receive_buffer == NULL)) {
1163+ status = CLIENT_RECV;
1164+ goto handle_sorryserver_connect_out;
1165+ }
1166+
1167+ //send list check
1168+ send_status_it it = recv_data.send_status_list.begin();
1169+ send_status_it it_end = recv_data.send_status_list.end();
1170+
1171+ it = find_if(it, it_end, data_send_possible());
1172+ if (unlikely(it == it_end)) {
1173+ boost::format formatter("Sending possible data is not existed. thread id : %d.");
1174+ formatter % boost::this_thread::get_id();
1175+ putLogError(100066, formatter.str(), __FILE__, __LINE__);
1176+ throw - 1;
1177+ }
1178+
1179+ //send buffer rest size initialization
1180+ send_buffer_remian_size = send_buffer_end_size;
1181+
1182+ //copy data as large as possible
1183+ //send_possible_size is larger
1184+ if (send_buffer_remian_size >= it->send_possible_size) {
1185+ copy_size = it->send_possible_size;
1186+ //copy data by send_possible size
1187+ memcpy(sendbuffer.data(), recv_data.receive_buffer
1188+ + it->send_offset, copy_size);
1189+ it->send_end_size = it->send_possible_size;
1190+ it->send_possible_size = 0;
1191+ send_buffer_remian_size -= copy_size;
1192+ }
1193+ //buffer rest size is larger
1194+ else {
1195+ //copy data by buffer rest size
1196+ memcpy(sendbuffer.data(), recv_data.receive_buffer
1197+ + it->send_offset, send_buffer_remian_size);
1198+ it->send_end_size = send_buffer_remian_size;
1199+ it->send_possible_size -= send_buffer_remian_size;
1200+ send_buffer_remian_size = 0;
1201+ }
1202+
1203+ //set copied data length
1204+ datalen = send_buffer_end_size - send_buffer_remian_size;
1205+
1206+ status = SORRYSERVER_SEND;
1207+ } catch (...) {
1208+ status = FINALIZE;
1209+ }
1210+
1211+handle_sorryserver_connect_out:
1212+ return status;
1213+}
1214+
1215+//! called from after sorryserver connection fail
1216+//! @param[in] upstream thread id
1217+//! @param[in] sorryserver endpoint reference.
1218+//! @return session use EVENT mode.
1219+protocol_module_base::EVENT_TAG protocol_module_simple::handle_sorryserver_connection_fail(
1220+ const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &sorry_endpoint)
1221+{
1222+ EVENT_TAG status = FINALIZE;
1223+ thread_data_ptr session_data;
1224+ session_thread_data_map_it session_thread_it;
1225+
1226+ try {
1227+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
1228+
1229+ session_thread_it = session_thread_data_map.find(thread_id);
1230+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
1231+ boost::format formatter("Invalid thread id. thread id : %d.");
1232+ formatter % boost::this_thread::get_id();
1233+ putLogError(100070, formatter.str(), __FILE__, __LINE__);
1234+ throw - 1;
1235+ }
1236+
1237+ session_data = session_thread_it->second;
1238+
1239+ //set end flag on
1240+ session_data->end_flag = END_FLAG_ON;
1241+
1242+ status = CLIENT_DISCONNECT;
1243+ } catch (...) {
1244+ status = FINALIZE;
1245+ }
1246+
1247+ return status;
1248+}
1249+
1250+//! called from after sorryserver send
1251+//! @param[in] upstream thread id
1252+//! @return session use EVENT mode.
1253+protocol_module_base::EVENT_TAG protocol_module_simple::handle_sorryserver_send(
1254+ const boost::thread::id thread_id)
1255+{
1256+ EVENT_TAG status = FINALIZE;
1257+ thread_data_ptr session_data;
1258+ session_thread_data_map_it session_thread_it;
1259+ receive_data_map_it receive_data_it;
1260+
1261+ try {
1262+ {
1263+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
1264+
1265+ //thread_id check
1266+ session_thread_it = session_thread_data_map.find(thread_id);
1267+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
1268+ boost::format formatter("Invalid thread id. thread id : %d.");
1269+ formatter % boost::this_thread::get_id();
1270+ putLogError(100073, formatter.str(), __FILE__, __LINE__);
1271+ throw - 1;
1272+ }
1273+
1274+ session_data = session_thread_it->second;
1275+ }
1276+
1277+ //endpoint check
1278+ receive_data_it = session_data->receive_data_map.find(session_data->client_endpoint_tcp);
1279+ if (unlikely(receive_data_it
1280+ == session_data->receive_data_map.end())) {
1281+ boost::format formatter("Invalid endpoint. thread id : %d.");
1282+ formatter % boost::this_thread::get_id();
1283+ putLogError(100074, formatter.str(), __FILE__, __LINE__);
1284+ throw - 1;
1285+ }
1286+
1287+ receive_data &recv_data = receive_data_it->second;
1288+
1289+ send_status_it it = recv_data.send_status_list.begin();
1290+ send_status_it it_end = recv_data.send_status_list.end();
1291+ //status list check
1292+ it = std::adjacent_find(it, it_end, data_send_list_incorrect());
1293+ if (unlikely(it != it_end)) {
1294+ boost::format formatter("Sending possible data is invalid. thread id : %d.");
1295+ formatter % boost::this_thread::get_id();
1296+ putLogError(100075, formatter.str(), __FILE__, __LINE__);
1297+ throw - 1;
1298+ }
1299+
1300+ //status list check
1301+ it = recv_data.send_status_list.begin();
1302+ it = find_if(it, it_end, data_send_ok());
1303+ if (unlikely(it == it_end)) {
1304+ boost::format formatter("Sending possible data is not existed. thread id : %d.");
1305+ formatter % boost::this_thread::get_id();
1306+ putLogError(100076, formatter.str(), __FILE__, __LINE__);
1307+ throw - 1;
1308+ }
1309+
1310+ //sending possible data is exist
1311+ if (it->send_possible_size > 0) {
1312+ //status remain SEND_OK
1313+ it->status = SEND_OK;
1314+ //offset recalc
1315+ it->send_offset += it->send_end_size;
1316+
1317+ //insert_position recalc
1318+ for (std::list<edit_data>::iterator list_it = it->edit_data_list.begin(); list_it
1319+ != it->edit_data_list.end(); ++list_it) {
1320+ list_it->insert_posission -= it->send_end_size;
1321+ }
1322+
1323+ //send_end_size recalc
1324+ it->send_end_size = 0;
1325+ }
1326+ //sending possible data is not exist
1327+ else {
1328+ //can receive from client continue
1329+ if (it->send_rest_size > 0) {
1330+ //change status from SEND_OK to SEND_CONTINUE
1331+ it->status = SEND_CONTINUE;
1332+ }
1333+ //can not receive from client continue
1334+ else {
1335+ //change status from SEND_OK to SEND_END
1336+ it->status = SEND_END;
1337+ }
1338+ }
1339+
1340+ it = recv_data.send_status_list.begin();
1341+ it = find_if(it, it_end, data_send_ok());
1342+ //send_ok item is exist
1343+ if (it != it_end) {
1344+ status = SORRYSERVER_CONNECT;
1345+ }
1346+ //send_ok item is exist
1347+ else {
1348+ status = CLIENT_RECV;
1349+ }
1350+ } catch (...) {
1351+ status = FINALIZE;
1352+ }
1353+
1354+ return status;
1355+}
1356+
1357+//! called from after realserver receive.for UDP
1358+//! @param[in] downstream thread id
1359+//! @param[in] realserver UDP endpoint reference
1360+//! @param[in] receive from realserver buffer reference
1361+//! @param[in] recv data length
1362+//! @return session use EVENT mode.
1363+protocol_module_base::EVENT_TAG protocol_module_simple::handle_realserver_recv(
1364+ const boost::thread::id thread_id, const boost::asio::ip::udp::endpoint &rs_endpoint, const boost::array < char,
1365+ MAX_BUFFER_SIZE > & recvbuffer, const size_t recvlen)
1366+{
1367+ return STOP;
1368+}
1369+
1370+//! called from after realserver receive for TCP/IP
1371+//! @param[in] downstream thread id
1372+//! @param[in] realserver TCP/IP endpoint reference
1373+//! @param[in] realserver receive buffer reference.
1374+//! @param[in] recv data length
1375+//! @return session use EVENT mode.
1376+protocol_module_base::EVENT_TAG protocol_module_simple::handle_realserver_recv(
1377+ const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &rs_endpoint, const boost::array < char,
1378+ MAX_BUFFER_SIZE > & recvbuffer, const size_t recvlen)
1379+{
1380+ EVENT_TAG status = FINALIZE;
1381+ size_t data_remain_start = 0;
1382+ size_t data_remain_size = 0;
1383+ size_t request_data_remain_size = 0;
1384+ size_t buffer_size = 0;
1385+ thread_data_ptr session_data;
1386+ char *buffer1 = NULL;
1387+ char *buffer2 = NULL;
1388+ std::string str_value;
1389+ session_thread_data_map_it session_thread_it;
1390+ receive_data_map_it receive_data_it;
1391+
1392+ //parameter check
1393+ if (recvlen > recvbuffer.size()) {
1394+ std::cerr << "protocol_module_simple::handle_realserver_recv() : Data size bigger than buffer size." << std::endl;
1395+ boost::format formatter("Data size bigger than buffer size. thread id : %d.");
1396+ formatter % boost::this_thread::get_id();
1397+ putLogError(100079, formatter.str(), __FILE__, __LINE__);
1398+ return FINALIZE;
1399+ }
1400+
1401+ try {
1402+ {
1403+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
1404+
1405+ session_thread_it = session_thread_data_map.find(thread_id);
1406+ if (unlikely(session_thread_it == session_thread_data_map.end()
1407+ || session_thread_it->second == NULL)) {
1408+ boost::format formatter("Invalid thread id. thread id : %d.");
1409+ formatter % boost::this_thread::get_id();
1410+ putLogError(100080, formatter.str(), __FILE__, __LINE__);
1411+ throw - 1;
1412+ }
1413+
1414+ session_data = session_thread_it->second;
1415+ }
1416+
1417+ receive_data_it = session_data->receive_data_map.find(rs_endpoint);
1418+ if (receive_data_it == session_data->receive_data_map.end()) {
1419+ receive_data recv_data;
1420+ session_data->receive_data_map[rs_endpoint] = recv_data;
1421+ }
1422+
1423+ session_data->target_endpoint = rs_endpoint;
1424+
1425+ receive_data &recv_data = session_data->receive_data_map[rs_endpoint];
1426+
1427+ send_status_it it = recv_data.send_status_list.begin();
1428+ send_status_it it_end = recv_data.send_status_list.end();
1429+
1430+ //status list check
1431+ it = std::find_if(it, it_end, data_send_ok());
1432+ if (unlikely(it != it_end)) {
1433+ boost::format formatter("Sending data is not correct. thread id : %d.");
1434+ formatter % boost::this_thread::get_id();
1435+ putLogError(100081, formatter.str(), __FILE__, __LINE__);
1436+ throw - 1;
1437+ }
1438+
1439+ //status list check
1440+ it = recv_data.send_status_list.begin();
1441+ it = std::adjacent_find(it, it_end, data_send_repeated());
1442+ if (unlikely(it != it_end)) {
1443+ boost::format formatter("Sending data is not correct. thread id : %d.");
1444+ formatter % boost::this_thread::get_id();
1445+ putLogError(100082, formatter.str(), __FILE__, __LINE__);
1446+ throw - 1;
1447+ }
1448+
1449+ it = recv_data.send_status_list.begin();
1450+ //get original status info
1451+ while (it != it_end) {
1452+ //item status is SEND_END
1453+ if (it->status == SEND_END) {
1454+ //erase from list
1455+ recv_data.send_status_list.erase(it++);
1456+ continue;
1457+ }
1458+ //item status is SEND_CONTINUE
1459+ else if (it->status == SEND_CONTINUE) {
1460+ it->send_offset += it->send_end_size;
1461+ data_remain_start = it->send_offset;
1462+ break;
1463+ }
1464+ //item status is SEND_NG
1465+ else {
1466+ data_remain_start = it->send_offset;
1467+ data_remain_size = it->unsend_size;
1468+ break;
1469+ }
1470+
1471+ ++it;
1472+ }
1473+ //receive buffer process
1474+ //buffer rest size < request size
1475+ if (recv_data.receive_buffer_rest_size < recvlen) {
1476+ //buffer max size < remain size + request size
1477+ //buffer is need reallocate
1478+ if (recv_data.receive_buffer_max_size < data_remain_size + recvlen) {
1479+ //the buffer's size that will be allocated is exceed the upper limit value
1480+ if (MAX_SIMPLE_MODULE_BUFFER_SIZE < data_remain_size + recvlen) {
1481+ std::cerr << "protocol_module_simple::handle_realserver_recv() : the buffer's size that will be allocated is exceed the upper limit value." << std::endl;
1482+ boost::format formatter("The buffer's size that will be allocated is exceed the upper limit value. thread id : %d.");
1483+ formatter % boost::this_thread::get_id();
1484+ putLogError(100083, formatter.str(), __FILE__, __LINE__);
1485+
1486+ return FINALIZE;
1487+ }
1488+ //receive_buffer1's memory allocate and initialization
1489+ buffer_size = (data_remain_size + recvlen) > MAX_BUFFER_SIZE ? (data_remain_size + recvlen) : MAX_BUFFER_SIZE;
1490+ buffer1 = new char[buffer_size];
1491+ memset(buffer1, 0, buffer_size);
1492+ //receive_buffer2's memory allocate and initialization
1493+ buffer2 = new char[buffer_size];
1494+ memset(buffer2, 0, buffer_size);
1495+
1496+ //copy data from old buffer to new buffer
1497+ memcpy(buffer1, recv_data.receive_buffer + data_remain_start, data_remain_size);
1498+ memcpy(buffer1 + data_remain_size, recvbuffer.data(), recvlen);
1499+ //free old buffer1 and old buffer2
1500+ if (recv_data.receive_buffer1 != NULL) {
1501+ delete[] recv_data.receive_buffer1;
1502+ recv_data.receive_buffer1 = NULL;
1503+ }
1504+
1505+ if (recv_data.receive_buffer2 != NULL) {
1506+ delete[] recv_data.receive_buffer2;
1507+ recv_data.receive_buffer2 = NULL;
1508+ }
1509+
1510+ //set new buffer pointer
1511+ recv_data.receive_buffer1 = buffer1;
1512+ recv_data.receive_buffer2 = buffer2;
1513+ recv_data.receive_buffer = recv_data.receive_buffer1;
1514+ //set new buffer's max size
1515+ recv_data.receive_buffer_max_size = buffer_size;
1516+ }
1517+ //buffer's max size >= remain data size + request size
1518+ //buffer isn't need reallocate, but switch
1519+ else {
1520+ //pointer valid check
1521+ if (unlikely(recv_data.receive_buffer1 == NULL || recv_data.receive_buffer2 == NULL)) {
1522+ boost::format formatter("Invalid pointer. thread id : %d.");
1523+ formatter % boost::this_thread::get_id();
1524+ putLogError(100084, formatter.str(), __FILE__, __LINE__);
1525+ throw - 1;
1526+ }
1527+ //using buffer is buffer1
1528+ if (recv_data.receive_buffer == recv_data.receive_buffer1) {
1529+ //buffer2 initialization
1530+ memset(recv_data.receive_buffer2, 0, recv_data.receive_buffer_max_size);
1531+ //copy data from buffer1 to buffer2
1532+ memcpy(recv_data.receive_buffer2, recv_data.receive_buffer + data_remain_start, data_remain_size);
1533+ memcpy(recv_data.receive_buffer2 + data_remain_size, recvbuffer.data(), recvlen);
1534+ //set buffer2 as using buffer
1535+ recv_data.receive_buffer = recv_data.receive_buffer2;
1536+ }
1537+ //using buffer is buffer2
1538+ else {
1539+ //buffer1 initialization
1540+ memset(recv_data.receive_buffer1, 0, recv_data.receive_buffer_max_size);
1541+ //copy data from buffer2 to buffer1
1542+ memcpy(recv_data.receive_buffer1, recv_data.receive_buffer + data_remain_start, data_remain_size);
1543+ memcpy(recv_data.receive_buffer1 + data_remain_size, recvbuffer.data(), recvlen);
1544+ //set buffer1 as using buffer
1545+ recv_data.receive_buffer = recv_data.receive_buffer1;
1546+ }
1547+ }
1548+
1549+ //set buffer's rest size
1550+ recv_data.receive_buffer_rest_size = recv_data.receive_buffer_max_size - data_remain_size - recvlen;
1551+
1552+ //remain_size recalc
1553+ data_remain_size += recvlen;
1554+
1555+ send_status_it it_begin = recv_data.send_status_list.begin();
1556+ send_status_it it_end = recv_data.send_status_list.end();
1557+ //offset recalc
1558+ for (; it_begin != it_end; ++it_begin) {
1559+ it_begin->send_offset -= data_remain_start;
1560+ }
1561+ }
1562+ //buffer's rest size >= request size
1563+ //copy directly
1564+ else {
1565+ //pointer valid check
1566+ if (unlikely(recv_data.receive_buffer == NULL)) {
1567+ boost::format formatter("Invalid pointer. thread id : %d.");
1568+ formatter % boost::this_thread::get_id();
1569+ putLogError(100085, formatter.str(), __FILE__, __LINE__);
1570+ throw - 1;
1571+ }
1572+
1573+ //copy data from parameter to using buffer
1574+ memcpy(recv_data.receive_buffer + recv_data.receive_buffer_max_size - recv_data.receive_buffer_rest_size,
1575+ recvbuffer.data(), recvlen);
1576+ //buffer's rest size recalc
1577+ recv_data.receive_buffer_rest_size -= recvlen;
1578+ //remain data size recalc
1579+ data_remain_size += recvlen;
1580+ }
1581+
1582+ it = recv_data.send_status_list.begin();
1583+ it_end = recv_data.send_status_list.end();
1584+ //request rest size initialization
1585+ request_data_remain_size = recvlen;
1586+ //original status process
1587+ for (; it != it_end; ++it) {
1588+ //status is SEND_CONTINUE
1589+ if (it->status == SEND_CONTINUE) {
1590+ //send rest size > request size
1591+ if (it->send_rest_size > request_data_remain_size) {
1592+ //send possible size recalc
1593+ it->send_possible_size = request_data_remain_size;
1594+ //send rest size recalc
1595+ it->send_rest_size -= request_data_remain_size;
1596+ //send end size recalc
1597+ it->send_end_size = 0;
1598+ //request size recalc
1599+ request_data_remain_size = 0;
1600+ }
1601+ //send rest size <= request size
1602+ else {
1603+ //send possible size recalc
1604+ it->send_possible_size = it->send_rest_size;
1605+ //send rest size recalc
1606+ request_data_remain_size -= it->send_rest_size;
1607+ //send end size recalc
1608+ it->send_end_size = 0;
1609+ //request size recalc
1610+ it->send_rest_size = 0;
1611+ }
1612+ //change status from SEND_CONTINUE to SEND_OK
1613+ it->status = SEND_OK;
1614+ }
1615+ //status is SEND_NG
1616+ else if (it->status == SEND_NG) {
1617+ //send_rest_size recalc
1618+ it->send_rest_size = it->unsend_size + request_data_remain_size;
1619+
1620+ //recalc fields value according to send_rest_size and request rest size
1621+ if (it->send_rest_size > it->unsend_size + request_data_remain_size) {
1622+ it->send_possible_size = it->unsend_size + request_data_remain_size;
1623+ it->send_rest_size -= (it->unsend_size + request_data_remain_size);
1624+ it->send_end_size = 0;
1625+ it->unsend_size = 0;
1626+ request_data_remain_size = 0;
1627+ } else {
1628+ it->send_possible_size = it->send_rest_size;
1629+ request_data_remain_size = it->unsend_size + request_data_remain_size - it->send_rest_size;
1630+ it->send_end_size = 0;
1631+ it->unsend_size = 0;
1632+ it->send_rest_size = 0;
1633+ }
1634+
1635+ //change status from SEND_NG to SEND_OK
1636+ it->status = SEND_OK;
1637+ }
1638+ //no request rest data to process
1639+ if (request_data_remain_size <= 0) {
1640+ break;
1641+ }
1642+ }
1643+
1644+ //there are still rest data need to process
1645+ //new status created and add to status list
1646+ while (request_data_remain_size > 0) {
1647+ //new status created
1648+ send_status new_send_state;
1649+ new_send_state.edit_division = EDIT_DIVISION_NO_EDIT;
1650+ new_send_state.send_end_size = 0;
1651+ new_send_state.send_offset = 0;
1652+ new_send_state.send_possible_size = 0;
1653+ new_send_state.unsend_size = 0;
1654+ new_send_state.send_rest_size = 0;
1655+ //status initialize to SEND_NG
1656+ new_send_state.status = SEND_NG;
1657+ //add new status to status_list
1658+ recv_data.send_status_list.push_back(new_send_state);
1659+ std::list<send_status>::reverse_iterator new_send_it = recv_data.send_status_list.rbegin();
1660+ //calc offset
1661+ new_send_it->send_offset = recv_data.receive_buffer_max_size - recv_data.receive_buffer_rest_size
1662+ - request_data_remain_size;
1663+
1664+ new_send_it->send_rest_size = request_data_remain_size;
1665+
1666+ //recalc fields value according to send_rest_size and request rest size
1667+ if (new_send_it->send_rest_size > request_data_remain_size) {
1668+ new_send_it->send_possible_size = request_data_remain_size;
1669+ new_send_it->send_rest_size -= request_data_remain_size;
1670+ new_send_it->send_end_size = 0;
1671+ new_send_it->send_end_size = 0;
1672+ request_data_remain_size = 0;
1673+ } else {
1674+ new_send_it->send_possible_size = new_send_it->send_rest_size;
1675+ request_data_remain_size -= new_send_it->send_rest_size;
1676+ new_send_it->send_end_size = 0;
1677+ new_send_it->send_rest_size = 0;
1678+ }
1679+
1680+ //change status from SEND_NG to SEND_OK
1681+ new_send_it->status = SEND_OK;
1682+ }
1683+
1684+ //search for send_possible item in status list
1685+ send_status_it it_find = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(),
1686+ data_send_possible());
1687+ //the data that can be sent possible is exist
1688+ if (it_find != recv_data.send_status_list.end()) {
1689+ status = CLIENT_CONNECTION_CHECK;
1690+ }
1691+ //the data that can be sent possible is not exist
1692+ else {
1693+ status = REALSERVER_RECV;
1694+ }
1695+ } catch (...) {
1696+ status = FINALIZE;
1697+ }
1698+
1699+ return status;
1700+}
1701+
1702+
1703+
1704+//! called from after sorryserver receive
1705+//! @param[in] downstream thread id
1706+//! @param[in] sorryserver endpoint reference
1707+//! @param[in] receive from realserver buffer reference.
1708+//! @param[in] recv data length
1709+//! @return session use EVENT mode
1710+protocol_module_base::EVENT_TAG protocol_module_simple::handle_sorryserver_recv(
1711+ const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &sorry_endpoint, const boost::array <
1712+ char, MAX_BUFFER_SIZE > & recvbuffer, const size_t recvlen)
1713+{
1714+ EVENT_TAG status = FINALIZE;
1715+ size_t data_remain_start = 0;
1716+ size_t data_remain_size = 0;
1717+ size_t request_data_remain_size = 0;
1718+ size_t buffer_size = 0;
1719+ thread_data_ptr session_data;
1720+ char *buffer1 = NULL;
1721+ char *buffer2 = NULL;
1722+ session_thread_data_map_it session_thread_it;
1723+ receive_data_map_it receive_data_it;
1724+
1725+ //parameter check
1726+ if (recvlen > recvbuffer.size()) {
1727+ std::cerr << "protocol_module_simple::handle_sorryserver_recv() : Data size bigger than buffer size." << std::endl;
1728+ boost::format formatter("Data size bigger than buffer size. thread id : %d.");
1729+ formatter % boost::this_thread::get_id();
1730+ putLogError(100090, formatter.str(), __FILE__,
1731+ __LINE__);
1732+ return FINALIZE;
1733+ }
1734+
1735+ try {
1736+ {
1737+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
1738+
1739+ session_thread_it = session_thread_data_map.find(thread_id);
1740+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
1741+ boost::format formatter("Invalid thread id. thread id : %d.");
1742+ formatter % boost::this_thread::get_id();
1743+ putLogError(100091, formatter.str(), __FILE__, __LINE__);
1744+ throw - 1;
1745+ }
1746+
1747+ session_data = session_thread_it->second;
1748+ }
1749+
1750+ receive_data_it = session_data->receive_data_map.find(sorry_endpoint);
1751+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
1752+ receive_data recv_data;
1753+ session_data->receive_data_map[sorry_endpoint] = recv_data;
1754+ }
1755+
1756+ session_data->target_endpoint = sorry_endpoint;
1757+
1758+ receive_data &recv_data = session_data->receive_data_map[sorry_endpoint];
1759+
1760+ //status list check
1761+ send_status_it it = recv_data.send_status_list.begin();
1762+ send_status_it it_end = recv_data.send_status_list.end();
1763+ it = std::find_if(it, it_end, data_send_ok());
1764+ if (unlikely(it != it_end)) {
1765+ boost::format formatter("Sending data is invalid. thread id : %d.");
1766+ formatter % boost::this_thread::get_id();
1767+ putLogError(100092, formatter.str(), __FILE__, __LINE__);
1768+ throw - 1;
1769+ }
1770+
1771+ //status list check
1772+ it = recv_data.send_status_list.begin();
1773+ it = std::adjacent_find(it, it_end, data_send_repeated());
1774+ if (unlikely(it != it_end)) {
1775+ boost::format formatter("Sending data is invalid. thread id : %d.");
1776+ formatter % boost::this_thread::get_id();
1777+ putLogError(100093, formatter.str(), __FILE__, __LINE__);
1778+ throw - 1;
1779+ }
1780+
1781+ it = recv_data.send_status_list.begin();
1782+ //get original status info
1783+ while (it != it_end) {
1784+ //item status is SEND_END
1785+ if (it->status == SEND_END) {
1786+ //erase from list
1787+ recv_data.send_status_list.erase(it++);
1788+ continue;
1789+ }
1790+ //item status is SEND_CONTINUE
1791+ else if (it->status == SEND_CONTINUE) {
1792+ it->send_offset += it->send_end_size;
1793+ data_remain_start = it->send_offset;
1794+ break;
1795+ }
1796+ //item status is SEND_NG
1797+ else {
1798+ data_remain_start = it->send_offset;
1799+ data_remain_size = it->unsend_size;
1800+ break;
1801+ }
1802+
1803+ ++it;
1804+ }
1805+ //receive buffer process
1806+ //buffer rest size < request size
1807+ if (recv_data.receive_buffer_rest_size < recvlen) {
1808+ //buffer max size < remain size + request size
1809+ //buffer is need reallocate
1810+ if (recv_data.receive_buffer_max_size < data_remain_size + recvlen) {
1811+ //the buffer's size that will be allocated is exceed the upper limit value
1812+ if (MAX_SIMPLE_MODULE_BUFFER_SIZE < data_remain_size + recvlen) {
1813+ std::cerr << "protocol_module_simple::handle_sorryserver_recv() : the buffer's size that will be allocated is exceed the upper limit value." << std::endl;
1814+ boost::format formatter("The buffer's size that will be allocated is exceed the upper limit value. thread id : %d.");
1815+ formatter % boost::this_thread::get_id();
1816+ putLogError(100094, formatter.str(), __FILE__, __LINE__);
1817+ return FINALIZE;
1818+ }
1819+ //receive_buffer1's memory allocate and initialization
1820+ buffer_size = (data_remain_size + recvlen) > MAX_BUFFER_SIZE ? (data_remain_size + recvlen) : MAX_BUFFER_SIZE;
1821+ buffer1 = new char[buffer_size];
1822+ memset(buffer1, 0, buffer_size);
1823+ //receive_buffer2's memory allocate and initialization
1824+ buffer2 = new char[buffer_size];
1825+ memset(buffer2, 0, buffer_size);
1826+
1827+ //copy data from old buffer to new buffer
1828+ memcpy(buffer1, recv_data.receive_buffer + data_remain_start, data_remain_size);
1829+ memcpy(buffer1 + data_remain_size, recvbuffer.data(), recvlen);
1830+ //free old buffer1 and old buffer2
1831+ if (recv_data.receive_buffer1 != NULL) {
1832+ delete[] recv_data.receive_buffer1;
1833+ recv_data.receive_buffer1 = NULL;
1834+ }
1835+
1836+ if (recv_data.receive_buffer2 != NULL) {
1837+ delete[] recv_data.receive_buffer2;
1838+ recv_data.receive_buffer2 = NULL;
1839+ }
1840+
1841+ //set new buffer pointer
1842+ recv_data.receive_buffer1 = buffer1;
1843+ recv_data.receive_buffer2 = buffer2;
1844+ recv_data.receive_buffer = recv_data.receive_buffer1;
1845+ //set new buffer's max size
1846+ recv_data.receive_buffer_max_size = buffer_size;
1847+ }
1848+ //buffer's max size >= remain data size + request size
1849+ //buffer isn't need reallocate, but switch
1850+ else {
1851+ //pointer valid check
1852+ if (unlikely(recv_data.receive_buffer1 == NULL || recv_data.receive_buffer2 == NULL)) {
1853+ boost::format formatter("Invalid pointer. thread id : %d.");
1854+ formatter % boost::this_thread::get_id();
1855+ putLogError(100095, formatter.str(), __FILE__, __LINE__);
1856+ throw - 1;
1857+ }
1858+ //using buffer is buffer1
1859+ if (recv_data.receive_buffer == recv_data.receive_buffer1) {
1860+ //buffer2 initialization
1861+ memset(recv_data.receive_buffer2, 0, recv_data.receive_buffer_max_size);
1862+ //copy data from buffer1 to buffer2
1863+ memcpy(recv_data.receive_buffer2, recv_data.receive_buffer + data_remain_start, data_remain_size);
1864+ memcpy(recv_data.receive_buffer2 + data_remain_size, recvbuffer.data(), recvlen);
1865+ //set buffer2 as using buffer
1866+ recv_data.receive_buffer = recv_data.receive_buffer2;
1867+ }
1868+ //using buffer is buffer2
1869+ else {
1870+ //buffer1 initialization
1871+ memset(recv_data.receive_buffer1, 0, recv_data.receive_buffer_max_size);
1872+ //copy data from buffer2 to buffer1
1873+ memcpy(recv_data.receive_buffer1, recv_data.receive_buffer + data_remain_start, data_remain_size);
1874+ memcpy(recv_data.receive_buffer1 + data_remain_size, recvbuffer.data(), recvlen);
1875+ //set buffer1 as using buffer
1876+ recv_data.receive_buffer = recv_data.receive_buffer1;
1877+ }
1878+ }
1879+
1880+ //set buffer's rest size
1881+ recv_data.receive_buffer_rest_size = recv_data.receive_buffer_max_size - data_remain_size - recvlen;
1882+
1883+ //remain_size recalc
1884+ data_remain_size += recvlen;
1885+
1886+ send_status_it it_begin = recv_data.send_status_list.begin();
1887+ send_status_it it_end = recv_data.send_status_list.end();
1888+ //offset recalc
1889+ for (; it_begin != it_end; ++it_begin) {
1890+ it_begin->send_offset -= data_remain_start;
1891+ }
1892+ }
1893+ //buffer's rest size >= request size
1894+ //copy directly
1895+ else {
1896+ //pointer valid check
1897+ if (unlikely(recv_data.receive_buffer == NULL)) {
1898+ boost::format formatter("Invalid pointer. thread id : %d");
1899+ formatter % boost::this_thread::get_id();
1900+ putLogError(100096, formatter.str(), __FILE__, __LINE__);
1901+ throw - 1;
1902+ }
1903+
1904+ //copy data from parameter to using buffer
1905+ memcpy(recv_data.receive_buffer + recv_data.receive_buffer_max_size - recv_data.receive_buffer_rest_size,
1906+ recvbuffer.data(), recvlen);
1907+ //buffer's rest size recalc
1908+ recv_data.receive_buffer_rest_size -= recvlen;
1909+ //remain data size recalc
1910+ data_remain_size += recvlen;
1911+ }
1912+
1913+ it = recv_data.send_status_list.begin();
1914+ it_end = recv_data.send_status_list.end();
1915+ //request rest size initialization
1916+ request_data_remain_size = recvlen;
1917+ //original status process
1918+ for (; it != it_end; ++it) {
1919+ //status is SEND_CONTINUE
1920+ if (it->status == SEND_CONTINUE) {
1921+ //
1922+ if (it->send_rest_size > request_data_remain_size) {
1923+ it->send_possible_size = request_data_remain_size;
1924+ it->send_rest_size -= request_data_remain_size;
1925+ it->send_end_size = 0;
1926+ request_data_remain_size = 0;
1927+ } else {
1928+ it->send_possible_size = it->send_rest_size;
1929+ request_data_remain_size -= it->send_rest_size;
1930+ it->send_end_size = 0;
1931+ it->send_rest_size = 0;
1932+ }
1933+
1934+ //change status from SEND_CONTINUE to SEND_OK
1935+ it->status = SEND_OK;
1936+ }
1937+ //status is SEND_NG
1938+ else if (it->status == SEND_NG) {
1939+ it->send_rest_size = it->unsend_size + request_data_remain_size;
1940+
1941+ //recalc fields value according to send_rest_size and request rest size
1942+ if (it->send_rest_size > it->unsend_size + request_data_remain_size) {
1943+ it->send_possible_size = it->unsend_size + request_data_remain_size;
1944+ it->send_rest_size -= (it->unsend_size + request_data_remain_size);
1945+ it->send_end_size = 0;
1946+ it->unsend_size = 0;
1947+ request_data_remain_size = 0;
1948+ } else {
1949+ it->send_possible_size = it->send_rest_size;
1950+ request_data_remain_size = it->unsend_size + request_data_remain_size - it->send_rest_size;
1951+ it->send_end_size = 0;
1952+ it->unsend_size = 0;
1953+ it->send_rest_size = 0;
1954+ }
1955+
1956+ //change status from SEND_NG to SEND_OK
1957+ it->status = SEND_OK;
1958+ }
1959+ //no request rest data to process
1960+ if (request_data_remain_size <= 0) {
1961+ break;
1962+ }
1963+ }
1964+
1965+ //there are still rest data need to process
1966+ //new status created and add to status list
1967+ while (request_data_remain_size > 0) {
1968+ //new status created
1969+ send_status new_send_state;
1970+ new_send_state.edit_division = EDIT_DIVISION_NO_EDIT;
1971+ new_send_state.send_end_size = 0;
1972+ new_send_state.send_offset = 0;
1973+ new_send_state.send_possible_size = 0;
1974+ new_send_state.unsend_size = 0;
1975+ new_send_state.send_rest_size = 0;
1976+ //status initialize to SEND_NG
1977+ new_send_state.status = SEND_NG;
1978+ //add new status to status_list
1979+ recv_data.send_status_list.push_back(new_send_state);
1980+ std::list<send_status>::reverse_iterator new_send_it = recv_data.send_status_list.rbegin();
1981+ //calc offset
1982+ new_send_it->send_offset = recv_data.receive_buffer_max_size - recv_data.receive_buffer_rest_size
1983+ - request_data_remain_size;
1984+
1985+ new_send_it->send_rest_size = request_data_remain_size;
1986+
1987+ //recalc fields value according to send_rest_size and request rest size
1988+ if (new_send_it->send_rest_size > request_data_remain_size) {
1989+ new_send_it->send_possible_size = request_data_remain_size;
1990+ new_send_it->send_rest_size -= request_data_remain_size;
1991+ new_send_it->send_end_size = 0;
1992+ request_data_remain_size = 0;
1993+ } else {
1994+ new_send_it->send_possible_size = new_send_it->send_rest_size;
1995+ request_data_remain_size -= new_send_it->send_rest_size;
1996+ new_send_it->send_end_size = 0;
1997+ new_send_it->send_rest_size = 0;
1998+ }
1999+
2000+ //change status from SEND_NG to SEND_OK
2001+ new_send_it->status = SEND_OK;
2002+ }
2003+
2004+ //search for send_possible item in status list
2005+ send_status_it it_find = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(),
2006+ data_send_possible());
2007+ //the data that can be sent possible is exist
2008+ if (it_find != recv_data.send_status_list.end()) {
2009+ status = CLIENT_CONNECTION_CHECK;
2010+ }
2011+ //the data that can be sent possible is not exist
2012+ else {
2013+ status = SORRYSERVER_RECV;
2014+ }
2015+ } catch (...) {
2016+ status = FINALIZE;
2017+ }
2018+
2019+ return status;
2020+}
2021+
2022+//! called from UPSTREAM thread. make module original message.
2023+//! @param[in] downstream thread id.
2024+//! @return session use EVENT mode
2025+protocol_module_base::EVENT_TAG protocol_module_simple::handle_response_send_inform(
2026+ const boost::thread::id thread_id)
2027+{
2028+ return STOP;
2029+}
2030+
2031+//! called from after client connection check. use TCP/IP only. create client send message.
2032+//! @param[in] downstream thread id
2033+//! @param[out] send buffer reference
2034+//! @param[out] send data length
2035+//! @return session use EVENT mode
2036+protocol_module_base::EVENT_TAG protocol_module_simple::handle_client_connection_check(
2037+ const boost::thread::id thread_id, boost::array<char, MAX_BUFFER_SIZE>& sendbuffer, size_t &datalen)
2038+{
2039+ EVENT_TAG status = FINALIZE;
2040+ size_t send_buffer_size = sendbuffer.max_size();
2041+ thread_data_ptr session_data;
2042+ session_thread_data_map_it session_thread_it;
2043+ receive_data_map_it receive_data_it;
2044+
2045+ try {
2046+ {
2047+ boost::mutex::scoped_lock sclock(session_thread_data_map_mutex);
2048+
2049+ session_thread_it = session_thread_data_map.find(thread_id);
2050+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
2051+ boost::format formatter("Invalid thread id. thread id : %d.");
2052+ formatter % boost::this_thread::get_id();
2053+ putLogError(100101, formatter.str(), __FILE__, __LINE__);
2054+ throw - 1;
2055+ }
2056+
2057+ session_data = session_thread_it->second;
2058+ }
2059+
2060+ receive_data_it = session_data->receive_data_map.find(session_data->target_endpoint);
2061+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
2062+ boost::format formatter("Invalid endpoint. thread id : %d.");
2063+ formatter % boost::this_thread::get_id();
2064+ putLogError(100102, formatter.str(), __FILE__, __LINE__);
2065+ throw - 1;
2066+ }
2067+
2068+ receive_data &recv_data = receive_data_it->second;
2069+
2070+ //get the data that can be sent possible
2071+ send_status_it it = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(),
2072+ data_send_possible());
2073+ if (unlikely(it == recv_data.send_status_list.end())) {
2074+ boost::format formatter("Sending possible data is not existed. thread id : %d.");
2075+ formatter % boost::this_thread::get_id();
2076+ putLogError(100103, formatter.str(), __FILE__, __LINE__);
2077+ throw - 1;
2078+ }
2079+
2080+ //buffer size >= sending_possible size
2081+ if (send_buffer_size > it->send_possible_size) {
2082+ //copy data from receive_buffer to sendbuffer by sending_possible size
2083+ memcpy(sendbuffer.data(), recv_data.receive_buffer + it->send_offset, it->send_possible_size);
2084+ //send_end_size recalc
2085+ it->send_end_size = it->send_possible_size;
2086+ //set copied data length
2087+ datalen = it->send_possible_size;
2088+ //sending_possible size recalc
2089+ it->send_possible_size = 0;
2090+ }
2091+ //buffer size < sending_possible size
2092+ else {
2093+ //copy data from receive_buffer to sendbuffer by buffer size
2094+ memcpy(sendbuffer.data(), recv_data.receive_buffer + it->send_offset, send_buffer_size);
2095+ //send_end_size recalc
2096+ it->send_end_size = send_buffer_size;
2097+ //sending_possible size recalc
2098+ it->send_possible_size -= send_buffer_size;
2099+ //set copied data length
2100+ datalen = send_buffer_size;
2101+ }
2102+
2103+ status = CLIENT_SEND;
2104+ } catch (...) {
2105+ status = FINALIZE;
2106+ }
2107+
2108+ return status;
2109+}
2110+
2111+//! called from after client select. use UDP only
2112+//! @param[in] downstream thread id
2113+//! @param[in] client udp endpoint
2114+//! @param[out] send buffer reference
2115+//! @param[out] send data length
2116+//! @return session use EVENT mode
2117+protocol_module_base::EVENT_TAG protocol_module_simple::handle_client_select(
2118+ const boost::thread::id thread_id, boost::asio::ip::udp::endpoint &cl_endpoint, boost::array < char,
2119+ MAX_BUFFER_SIZE > & sendbuffer, size_t &datalen)
2120+{
2121+ return STOP;
2122+}
2123+
2124+//! called from after client send
2125+//! @param[in] downstream thread id
2126+//! @return session use EVENT mode
2127+protocol_module_base::EVENT_TAG protocol_module_simple::handle_client_send(
2128+ const boost::thread::id thread_id)
2129+{
2130+ EVENT_TAG status = FINALIZE;
2131+ thread_data_ptr session_data;
2132+ session_thread_data_map_it session_thread_it;
2133+ receive_data_map_it receive_data_it;
2134+
2135+ try {
2136+ {
2137+ boost::mutex::scoped_lock sclock(session_thread_data_map_mutex);
2138+ //thread_id check
2139+ session_thread_it = session_thread_data_map.find(thread_id);
2140+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
2141+ boost::format formatter("Invalid thread id. thread id : %d.");
2142+ formatter % boost::this_thread::get_id();
2143+ putLogError(100106, formatter.str(), __FILE__, __LINE__);
2144+ throw - 1;
2145+ }
2146+ session_data = session_thread_it->second;
2147+ }
2148+ //endpoint check
2149+ receive_data_it = session_data->receive_data_map.find(session_data->target_endpoint);
2150+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
2151+ boost::format formatter("Invalid endpoint. thread id : %d.");
2152+ formatter % boost::this_thread::get_id();
2153+ putLogError(100107, formatter.str(), __FILE__, __LINE__);
2154+ throw - 1;
2155+ }
2156+
2157+ receive_data &recv_data = receive_data_it->second;
2158+
2159+ send_status_it it = recv_data.send_status_list.begin();
2160+ send_status_it it_end = recv_data.send_status_list.end();
2161+
2162+ //check status list
2163+ it = std::adjacent_find(it, it_end, data_send_list_incorrect());
2164+ if (unlikely(it != it_end)) {
2165+ boost::format formatter("Sending possible data is invalid. thread id : %d.");
2166+ formatter % boost::this_thread::get_id();
2167+ putLogError(100108, formatter.str(), __FILE__, __LINE__);
2168+ throw - 1;
2169+ }
2170+ //status list check
2171+ it = recv_data.send_status_list.begin();
2172+ it = find_if(it, it_end, data_send_ok());
2173+ if (unlikely(it == it_end)) {
2174+ boost::format formatter("Sending possible data is not existed. thread id : %d.");
2175+ formatter % boost::this_thread::get_id();
2176+ putLogError(100109, formatter.str(), __FILE__, __LINE__);
2177+ throw - 1;
2178+ }
2179+
2180+ //sending possible data is exist
2181+ if (it->send_possible_size > 0) {
2182+ //status remain SEND_OK
2183+ it->status = SEND_OK;
2184+ //offset recalc
2185+ it->send_offset += it->send_end_size;
2186+ //send_end_size recalc
2187+ it->send_end_size = 0;
2188+ }
2189+ //sending possible data is not exist
2190+ else {
2191+ //can receive from client continue
2192+ if (it->send_rest_size > 0) {
2193+ //change status from SEND_OK to SEND_CONTINUE
2194+ it->status = SEND_CONTINUE;
2195+ }
2196+ //can not receive from client continue
2197+ else {
2198+ //change status from SEND_OK to SEND_END
2199+ it->status = SEND_END;
2200+ }
2201+ }
2202+
2203+ it = recv_data.send_status_list.begin();
2204+ it = find_if(it, it_end, data_send_ok());
2205+ //send_ok item is exist
2206+ if (it != it_end) {
2207+ status = CLIENT_CONNECTION_CHECK;
2208+ }
2209+ //send_ok item is not exist
2210+ else {
2211+ //end flag is on
2212+ if (session_data->end_flag == END_FLAG_ON) {
2213+ status = CLIENT_DISCONNECT;
2214+ }
2215+ //end flag is off
2216+ else {
2217+ //sorry flag is on
2218+ if (session_data->sorry_flag == SORRY_FLAG_ON) {
2219+ status = SORRYSERVER_RECV;
2220+ }
2221+ //sorry flag is off
2222+ else {
2223+ status = REALSERVER_RECV;
2224+ }
2225+ }
2226+ }
2227+ } catch (...) {
2228+ status = FINALIZE;
2229+ }
2230+
2231+ return status;
2232+}
2233+
2234+//! call from client disconnect event. use upstream thread and downstream thread.
2235+//! @param[in] upstream and downstream thread id( check! one thread one event! )
2236+//! @return session use EVENT mode
2237+protocol_module_base::EVENT_TAG protocol_module_simple::handle_client_disconnect(
2238+ const boost::thread::id thread_id)
2239+{
2240+ return FINALIZE;
2241+}
2242+
2243+//! call from sorry mode event. use upstream thread and downstream thread
2244+//! @param[in] upstream and downstream thread id( check! one thread one event and first time call pattern )
2245+//! @return session use EVENT mode
2246+protocol_module_base::EVENT_TAG protocol_module_simple::handle_sorry_enable(
2247+ const boost::thread::id thread_id)
2248+{
2249+ EVENT_TAG status = FINALIZE;
2250+ boost::asio::ip::tcp::endpoint endpoint;
2251+ bool send_possible = false;
2252+ bool send_continue = false;
2253+ bool send_disable = false;
2254+ thread_data_ptr session_data;
2255+ session_thread_data_map_it session_thread_it;
2256+ receive_data_map_it receive_data_it;
2257+
2258+ try {
2259+ {
2260+ boost::mutex::scoped_lock slock(session_thread_data_map_mutex);
2261+ //check thread_id
2262+ session_thread_it = session_thread_data_map.find(thread_id);
2263+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
2264+ boost::format formatter("Invalid thread id. thread id : %d.");
2265+ formatter % boost::this_thread::get_id();
2266+ putLogError(100112, formatter.str(), __FILE__, __LINE__);
2267+ throw - 1;
2268+ }
2269+
2270+ session_data = session_thread_it->second;
2271+ }
2272+ //check endpoint
2273+ endpoint = session_data->thread_division == THREAD_DIVISION_UP_STREAM ? session_data->client_endpoint_tcp
2274+ : session_data->target_endpoint;
2275+ receive_data_it = session_data->receive_data_map.find(endpoint);
2276+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
2277+ //must be down thread
2278+ if (unlikely(session_data->thread_division == THREAD_DIVISION_UP_STREAM)) {
2279+ boost::format formatter("Invalid endpoint. thread id : %d.");
2280+ formatter % boost::this_thread::get_id();
2281+ putLogError(100113, formatter.str(), __FILE__, __LINE__);
2282+ throw - 1;
2283+ }
2284+ session_data->sorry_flag = SORRY_FLAG_ON;
2285+ status = SORRYSERVER_RECV;
2286+ } else {
2287+ receive_data &recv_data = receive_data_it->second;
2288+
2289+ //get this thread sending possible data
2290+ send_status_it it = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(),
2291+ data_send_possible());
2292+ if (it != recv_data.send_status_list.end()) {
2293+ send_possible = true;
2294+ }
2295+
2296+ it = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(), data_send_continue());
2297+ if (it != recv_data.send_status_list.end()) {
2298+ send_continue = true;
2299+ }
2300+
2301+ it = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(), data_send_disable());
2302+ if (it != recv_data.send_status_list.end()) {
2303+ send_disable = true;
2304+ }
2305+
2306+ //up thread
2307+ if (session_data->thread_division == THREAD_DIVISION_UP_STREAM) {
2308+ //accept_end_flag is off
2309+ if (session_data->accept_end_flag == ACCEPT_END_FLAG_OFF) {
2310+ //set sorry flag on
2311+ session_data->sorry_flag = SORRY_FLAG_ON;
2312+ status = ACCEPT;
2313+ }
2314+ //accept_end_flag is on
2315+ else {
2316+ //set sorry flag on
2317+ if (session_data->sorry_flag == SORRY_FLAG_ON) {
2318+ if (send_possible) {
2319+ status = SORRYSERVER_CONNECT;
2320+ } else {
2321+ status = SORRYSERVER_SELECT;
2322+ }
2323+
2324+ }
2325+ //set sorry flag off
2326+ else {
2327+ //the data that can be sent continue is exist
2328+ if (send_continue) {
2329+ //set end flag on
2330+ session_data->end_flag = END_FLAG_ON;
2331+ status = REALSERVER_DISCONNECT;
2332+ }
2333+ //the data that can be sent continue is not exist
2334+ else {
2335+ //set sorryserver_switch_flag on
2336+ session_data->sorryserver_switch_flag = SORRYSERVER_SWITCH_FLAG_ON;
2337+ //set sorry_flag on
2338+ session_data->sorry_flag = SORRY_FLAG_ON;
2339+ status = REALSERVER_DISCONNECT;
2340+ }
2341+ }
2342+ }
2343+ }
2344+ //down thread
2345+ else {
2346+ //sorry_flag is on
2347+ if (session_data->sorry_flag == SORRY_FLAG_ON) {
2348+ //sending possible data is exist
2349+ if (send_possible) {
2350+ status = CLIENT_CONNECTION_CHECK;
2351+ }
2352+ //sending possible data is not exist
2353+ else {
2354+ status = SORRYSERVER_RECV;
2355+ }
2356+ }
2357+ //sorry_flag is off
2358+ else {
2359+ //set sorry_flag on
2360+ session_data->sorry_flag = SORRY_FLAG_ON;
2361+ session_data->sorryserver_switch_flag = SORRYSERVER_SWITCH_FLAG_ON;
2362+
2363+ //sending NG data is exist or send_rest_size > 0
2364+ if (send_disable) {
2365+ //set end flag on
2366+ session_data->end_flag = END_FLAG_ON;
2367+ status = REALSERVER_DISCONNECT;
2368+ }
2369+ else {
2370+ //sending possible data is exist
2371+ if (send_possible) {
2372+ status = CLIENT_CONNECTION_CHECK;
2373+ }
2374+ //sending possible data is not exist
2375+ else {
2376+ status = SORRYSERVER_RECV;
2377+ }
2378+ }
2379+ }
2380+ }
2381+ }
2382+ } catch (...) {
2383+ status = FINALIZE;
2384+ }
2385+
2386+ return status;
2387+}
2388+
2389+//! call from sorry mode disable. use upstream thread and downstream thread.
2390+//! @param[in] upstream and downstream thread id( check! one thread one event )
2391+//! @return session use EVENT mode
2392+protocol_module_base::EVENT_TAG protocol_module_simple::handle_sorry_disable(
2393+ const boost::thread::id thread_id)
2394+{
2395+ EVENT_TAG status = FINALIZE;
2396+ boost::asio::ip::tcp::endpoint endpoint;
2397+ bool send_possible = false;
2398+ bool send_disable = false;
2399+ bool send_continue = false;
2400+ thread_data_ptr session_data;
2401+
2402+ try {
2403+ {
2404+ boost::mutex::scoped_lock sclock(session_thread_data_map_mutex);
2405+ //check thread_id
2406+ session_thread_data_map_it session_thread_it = session_thread_data_map.find(thread_id);
2407+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
2408+ boost::format formatter("Invalid thread id. thread id : %d.");
2409+ formatter % boost::this_thread::get_id();
2410+ putLogError(100116, formatter.str(), __FILE__, __LINE__);
2411+ throw - 1;
2412+ }
2413+ //check pointer
2414+ session_data = session_thread_it->second;
2415+ }
2416+ //check endpoint
2417+ endpoint = session_data->thread_division == THREAD_DIVISION_UP_STREAM ? session_data->client_endpoint_tcp
2418+ : session_data->target_endpoint;
2419+ receive_data_map_it receive_data_it = session_data->receive_data_map.find(endpoint);
2420+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
2421+ //must be down thread
2422+ if (unlikely(session_data->thread_division == THREAD_DIVISION_UP_STREAM)) {
2423+ boost::format formatter("Invalid endpoint. thread id : %d.");
2424+ formatter % boost::this_thread::get_id();
2425+ putLogError(100117, formatter.str(), __FILE__, __LINE__);
2426+ throw - 1;
2427+ }
2428+
2429+ session_data->sorry_flag = SORRY_FLAG_OFF;
2430+ status = REALSERVER_RECV;
2431+ } else {
2432+ receive_data &recv_data = receive_data_it->second;
2433+
2434+ //get this thread sending possible data
2435+ send_status_it it = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(),
2436+ data_send_possible());
2437+ if (it != recv_data.send_status_list.end()) {
2438+ send_possible = true;
2439+ }
2440+
2441+ //sending NG data is exist or send_rest_size > 0
2442+ it = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(), data_send_disable());
2443+ if (it != recv_data.send_status_list.end()) {
2444+ send_disable = true;
2445+ }
2446+
2447+ //the data that can be sent continue is exist
2448+ it = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(), data_send_continue());
2449+ if (it != recv_data.send_status_list.end()) {
2450+ send_continue = true;
2451+ }
2452+
2453+ //up thread
2454+ if (session_data->thread_division == THREAD_DIVISION_UP_STREAM) {
2455+ //accept_end_flag is off
2456+ if (session_data->accept_end_flag == ACCEPT_END_FLAG_OFF) {
2457+ //set sorry flag off
2458+ session_data->sorry_flag = SORRY_FLAG_OFF;
2459+ status = ACCEPT;
2460+ }
2461+ //accept_end_flag is on
2462+ else {
2463+ //sorry flag is on
2464+ if (session_data->sorry_flag == SORRY_FLAG_ON) {
2465+ //the data that can be sent continue is exist
2466+ if (send_continue) {
2467+ //set end flag on
2468+ session_data->end_flag = END_FLAG_ON;
2469+ status = SORRYSERVER_DISCONNECT;
2470+ }
2471+ //the data that can be sent continue is not exist
2472+ else {
2473+ //set realserver_switch_flag on
2474+ session_data->realserver_switch_flag = REALSERVER_SWITCH_FLAG_ON;
2475+ //set sorry_flag off
2476+ session_data->sorry_flag = SORRY_FLAG_OFF;
2477+ status = SORRYSERVER_DISCONNECT;
2478+ }
2479+ }
2480+ //sorry flag is off
2481+ else {
2482+ if (send_possible) {
2483+ status = REALSERVER_CONNECT;
2484+ } else {
2485+ status = REALSERVER_SELECT;
2486+ }
2487+ }
2488+ }
2489+ }
2490+ //down thread
2491+ else {
2492+ //sorry_flag is on
2493+ if (session_data->sorry_flag == SORRY_FLAG_ON) {
2494+ //set sorry_flag off
2495+ session_data->sorry_flag = SORRY_FLAG_OFF;
2496+ session_data->realserver_switch_flag = REALSERVER_SWITCH_FLAG_ON;
2497+ //sending NG data is exist or send_rest_size > 0
2498+ if (send_disable) {
2499+ //set end flag on
2500+ session_data->end_flag = END_FLAG_ON;
2501+ status = SORRYSERVER_DISCONNECT;
2502+ }
2503+ else {
2504+ //sending possible data is exist
2505+ if (send_possible) {
2506+ status = CLIENT_CONNECTION_CHECK;
2507+ }
2508+ //sending possible data is not exist
2509+ else {
2510+ status = REALSERVER_RECV;
2511+ }
2512+ }
2513+ }
2514+ //sorry_flag is off
2515+ else {
2516+ //sending possible data is exist
2517+ if (send_possible) {
2518+ status = CLIENT_CONNECTION_CHECK;
2519+ }
2520+ //sending possible data is not exist
2521+ else {
2522+ status = REALSERVER_RECV;
2523+ }
2524+ }
2525+ }
2526+ }
2527+ } catch (...) {
2528+ status = FINALIZE;
2529+ }
2530+
2531+ return status;
2532+}
2533+
2534+//! call from realserver disconnect. use upstream thread and downstream thread
2535+//! @param[in] upstream and downstream thread id( check! one thread one event )
2536+//! @param[in] disconnected realserver endpoint.
2537+//! @return session use EVENT mode
2538+protocol_module_base::EVENT_TAG protocol_module_simple::handle_realserver_disconnect(
2539+ const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &rs_endpoint)
2540+{
2541+ EVENT_TAG status = FINALIZE;
2542+ bool possible_flag = false;
2543+ thread_data_ptr session_data;
2544+ boost::asio::ip::tcp::endpoint endpoint;
2545+
2546+ try {
2547+ {
2548+ boost::mutex::scoped_lock sclock(session_thread_data_map_mutex);
2549+
2550+ session_thread_data_map_it session_thread_it = session_thread_data_map.find(thread_id);
2551+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
2552+ boost::format formatter("Invalid thread id. thread id : %d.");
2553+ formatter % boost::this_thread::get_id();
2554+ putLogError(100120, formatter.str(), __FILE__, __LINE__);
2555+ throw - 1;
2556+ }
2557+
2558+ session_data = session_thread_it->second;
2559+ }
2560+
2561+ endpoint = session_data->thread_division == THREAD_DIVISION_UP_STREAM ? session_data->client_endpoint_tcp
2562+ : session_data->target_endpoint;
2563+ receive_data_map_it receive_data_it = session_data->receive_data_map.find(endpoint);
2564+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
2565+ return FINALIZE;
2566+ }
2567+
2568+ receive_data &recv_data = receive_data_it->second;
2569+
2570+ //the data that can be sent possible is exist
2571+ send_status_it it = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(),
2572+ data_send_possible());
2573+ if (it != recv_data.send_status_list.end()) {
2574+ possible_flag = true;
2575+ }
2576+
2577+ //up thread
2578+ if (session_data->thread_division == THREAD_DIVISION_UP_STREAM) {
2579+ //end flag is on
2580+ if (session_data->end_flag == END_FLAG_ON) {
2581+ status = CLIENT_RECV;
2582+ }
2583+ //end flag is off
2584+ else {
2585+ //sorryserver_switch_flag is on
2586+ if (session_data->sorryserver_switch_flag == SORRYSERVER_SWITCH_FLAG_ON) {
2587+ session_data->sorryserver_switch_flag = SORRYSERVER_SWITCH_FLAG_OFF;
2588+ status = SORRYSERVER_SELECT;
2589+ }
2590+ //sorryserver_switch_flag is off
2591+ else {
2592+ //set end flag on
2593+ session_data->end_flag = END_FLAG_ON;
2594+ status = CLIENT_RECV;
2595+ }
2596+ }
2597+ }
2598+ //down thread
2599+ else {
2600+ if (session_data->end_flag == END_FLAG_ON) {
2601+ status = CLIENT_DISCONNECT;
2602+ } else {
2603+ if (session_data->sorryserver_switch_flag == SORRYSERVER_SWITCH_FLAG_ON) {
2604+ session_data->sorryserver_switch_flag = SORRYSERVER_SWITCH_FLAG_OFF;
2605+ status = SORRYSERVER_RECV;
2606+ } else {
2607+ //set end flag on
2608+ session_data->end_flag = END_FLAG_ON;
2609+ status = CLIENT_DISCONNECT;
2610+ }
2611+ }
2612+
2613+ //the data that can be sent possible is exist
2614+ if (possible_flag) {
2615+ status = CLIENT_CONNECTION_CHECK;
2616+ }
2617+ }
2618+ } catch (...) {
2619+ status = FINALIZE;
2620+ }
2621+
2622+ return status;
2623+}
2624+
2625+//! call from sorry server disconnect. use upstream thread and downstream thread
2626+//! @param[in] upstream and downstream thread id( check! one thread one event )
2627+//! @param[in] disconnect sorryserver endpoint
2628+//! @return session use EVENT mode
2629+//! @return session use EVENT mode
2630+protocol_module_base::EVENT_TAG protocol_module_simple::handle_sorryserver_disconnect(
2631+ const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &sorry_endpoint)
2632+{
2633+ EVENT_TAG status = FINALIZE;
2634+ bool possible_flag = false;
2635+ thread_data_ptr session_data;
2636+ boost::asio::ip::tcp::endpoint endpoint;
2637+
2638+ try {
2639+ {
2640+ boost::mutex::scoped_lock sclock(session_thread_data_map_mutex);
2641+
2642+ session_thread_data_map_it session_thread_it = session_thread_data_map.find(thread_id);
2643+ if (unlikely(session_thread_it == session_thread_data_map.end() || session_thread_it->second == NULL)) {
2644+ boost::format formatter("Invalid thread id. thread id : %d.");
2645+ formatter % boost::this_thread::get_id();
2646+ putLogError(100124, formatter.str(), __FILE__, __LINE__);
2647+ throw - 1;
2648+ }
2649+
2650+ session_data = session_thread_it->second;
2651+ }
2652+
2653+ endpoint = session_data->thread_division == THREAD_DIVISION_UP_STREAM ? session_data->client_endpoint_tcp
2654+ : session_data->target_endpoint;
2655+ receive_data_map_it receive_data_it = session_data->receive_data_map.find(endpoint);
2656+ if (unlikely(receive_data_it == session_data->receive_data_map.end())) {
2657+ boost::format formatter("Invalid endpoint(%s). thread id: %d.");
2658+ formatter % endpoint % boost::this_thread::get_id();
2659+ putLogError(100125, formatter.str(), __FILE__, __LINE__);
2660+ throw - 1;
2661+ }
2662+
2663+ receive_data &recv_data = receive_data_it->second;
2664+
2665+ //the data that can be sent possible is exist
2666+ send_status_it it = find_if(recv_data.send_status_list.begin(), recv_data.send_status_list.end(),
2667+ data_send_possible());
2668+ if (it != recv_data.send_status_list.end()) {
2669+ possible_flag = true;
2670+ }
2671+
2672+ //up thread
2673+ if (session_data->thread_division == THREAD_DIVISION_UP_STREAM) {
2674+ //end flag is on
2675+ if (session_data->end_flag == END_FLAG_ON) {
2676+ status = CLIENT_RECV;
2677+ }
2678+ //end flag is off
2679+ else {
2680+ //realserver_switch_flag is on
2681+ if (session_data->realserver_switch_flag == REALSERVER_SWITCH_FLAG_ON) {
2682+ session_data->realserver_switch_flag = REALSERVER_SWITCH_FLAG_OFF;
2683+ status = REALSERVER_SELECT;
2684+ }
2685+ //realserver_switch_flag is off
2686+ else {
2687+ //set end flag on
2688+ session_data->end_flag = END_FLAG_ON;
2689+ status = CLIENT_RECV;
2690+ }
2691+ }
2692+ }
2693+ //down thread
2694+ else {
2695+ if (session_data->end_flag == END_FLAG_ON) {
2696+ status = CLIENT_DISCONNECT;
2697+ } else {
2698+ if (session_data->realserver_switch_flag == REALSERVER_SWITCH_FLAG_ON) {
2699+ session_data->realserver_switch_flag = REALSERVER_SWITCH_FLAG_OFF;
2700+ status = REALSERVER_RECV;
2701+ } else {
2702+ session_data->end_flag = END_FLAG_ON;
2703+ status = CLIENT_DISCONNECT;
2704+ }
2705+ }
2706+
2707+ //the data that can be sent possible is exist
2708+ if (possible_flag) {
2709+ status = CLIENT_CONNECTION_CHECK;
2710+ }
2711+ }
2712+ } catch (...) {
2713+ status = FINALIZE;
2714+ }
2715+
2716+ return status;
2717+}
2718+
2719+//! call from realserver disconnect. use upstream thread and downstream thread.
2720+//! @param[in] upstream and downstream thread id( check! one thread one event )
2721+//! @param[in] disconnect realserver endpoint
2722+//! @return session use EVENT mode.
2723+protocol_module_base::EVENT_TAG protocol_module_simple::handle_realserver_close(
2724+ const boost::thread::id thread_id, const boost::asio::ip::udp::endpoint &rs_endpoint)
2725+{
2726+ return STOP;
2727+}
2728+
2729+}
2730+
2731+extern "C" l7vs::protocol_module_base*
2732+create_module()
2733+{
2734+ return dynamic_cast<l7vs::protocol_module_base *>(new l7vs::protocol_module_simple());
2735+}
2736+
2737+extern "C" void
2738+destroy_module(l7vs::protocol_module_base *in)
2739+{
2740+ delete in;
2741+}
--- /dev/null
+++ b/doc/moduledevel/sample/protocol/protocol_module_simple.h
@@ -0,0 +1,288 @@
1+/*
2+ * @file protocol_module_simple.h
3+ * @brief protocol module simple header file.
4+ *
5+ * L7VSD: Linux Virtual Server for Layer7 Load Balancing
6+ * Copyright (C) 2009 NTT COMWARE Corporation.
7+ *
8+ * This program is free software; you can redistribute it and/or
9+ * modify it under the terms of the GNU Lesser General Public
10+ * License as published by the Free Software Foundation; either
11+ * version 2.1 of the License, or (at your option) any later version.
12+ *
13+ * This program is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+ * Lesser General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU Lesser General Public
19+ * License along with this library; if not, write to the Free Software
20+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21+ * 02110-1301 USA
22+ *
23+ **********************************************************************/
24+
25+#include <boost/thread/mutex.hpp>
26+#include <boost/lexical_cast.hpp>
27+#include "http_protocol_module_base.h"
28+
29+#ifndef PROTOCOL_MODULE_SIMPLE_H
30+#define PROTOCOL_MODULE_SIMPLE_H
31+
32+#define MAX_OPTION_SIZE 128
33+#define MAX_SIMPLE_MODULE_BUFFER_SIZE (8190 + MAX_BUFFER_SIZE)
34+
35+namespace l7vs
36+{
37+
38+class protocol_module_simple : public http_protocol_module_base
39+{
40+public:
41+ enum SEND_STATUS_TAG {
42+ SEND_OK = 0,
43+ SEND_NG,
44+ SEND_END,
45+ SEND_CONTINUE
46+ };
47+ struct edit_data {
48+ std::string data;
49+ size_t data_size;
50+ size_t insert_posission;
51+ size_t replace_size;
52+ } ;
53+
54+ struct send_status {
55+ SEND_STATUS_TAG status;
56+ size_t send_end_size;
57+ size_t send_rest_size;
58+ size_t send_possible_size;
59+ size_t send_offset;
60+ size_t unsend_size;
61+ int edit_division;
62+ boost::asio::ip::tcp::endpoint send_endpoint;
63+ std::list<edit_data> edit_data_list;
64+ };
65+
66+ struct receive_data {
67+ char *receive_buffer;
68+ char *receive_buffer1;
69+ char *receive_buffer2;
70+ size_t receive_buffer_max_size;
71+ size_t receive_buffer_rest_size;
72+ std::list<send_status> send_status_list;
73+ receive_data() {
74+ receive_buffer1 = NULL;
75+ receive_buffer2 = NULL;
76+ receive_buffer = NULL;
77+ receive_buffer_max_size = 0;
78+ receive_buffer_rest_size = 0;
79+ }
80+ ~receive_data() {
81+ if (receive_buffer1 != NULL) {
82+ delete [] receive_buffer1;
83+ receive_buffer1 = NULL;
84+ }
85+
86+ if (receive_buffer2 != NULL) {
87+ delete [] receive_buffer2;
88+ receive_buffer2 = NULL;
89+ }
90+
91+ receive_buffer = NULL;
92+ receive_buffer_max_size = 0;
93+ receive_buffer_rest_size = 0;
94+ }
95+ };
96+
97+
98+ struct session_thread_data_simple {
99+ boost::thread::id thread_id;
100+ int thread_division;
101+ boost::thread::id pair_thread_id;
102+ std::map<boost::asio::ip::tcp::endpoint, receive_data> receive_data_map;
103+ int end_flag;
104+ int accept_end_flag;
105+ int sorry_flag;
106+ int sorryserver_switch_flag;
107+ int realserver_switch_flag;
108+ boost::asio::ip::tcp::endpoint target_endpoint;
109+ boost::asio::ip::tcp::endpoint client_endpoint_tcp;
110+ EVENT_TAG last_status;
111+ };
112+
113+ typedef std::list<send_status>::iterator send_status_it;
114+ typedef boost::shared_ptr<session_thread_data_simple> thread_data_ptr;
115+ typedef std::map<boost::thread::id, thread_data_ptr>::iterator session_thread_data_map_it;
116+ typedef std::map<boost::asio::ip::tcp::endpoint, receive_data>::iterator receive_data_map_it;
117+protected:
118+ int forwarded_for;
119+ boost:: array<char, MAX_OPTION_SIZE> sorry_uri ;
120+ std::map<boost::thread::id, thread_data_ptr> session_thread_data_map;
121+ boost::mutex session_thread_data_map_mutex;
122+
123+public:
124+ static const std::string MODULE_NAME;
125+
126+ static const int THREAD_DIVISION_UP_STREAM;
127+ static const int THREAD_DIVISION_DOWN_STREAM;
128+
129+ static const int END_FLAG_OFF;
130+ static const int END_FLAG_ON;
131+
132+ static const int ACCEPT_END_FLAG_OFF;
133+ static const int ACCEPT_END_FLAG_ON;
134+
135+ static const int SORRY_FLAG_ON;
136+ static const int SORRY_FLAG_OFF;
137+
138+ static const int SORRYSERVER_SWITCH_FLAG_OFF;
139+ static const int SORRYSERVER_SWITCH_FLAG_ON;
140+
141+ static const int REALSERVER_SWITCH_FLAG_OFF;
142+ static const int REALSERVER_SWITCH_FLAG_ON;
143+
144+ static const int EDIT_DIVISION_NO_EDIT;
145+ static const int EDIT_DIVISION_EDIT;
146+
147+ static const int FORWARDED_FOR_OFF;
148+ static const int FORWARDED_FOR_ON;
149+
150+ static const int COLLECT_STATS_OFF;
151+ static const int COLLECT_STATS_ON;
152+
153+public:
154+ protocol_module_simple();
155+ ~protocol_module_simple();
156+
157+ bool is_tcp();
158+ bool is_udp();
159+ void replication_interrupt();
160+ void initialize(rs_list_itr_func_type inlist_begin,
161+ rs_list_itr_func_type inlist_end,
162+ rs_list_itr_next_func_type inlist_next,
163+ boost::function< void(void) > inlist_lock,
164+ boost::function< void(void) > inlist_unlock);
165+ void finalize();
166+ bool is_use_sorry();
167+ check_message_result check_parameter(const std::vector<std::string>& args);
168+ check_message_result set_parameter(const std::vector<std::string>& args);
169+ check_message_result add_parameter(const std::vector<std::string>& args);
170+ void get_option_info(std::string &option);
171+ void handle_rslist_update();
172+ void register_schedule(tcp_schedule_func_type inschedule);
173+ void register_schedule(udp_schedule_func_type inschedule);
174+ EVENT_TAG handle_session_initialize(const boost::thread::id up_thread_id, const boost::thread::id down_thread_id, const boost::asio::ip::tcp::endpoint &client_endpoint_tcp, const boost::asio::ip::udp::endpoint &client_endpoint_udp);
175+ EVENT_TAG handle_session_finalize(const boost::thread::id up_thread_id, const boost::thread::id down_thread_id);
176+ EVENT_TAG handle_accept(const boost::thread::id thread_id);
177+ EVENT_TAG handle_client_recv(const boost::thread::id thread_id, const boost::array<char, MAX_BUFFER_SIZE>& recvbuffer, const size_t recvlen);
178+ EVENT_TAG handle_realserver_select(const boost::thread::id thread_id, boost::asio::ip::tcp::endpoint &rs_endpoint);
179+ EVENT_TAG handle_realserver_select(const boost::thread::id thread_id, boost::asio::ip::udp::endpoint &rs_endpoint, boost::array<char, MAX_BUFFER_SIZE>& sendbuffer, size_t &datalen);
180+ EVENT_TAG handle_realserver_connect(const boost::thread::id thread_id, boost::array<char, MAX_BUFFER_SIZE>& sendbuffer, size_t &datalen);
181+ EVENT_TAG handle_realserver_connection_fail(const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &rs_endpoint);
182+ EVENT_TAG handle_realserver_send(const boost::thread::id thread_id);
183+ EVENT_TAG handle_sorryserver_select(const boost::thread::id thread_id, boost::asio::ip::tcp::endpoint &sorry_endpoint);
184+ EVENT_TAG handle_sorryserver_connect(const boost::thread::id thread_id, boost::array<char, MAX_BUFFER_SIZE>& sendbuffer, size_t &datalen);
185+ EVENT_TAG handle_sorryserver_connection_fail(const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &sorry_endpoint);
186+ EVENT_TAG handle_sorryserver_send(const boost::thread::id thread_id);
187+ EVENT_TAG handle_realserver_recv(const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &rs_endpoint, const boost::array<char, MAX_BUFFER_SIZE>& recvbuffer, const size_t recvlen);
188+ EVENT_TAG handle_realserver_recv(const boost::thread::id thread_id, const boost::asio::ip::udp::endpoint &rs_endpoint, const boost::array<char, MAX_BUFFER_SIZE>& recvbuffer, const size_t recvlen);
189+ EVENT_TAG handle_sorryserver_recv(const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &sorry_endpoint, const boost::array<char, MAX_BUFFER_SIZE>& recvbuffer, const size_t recvlen);
190+ EVENT_TAG handle_response_send_inform(const boost::thread::id thread_id);
191+ EVENT_TAG handle_client_connection_check(const boost::thread::id thread_id, boost::array<char, MAX_BUFFER_SIZE>& sendbuffer, size_t &datalen);
192+ EVENT_TAG handle_client_select(const boost::thread::id thread_id, boost::asio::ip::udp::endpoint &cl_endpoint, boost::array<char, MAX_BUFFER_SIZE>& sendbuffer, size_t &datalen);
193+ EVENT_TAG handle_client_send(const boost::thread::id thread_id);
194+ EVENT_TAG handle_client_disconnect(const boost::thread::id thread_id);
195+ EVENT_TAG handle_sorry_enable(const boost::thread::id thread_id);
196+ EVENT_TAG handle_sorry_disable(const boost::thread::id thread_id);
197+ EVENT_TAG handle_realserver_disconnect(const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &rs_endpoint);
198+ EVENT_TAG handle_sorryserver_disconnect(const boost::thread::id thread_id, const boost::asio::ip::tcp::endpoint &sorry_endpoint);
199+ EVENT_TAG handle_realserver_close(const boost::thread::id thread_id, const boost::asio::ip::udp::endpoint &rs_endpoint);
200+};
201+
202+inline bool operator < (const protocol_module_simple::edit_data &lref, const protocol_module_simple::edit_data &rref)
203+{
204+ return lref.insert_posission < rref.insert_posission;
205+}
206+
207+class data_send_possible
208+{
209+public:
210+ inline bool operator()(const protocol_module_simple::send_status &send_status) {
211+ return send_status.status == protocol_module_simple::SEND_OK
212+ && send_status.send_possible_size > 0;
213+ }
214+};
215+
216+class data_send_disable
217+{
218+public:
219+ inline bool operator()(const protocol_module_simple::send_status &send_status) {
220+ return send_status.status == protocol_module_simple::SEND_NG
221+ || send_status.send_rest_size > 0 ;
222+ }
223+};
224+
225+class data_send_continue
226+{
227+public:
228+ inline bool operator()(const protocol_module_simple::send_status &send_status) {
229+ return send_status.status == protocol_module_simple::SEND_CONTINUE;
230+ }
231+};
232+
233+class data_send_ng
234+{
235+public:
236+ inline bool operator()(const protocol_module_simple::send_status &send_status) {
237+ return send_status.status == protocol_module_simple::SEND_NG;
238+ }
239+};
240+
241+class data_send_ok
242+{
243+public:
244+ inline bool operator()(const protocol_module_simple::send_status &send_status) {
245+ return send_status.status == protocol_module_simple::SEND_OK;
246+ }
247+};
248+
249+class data_send_repeated
250+{
251+public:
252+ inline bool operator()(const protocol_module_simple::send_status &send_status_first,
253+ const protocol_module_simple::send_status &send_status_second) {
254+ return send_status_first.status == protocol_module_simple::SEND_NG
255+ || send_status_first.status == protocol_module_simple::SEND_CONTINUE;
256+ }
257+};
258+
259+class data_send_list_incorrect
260+{
261+public:
262+ inline bool operator()(const protocol_module_simple::send_status &send_status_first,
263+ const protocol_module_simple::send_status &send_status_second) {
264+ return (send_status_first.status == protocol_module_simple::SEND_OK
265+ && send_status_first.send_rest_size > 0)
266+ || (send_status_first.status == protocol_module_simple::SEND_CONTINUE)
267+ || (send_status_first.status == protocol_module_simple::SEND_NG);
268+ }
269+};
270+
271+class rs_list_scoped_lock
272+{
273+protected:
274+ boost::function< void(void) > rs_list_unlock;
275+public:
276+ rs_list_scoped_lock(boost::function< void(void) > inlist_lock,
277+ boost::function< void(void) > inlist_unlock) {
278+ inlist_lock();
279+ rs_list_unlock = inlist_unlock;
280+ }
281+ ~rs_list_scoped_lock() {
282+ rs_list_unlock();
283+ }
284+};
285+}
286+
287+#endif //PROTOCOL_MODULE_SIMPLE_H
288+
--- /dev/null
+++ b/doc/moduledevel/sample/schedule/Makefile.am
@@ -0,0 +1,25 @@
1+AUTOMAKE_OPTIONS = foreign
2+L7VS_MODDIR = @l7vs_moddir@
3+L7VS_INCLUDEDIR = @l7vs_includedir@
4+MAX_BUFFER_SIZE = @l7vs_max_buffer_size@
5+AM_CPPFLAGS = \
6+ -g -O2 -fno-strict-aliasing -Wall -Werror -fPIC -pthread \
7+ -I$(L7VS_INCLUDEDIR) \
8+ -DMAX_BUFFER_SIZE=$(MAX_BUFFER_SIZE)
9+
10+lib_LTLIBRARIES = \
11+ libsched_rnd.la
12+
13+libsched_rnd_la_SOURCES = \
14+ schedule_module_base.h \
15+ schedule_module_rnd.h \
16+ schedule_module_rnd.cpp
17+
18+libsched_rnd_la_LIBADD = -lrt -lboost_thread-mt
19+
20+install:
21+ cp ./.libs/libsched_rnd.so ./.libs/sched_rnd.so && \
22+ $(INSTALL) -m 755 -d $(L7VS_MODDIR)
23+ $(INSTALL) -m 755 -D \
24+ ./.libs/sched_rnd.so \
25+ $(L7VS_MODDIR)
--- /dev/null
+++ b/doc/moduledevel/sample/schedule/README
@@ -0,0 +1,24 @@
1+Sample source of schedule module for UltraMonkey-L7 .
2+This is random scheduler.
3+
4+== Files ==
5+./schedule
6+configure.in
7+Makefile.am
8+schedule_module_rnd.cpp
9+schedule_module_rnd.h
10+
11+== Set up ==
12+*please install um-l7 devel package before compile.
13+
14+cp -r ./schedule /path/to/develop
15+cd /path/to/develop/schedule
16+autoreconf -ifv
17+./configure
18+make
19+make install
20+
21+== How to use this module ==
22+l7vsadm -A -t VIP:PORT -m PROTO_MOD -s rnd
23+
24+
--- /dev/null
+++ b/doc/moduledevel/sample/schedule/configure.in
@@ -0,0 +1,89 @@
1+AC_PREREQ(2.59)
2+AC_INIT(l7vsd)
3+PACKAGENAME=ultramonkeyl7-mod-random-1.0.0
4+VERSION=1.0.0
5+
6+AM_INIT_AUTOMAKE($PACKAGENAME, $VERSION, no-define )
7+AC_CONFIG_SRCDIR([config.h.in])
8+AC_CONFIG_HEADER([config.h])
9+
10+# Checks for programs.
11+AC_PROG_CXX
12+AC_PROG_LIBTOOL
13+AC_PROG_CPP
14+AC_PROG_INSTALL
15+AC_PROG_LN_S
16+AC_PROG_MAKE_SET
17+
18+# Checks for libraries.
19+AC_CHECK_LIB(dl, dlopen)
20+AC_CHECK_LIB(log4cxx, main, :,
21+ [AC_MSG_ERROR( l7vsd require log4cxx library. )] )
22+AC_CHECK_LIB(rt, main, :,
23+ [AC_MSG_ERROR( l7vsd require rt library. )] )
24+AC_CHECK_LIB(boost_thread-mt, main, :,
25+ [AC_MSG_ERROR( l7vsd require boost library. )] )
26+AC_CHECK_LIB(boost_system-mt, main, :,
27+ [AC_MSG_ERROR( l7vsd require boost library. )] )
28+
29+# Checks for header files.
30+AC_CHECK_HEADERS([limits.h unistd.h])
31+
32+# Checks for typedefs, structures, and compiler characteristics.
33+AC_HEADER_STDBOOL
34+AC_C_CONST
35+AC_C_INLINE
36+AC_TYPE_SIZE_T
37+AC_STRUCT_TM
38+
39+# Checks for library functions.
40+AC_HEADER_STDC
41+AC_FUNC_MKTIME
42+AC_FUNC_STRFTIME
43+AC_CHECK_FUNCS([gethostname localtime_r memset])
44+
45+# application-specific option
46+if test `uname -m` == "x86_64"; then
47+ AC_SUBST( libdir, [/usr/lib64] )
48+else
49+ AC_SUBST( libdir, [/usr/lib] )
50+ AC_SUBST( CXXFLAGS, -march=i686 )
51+fi
52+AC_SUBST( includedir, [/usr/include] )
53+
54+AC_ARG_WITH(
55+ l7vs-moddir,
56+ [ --with-l7vs-moddir=DIR l7vs module is to be installed in DIR.
57+ [default=LIBDIR/l7vs] ],
58+ [ l7vs_moddir="$withval" ],
59+ [ l7vs_moddir="${libdir}/l7vs" ]
60+)
61+
62+AC_ARG_WITH(
63+ l7vs-includedir,
64+ [ --with-l7vs-includedir=DIR l7vs headerfile is to be installed in DIR.
65+ [default=INCLUDEDIR/l7vs] ],
66+ [ l7vs_includedir="$withval" ],
67+ [ l7vs_includedir="${includedir}/l7vs" ]
68+)
69+
70+AC_ARG_WITH(
71+ l7vs-buffer-size,
72+ [ --with-l7vs-buffer-size=NUM l7vsd using heap buffer size.
73+ [default=4096] ],
74+ [ l7vs_max_buffer_size="$withval" ],
75+ [ l7vs_max_buffer_size=4096 ]
76+)
77+
78+
79+AC_SUBST(CC,g++)
80+AC_SUBST(exec_prefix, [/usr] )
81+AC_SUBST(l7vs_moddir)
82+AC_SUBST(l7vs_includedir)
83+AC_SUBST(l7vs_max_buffer_size)
84+AC_SUBST(MANDIR)
85+AC_SUBST(ultramonkeyl7_version,ultramonkeyl7-$VERSION)
86+
87+AC_CONFIG_FILES([Makefile])
88+
89+AC_OUTPUT
--- /dev/null
+++ b/doc/moduledevel/sample/schedule/schedule_module_rnd.cpp
@@ -0,0 +1,280 @@
1+/*
2+ * @file schedule_module_rnd.cpp
3+ * @brief shared object schedule module class
4+ *
5+ * L7VSD: Linux Virtual Server for Layer7 Load Balancing
6+ * Copyright (C) 2009 NTT COMWARE Corporation.
7+ *
8+ * This program is free software; you can redistribute it and/or
9+ * modify it under the terms of the GNU Lesser General Public
10+ * License as published by the Free Software Foundation; either
11+ * version 2.1 of the License, or (at your option) any later version.
12+ *
13+ * This program is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+ * Lesser General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU Lesser General Public
19+ * License along with this library; if not, write to the Free Software
20+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21+ * 02110-1301 USA
22+ *
23+ **********************************************************************/
24+#include "schedule_module_rnd.h"
25+#include <boost/format.hpp>
26+
27+#include "utility.h"
28+
29+namespace l7vs
30+{
31+
32+//! constructor
33+schedule_module_random::schedule_module_random() : schedule_module_base("rnd")
34+{
35+}
36+
37+//! destructor
38+schedule_module_random::~schedule_module_random() {}
39+
40+//! initialize function
41+void schedule_module_random::initialize()
42+{
43+ if (likely(!getloglevel.empty())) {
44+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
45+ if (likely(!putLogDebug.empty())) {
46+ putLogDebug(200000, "Function in : schedule_module_random::initialize", __FILE__, __LINE__);
47+ }
48+ }
49+ }
50+
51+ boost::asio::ip::tcp::endpoint tcp_local_endpoint ;
52+ boost::asio::ip::udp::endpoint udp_local_endpoint ;
53+
54+ tcp_endpoint = tcp_local_endpoint ;
55+ udp_endpoint = udp_local_endpoint ;
56+
57+ if (likely(!putLogInfo.empty())) {
58+ putLogInfo(200000, "Saved endpoint was initialized.", __FILE__, __LINE__);
59+ }
60+
61+ if (likely(!getloglevel.empty())) {
62+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
63+ if (likely(!putLogDebug.empty())) {
64+ putLogDebug(200001, "Function out : schedule_module_random::initialize", __FILE__, __LINE__);
65+ }
66+ }
67+ }
68+}
69+
70+//! tcp protocol support check
71+//! @return tcp support is true
72+//! @return tcp not-support is false
73+bool schedule_module_random::is_tcp()
74+{
75+ return true;
76+}
77+
78+//! udp protocol support check
79+//! @return udp support is true
80+//! @return udp not-support is false
81+bool schedule_module_random::is_udp()
82+{
83+ return true;
84+}
85+
86+//! handle schedule called then schedule function for TCP/IP endpoint
87+//! @param[in] thread id
88+//! @param[in] list iterator first function object
89+//! @param[in] list iterator last function object
90+//! @param[in] list iterator next function object
91+//! @param[out] scheduled TCP/IP endpoint
92+void schedule_module_random::handle_schedule(
93+ boost::thread::id thread_id,
94+ rslist_iterator_begin_func_type inlist_begin,
95+ rslist_iterator_end_func_type inlist_end,
96+ rslist_iterator_next_func_type inlist_next,
97+ boost::asio::ip::tcp::endpoint &outendpoint)
98+{
99+ if (likely(!getloglevel.empty())) {
100+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
101+ if (likely(!putLogDebug.empty())) {
102+ putLogDebug(200002, "Function in : schedule_module_random::handle_schedule", __FILE__, __LINE__);
103+ }
104+ }
105+ }
106+
107+ boost::asio::ip::tcp::endpoint tcp_local_endpoint ;
108+ rslist_type::iterator itr;
109+ std::string buf;
110+ int loop;
111+ std::vector<boost::asio::ip::tcp::endpoint> tmp_list;
112+
113+ //! set clear data as NULL
114+ outendpoint = tcp_local_endpoint;
115+
116+ if (unlikely(inlist_begin.empty() || inlist_end.empty() || inlist_next.empty())) {
117+ //! invalid iterator function
118+ if (likely(!putLogFatal.empty())) {
119+ putLogFatal(200000, "Iterator function is empty.", __FILE__, __LINE__);
120+ }
121+ goto END;
122+ }
123+
124+ //! Debug log
125+ if (likely(!getloglevel.empty())) {
126+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
127+ if (likely(!putLogDebug.empty())) {
128+ for (loop = 1, itr = inlist_begin(); itr != inlist_end(); itr = inlist_next(itr), loop++) {
129+ buf = boost::io::str(boost::format("realserver[%d] : %s:%d weight(%d)")
130+ % loop
131+ % itr->tcp_endpoint.address()
132+ % itr->tcp_endpoint.port()
133+ % itr->weight);
134+ putLogDebug(200003, buf, __FILE__, __LINE__);
135+ }
136+ }
137+ }
138+ }
139+ //! Debug log END
140+
141+ for (itr = inlist_begin(); itr != inlist_end(); itr = inlist_next(itr)) {
142+ // pure random
143+ /*
144+ if (itr->weight > 0) {
145+ tmp_list.push_back(itr->tcp_endpoint);
146+ }
147+ */
148+ // rs1 weight=1 ,rs2 weight=2
149+ // hit % => rs1:33% rs2:66%
150+ for(int i=0; i < itr->weight; i++){
151+ tmp_list.push_back(itr->tcp_endpoint);
152+ }
153+ }
154+
155+ if (unlikely(tmp_list.empty())) {
156+ //! no data
157+ if (likely(!putLogError.empty())) {
158+ putLogError(200000, "There is no realserver on list.", __FILE__, __LINE__);
159+ }
160+ goto END;
161+ }
162+ //! set endpoind
163+ outendpoint = tmp_list.at(rand() % tmp_list.size());
164+
165+END:
166+ if (likely(!getloglevel.empty())) {
167+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
168+ if (likely(!putLogDebug.empty())) {
169+ putLogDebug(200006, "Function out : schedule_module_random::handle_schedule", __FILE__, __LINE__);
170+ }
171+ }
172+ }
173+}
174+
175+//! handle schedule calls then schedule function for UDP endpoint
176+//! @param[in] thread id
177+//! @param[in] list iterator first function object
178+//! @param[in] list iterator last function object
179+//! @param[in] list iterator next function object
180+//! @param[out] scheduled UDP endpoint
181+void schedule_module_random::handle_schedule(
182+ boost::thread::id thread_id,
183+ rslist_iterator_begin_func_type inlist_begin,
184+ rslist_iterator_end_func_type inlist_end,
185+ rslist_iterator_next_func_type inlist_next,
186+ boost::asio::ip::udp::endpoint &outendpoint)
187+{
188+ if (likely(!getloglevel.empty())) {
189+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
190+ if (likely(!putLogDebug.empty())) {
191+ putLogDebug(200007, "Function in : schedule_module_random::handle_schedule", __FILE__, __LINE__);
192+ }
193+ }
194+ }
195+
196+ boost::asio::ip::udp::endpoint udp_local_endpoint ;
197+ rslist_type::iterator itr;
198+ std::string buf;
199+ int loop;
200+ std::vector<boost::asio::ip::udp::endpoint> tmp_list;
201+
202+ //! set clear data as NULL
203+ outendpoint = udp_local_endpoint;
204+
205+ if (unlikely(inlist_begin.empty() || inlist_end.empty() || inlist_next.empty())) {
206+ //! invalid iterator function
207+ if (likely(!putLogFatal.empty())) {
208+ putLogFatal(200001, "Iterator function is empty.", __FILE__, __LINE__);
209+ }
210+ goto END;
211+ }
212+
213+ //! Debug log
214+ if (likely(!getloglevel.empty())) {
215+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
216+ if (likely(!putLogDebug.empty())) {
217+ for (loop = 1, itr = inlist_begin(); itr != inlist_end(); itr = inlist_next(itr), loop++) {
218+ buf = boost::io::str(boost::format("realserver[%d] : %s:%d weight(%d)")
219+ % loop
220+ % itr->udp_endpoint.address()
221+ % itr->udp_endpoint.port()
222+ % itr->weight);
223+ putLogDebug(200008, buf, __FILE__, __LINE__);
224+ }
225+ }
226+ }
227+ }
228+ //! Debug log END
229+
230+ for (itr = inlist_begin(); itr != inlist_end(); itr = inlist_next(itr)) {
231+ // pure random
232+ /*
233+ if (itr->weight > 0) {
234+ tmp_list.push_back(itr->udp_endpoint);
235+ }
236+ */
237+ // rs1 weight=1 ,rs2 weight=2
238+ // hit % => rs1:33% rs2:66%
239+ for(int i=0; i < itr->weight; i++){
240+ tmp_list.push_back(itr->udp_endpoint);
241+ }
242+ }
243+ if (unlikely(tmp_list.empty())) {
244+ //! no data
245+ if (likely(!putLogError.empty())) {
246+ putLogError(200000, "There is no realserver on list.", __FILE__, __LINE__);
247+ }
248+ goto END;
249+ }
250+
251+ //! set endpoind
252+ outendpoint = tmp_list.at(rand() % tmp_list.size());
253+
254+END:
255+ if (likely(!getloglevel.empty())) {
256+ if (unlikely(LOG_LV_DEBUG == getloglevel())) {
257+ if (likely(!putLogDebug.empty())) {
258+ putLogDebug(200011, "Function out : schedule_module_random::handle_schedule", __FILE__, __LINE__);
259+ }
260+ }
261+ }
262+}
263+
264+//! replication interval interrupt
265+//! timer thread call this function. from virtualservice.
266+void schedule_module_random::replication_interrupt() {}
267+
268+} //namespace l7vs
269+
270+extern "C" l7vs::schedule_module_base*
271+create_module()
272+{
273+ return dynamic_cast<l7vs::schedule_module_base *>(new l7vs::schedule_module_random());
274+}
275+
276+extern "C" void
277+destroy_module(l7vs::schedule_module_base *in)
278+{
279+ delete in;
280+}
--- /dev/null
+++ b/doc/moduledevel/sample/schedule/schedule_module_rnd.h
@@ -0,0 +1,88 @@
1+/*
2+ * @file schedule_module_rnd.h
3+ * @brief shared object schedule module class
4+ *
5+ * L7VSD: Linux Virtual Server for Layer7 Load Balancing
6+ * Copyright (C) 2009 NTT COMWARE Corporation.
7+ *
8+ * This program is free software; you can redistribute it and/or
9+ * modify it under the terms of the GNU Lesser General Public
10+ * License as published by the Free Software Foundation; either
11+ * version 2.1 of the License, or (at your option) any later version.
12+ *
13+ * This program is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+ * Lesser General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU Lesser General Public
19+ * License along with this library; if not, write to the Free Software
20+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21+ * 02110-1301 USA
22+ *
23+ **********************************************************************/
24+#ifndef SCHEDULE_MODULE_RND_H
25+#define SCHEDULE_MODULE_RND_H
26+
27+#include "schedule_module_base.h"
28+
29+namespace l7vs
30+{
31+
32+class schedule_module_random : public schedule_module_base
33+{
34+protected:
35+ boost::asio::ip::tcp::endpoint tcp_endpoint ;
36+ boost::asio::ip::udp::endpoint udp_endpoint ;
37+public:
38+ //! constructor
39+ schedule_module_random();
40+ //! destructor
41+ ~schedule_module_random();
42+
43+ //! initialize function
44+ void initialize();
45+
46+ //! tcp protocol support check
47+ //! @return tcp support is true
48+ //! @return tcp not-support is false
49+ bool is_tcp();
50+ //! udp protocol support check
51+ //! @return udp support is true
52+ //! @return udp not-support is false
53+ bool is_udp();
54+
55+ //! handle schedule called then schedule function for TCP/IP endpoint
56+ //! @param[in] thread id
57+ //! @param[in] list iterator first function object
58+ //! @param[in] list iterator last function object
59+ //! @param[in] list iterator next function object
60+ //! @param[out] scheduled TCP/IP endpoint
61+ void handle_schedule(
62+ boost::thread::id thread_id,
63+ rslist_iterator_begin_func_type inlist_begin,
64+ rslist_iterator_end_func_type inlist_end,
65+ rslist_iterator_next_func_type inlist_next,
66+ boost::asio::ip::tcp::endpoint &outendpoint);
67+
68+ //! handle schedule calls then schedule function for UDP endpoint
69+ //! @param[in] thread id
70+ //! @param[in] list iterator first function object
71+ //! @param[in] list iterator last function object
72+ //! @param[in] list iterator next function object
73+ //! @param[out] scheduled UDP endpoint
74+ void handle_schedule(
75+ boost::thread::id thread_id,
76+ rslist_iterator_begin_func_type inlist_begin,
77+ rslist_iterator_end_func_type inlist_end,
78+ rslist_iterator_next_func_type inlist_next,
79+ boost::asio::ip::udp::endpoint &outendpoint);
80+
81+ //! replication interval interrupt
82+ //! timer thread call this function. from virtualservice.
83+ void replication_interrupt();
84+};
85+
86+} //namespace l7vs
87+
88+#endif //SCHEDULE_MODULE_RND_H
--- a/ultramonkeyl7.spec
+++ b/ultramonkeyl7.spec
@@ -1,5 +1,6 @@
11 %define l7vs_moddir %{_libdir}/l7vs
22 %define l7vs_logdir %{_localstatedir}/log/l7vs
3+%define l7vs_includedir %{_includedir}/l7vs
34 %define l7vsadm_sockdir %{_localstatedir}/run/l7vs
45 %define l7vs_maxvs 64
56
@@ -14,13 +15,35 @@ Source0: %{name}-%{version}.tar.gz
1415 BuildRoot: %{_tmppath}/%{name}-%{version}-root
1516 BuildRequires: glib2-devel
1617 AutoReqProv: no
18+Requires: boost >= 1.41.0
19+Requires: apache-log4cxx >= 0.10.0
20+Requires: apr
21+Requires: apr-util
22+Requires: openssl
23+Requires: net-snmp
24+Requires: perl
25+Requires: perl-libwww-perl
26+Requires: perl-Crypt-SSLeay
27+Requires: perl-Net-SSLeay
28+Requires: perl-IO-Socket-SSL
29+Requires: perl-IO-Socket-INET6
1730
1831 %define hb2_tempdir /usr/share/doc/%{name}-%{version}-%{release}/heartbeat-ra
1932 %define mibs_tempdir /usr/share/doc/%{name}-%{version}-%{release}/mibs
33+%define moduledevel_tempdir /usr/share/doc/%{name}-%{version}-%{release}/moduledevel
2034
2135 %description
2236 Layer-7 load balancing daemon
2337
38+%package devel
39+Summary: Header files for UltraMonkeyl7's module
40+Group: Development/Libraries
41+Requires: %{name} = %{version}-%{release}
42+
43+%description devel
44+This is the development package that provides header files
45+for UltraMonkeyl7's module.
46+
2447 %prep
2548 %setup -q
2649
@@ -41,6 +64,9 @@ mkdir -p ${RPM_BUILD_ROOT}%{l7vs_logdir}
4164 mkdir -p ${RPM_BUILD_ROOT}%{l7vsadm_sockdir}
4265 mkdir -p ${RPM_BUILD_ROOT}%{hb2_tempdir}
4366 mkdir -p ${RPM_BUILD_ROOT}%{mibs_tempdir}
67+mkdir -p ${RPM_BUILD_ROOT}%{moduledevel_tempdir}
68+mkdir -p ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample
69+mkdir -p ${RPM_BUILD_ROOT}%{l7vs_includedir}
4470
4571 # bin
4672 install -c -m 755 -D l7vsd/src/l7vsd ${RPM_BUILD_ROOT}%{_sbindir}/l7vsd
@@ -80,6 +106,34 @@ install -c -m 755 -D doc/heartbeat-ra/VIPcheck ${RPM_BUILD_ROOT}%{hb2_tempdir}/V
80106 # mib file
81107 install -c -m 644 -D doc/mibs/ULTRAMONKEY-L7-MIB.txt ${RPM_BUILD_ROOT}%{mibs_tempdir}/ULTRAMONKEY-L7-MIB.txt
82108
109+# header for devel
110+install -c -m 644 -D l7vsd/include/protocol_module_base.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/protocol_module_base.h
111+install -c -m 644 -D l7vsd/include/schedule_module_base.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/schedule_module_base.h
112+install -c -m 644 -D l7vsd/include/module_base.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/module_base.h
113+install -c -m 644 -D l7vsd/include/utility.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/utility.h
114+install -c -m 644 -D l7vsd/include/logger.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/logger.h
115+install -c -m 644 -D l7vsd/include/logger_enum.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/logger_enum.h
116+install -c -m 644 -D l7vsd/include/trapmessage.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/trapmessage.h
117+install -c -m 644 -D l7vsd/include/error_code.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/error_code.h
118+install -c -m 644 -D l7vsd/include/atomic.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/atomic.h
119+install -c -m 644 -D l7vsd/include/wrlock.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/wrlock.h
120+install -c -m 644 -D l7vsd/include/replication.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/replication.h
121+install -c -m 644 -D l7vsd/include/realserver.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/realserver.h
122+install -c -m 644 -D l7vsd/include/realserver_element.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/realserver_element.h
123+install -c -m 644 -D l7vsd/include/endpoint.h ${RPM_BUILD_ROOT}%{l7vs_includedir}/endpoint.h
124+install -c -m 644 -D doc/moduledevel/sample/protocol/README ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/protocol/README
125+install -c -m 644 -D doc/moduledevel/sample/protocol/Makefile.am ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/protocol/Makefile.am
126+install -c -m 644 -D doc/moduledevel/sample/protocol/configure.in ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/protocol/configure.in
127+install -c -m 644 -D doc/moduledevel/sample/protocol/http_protocol_module_base.cpp ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/protocol/http_protocol_module_base.cpp
128+install -c -m 644 -D doc/moduledevel/sample/protocol/http_protocol_module_base.h ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/protocol/http_protocol_module_base.h
129+install -c -m 644 -D doc/moduledevel/sample/protocol/protocol_module_simple.cpp ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/protocol/protocol_module_simple.cpp
130+install -c -m 644 -D doc/moduledevel/sample/protocol/protocol_module_simple.h ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/protocol/protocol_module_simple.h
131+install -c -m 644 -D doc/moduledevel/sample/schedule/README ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/schedule/README
132+install -c -m 644 -D doc/moduledevel/sample/schedule/Makefile.am ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/schedule/Makefile.am
133+install -c -m 644 -D doc/moduledevel/sample/schedule/configure.in ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/schedule/configure.in
134+install -c -m 644 -D doc/moduledevel/sample/schedule/schedule_module_rnd.cpp ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/schedule/schedule_module_rnd.cpp
135+install -c -m 644 -D doc/moduledevel/sample/schedule/schedule_module_rnd.h ${RPM_BUILD_ROOT}%{moduledevel_tempdir}/sample/schedule/schedule_module_rnd.h
136+
83137 %clean
84138 rm -rf $RPM_BUILD_ROOT
85139
@@ -112,9 +166,30 @@ fi
112166 %dir %{mibs_tempdir}
113167 %config(noreplace) %{mibs_tempdir}/*
114168
169+%files devel
170+%defattr(-, root, root, 0755)
171+%dir %{_includedir}/l7vs
172+%{_includedir}/l7vs/protocol_module_base.h
173+%{_includedir}/l7vs/schedule_module_base.h
174+%{_includedir}/l7vs/module_base.h
175+%{_includedir}/l7vs/utility.h
176+%{_includedir}/l7vs/logger.h
177+%{_includedir}/l7vs/logger_enum.h
178+%{_includedir}/l7vs/trapmessage.h
179+%{_includedir}/l7vs/error_code.h
180+%{_includedir}/l7vs/atomic.h
181+%{_includedir}/l7vs/wrlock.h
182+%{_includedir}/l7vs/replication.h
183+%{_includedir}/l7vs/realserver.h
184+%{_includedir}/l7vs/realserver_element.h
185+%{_includedir}/l7vs/endpoint.h
186+%dir %{moduledevel_tempdir}
187+%{moduledevel_tempdir}/*
188+
115189 %changelog
116190 * Sat Sep 8 2012 HIBARI Michiro <l05102@shibaura-it.ac.jp> 3.1.0-devel
117191 - Update for 3.1.0-devel
192+- Change spec file for generate devel package.
118193
119194 * Fri Aug 31 2012 Hiroaki Nakano <nakano.hiroaki@nttcom.co.jp> 3.0.4-2
120195 - Update for 3.0.4-2