Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of git://git.process-one.net/tsung/mainline int…

…o p1

Conflicts:
	src/tsung/ts_http.erl
	src/tsung/ts_jabber.erl
	src/tsung/ts_jabber_common.erl
	src/tsung/ts_search.erl
	src/tsung_controller/ts_config.erl
	src/tsung_controller/ts_config_jabber.erl
	src/tsung_controller/ts_config_server.erl
	tsung-1.0.dtd
  • Loading branch information...
commit 10d19f33299c39bdd19a5f156b84940ae0e68711 2 parents c3426b5 + 78ff62e
Eric Cestari cstar authored
Showing with 2,860 additions and 2,411 deletions.
  1. +10 −0 CHANGES
  2. +9 −6 Makefile.in
  3. +183 −10 configure
  4. +18 −2 configure.in
  5. +6 −0 debian/changelog
  6. +145 −14 doc/user_manual.html
  7. +85 −7 doc/user_manual.tex
  8. +5 −2 include/ts_config.hrl
  9. +5 −2 include/ts_http.hrl
  10. +2 −1  include/ts_jabber.hrl
  11. +47 −0 include/ts_shell.hrl
  12. +1 −1  src/lib/mochijson2.erl
  13. +0 −949 src/lib/snmp_mgr.erl
  14. +0 −713 src/lib/snmp_mgr_misc.erl
  15. +28 −28 src/templates/graph.thtml
  16. +55 −19 src/test/ts_test_config.erl
  17. +38 −1 src/test/ts_test_http.erl
  18. +5 −3 src/test/ts_test_jabber.erl
  19. +18 −16 src/test/ts_test_proxy.erl
  20. +4 −4 src/test/ts_test_recorder.erl
  21. +129 −11 src/test/ts_test_search.erl
  22. +136 −0 src/test/xmpp-muc.xml.in
  23. +169 −27 src/tsung/ts_client.erl
  24. +150 −0 src/tsung/ts_cport.erl
  25. +13 −4 src/tsung/ts_fs.erl
  26. +137 −24 src/tsung/ts_http.erl
  27. +51 −23 src/tsung/ts_http_common.erl
  28. +186 −0 src/tsung/ts_ip_scan.erl
  29. +66 −30 src/tsung/ts_jabber.erl
  30. +43 −23 src/tsung/ts_jabber_common.erl
  31. +36 −24 src/tsung/ts_launcher.erl
  32. +6 −1 src/tsung/ts_launcher_mgr.erl
  33. +8 −0 src/tsung/ts_ldap.erl
  34. +4 −4 src/tsung/ts_mon_cache.erl
  35. +8 −0 src/tsung/ts_mysql.erl
  36. +9 −0 src/tsung/ts_pgsql.erl
  37. +8 −0 src/tsung/ts_raw.erl
  38. +58 −43 src/tsung/ts_search.erl
  39. +160 −0 src/tsung/ts_shell.erl
  40. +11 −2 src/tsung/ts_sup.erl
  41. +67 −63 src/tsung/ts_utils.erl
  42. +7 −0 src/tsung/ts_webdav.erl
  43. +1 −1  src/tsung/tsung.erl
  44. +135 −56 src/tsung_controller/ts_config.erl
  45. +1 −1  src/tsung_controller/ts_config_fs.erl
  46. +12 −4 src/tsung_controller/ts_config_http.erl
  47. +21 −2 src/tsung_controller/ts_config_jabber.erl
  48. +189 −121 src/tsung_controller/ts_config_server.erl
  49. +67 −0 src/tsung_controller/ts_config_shell.erl
  50. +19 −12 src/tsung_controller/ts_match_logger.erl
  51. +43 −22 src/tsung_controller/ts_mon.erl
  52. +44 −38 src/tsung_controller/ts_os_mon_snmp.erl
  53. +31 −32 src/tsung_controller/ts_timer.erl
  54. +31 −11 src/tsung_controller/ts_user_server.erl
  55. +1 −1  src/tsung_controller/tsung_controller.app.src.in
  56. +12 −12 src/tsung_recorder/ts_client_proxy.erl
  57. +4 −4 src/tsung_recorder/ts_proxy_http.erl
  58. +3 −3 src/tsung_recorder/ts_proxy_recorder.erl
  59. +52 −10 src/tsung_stats.pl.in
  60. +50 −19 tsung-1.0.dtd
  61. +1 −1  tsung-recorder.sh.in
  62. +16 −3 tsung.sh.in
  63. +1 −1  vsn.mk
10 CHANGES
View
@@ -1,3 +1,13 @@
+1.3.2 -> 1.3.3 Minor bugfixes (17 Aug 2010)
+Bugfix:
+ * [TSUN-154] - parent proxy doesn't work anymore in 1.3.x (tested with 1.3.2 and 1.3.0).
+ * [TSUN-155] - url substitution is broken in some cases
+ * [TSUN-156] - Tsung not using sessions with low probabilities
+ * [TSUN-157] - ssl doesn't work with erlang R14A
+ * [TSUN-158] - failure when a proxy is used and an URL substitution is set
+ * [TSUN-159] - HTTP cookies support is broken when a proxy is used
+ * [TSUN-160] - tsung can sometimes hang at the beginning using distributed setup
+ * [TSUN-161] - if statement not allowed in a transaction
1.3.1 -> 1.3.2 Major bugfixes and enhancements (14 Jun 2010)
Bugfix:
* [TSUN-128] - Apostrophes cause string to convert to deep list in setdynvars with Erlang function.
15 Makefile.in
View
@@ -296,8 +296,8 @@ boot: tsung priv/tsung.boot priv/tsung_recorder.boot priv/tsung_controller.boot
priv/tsung.boot: builder.beam $(SRC_APPFILES)
# use builder to make boot file
@rm -rf temp
- @mkdir -p temp/lib/$(APPLICATION)-$(VERSION)
- @ln -sf $(PWD)/ebin temp/lib/$(APPLICATION)-$(VERSION)/ebin
+ @mkdir -p temp/lib/$(APPLICATION)-$(VERSION)/ebin
+ @cp $(TARGET) $(LIB_TARGET) temp/lib/$(APPLICATION)-$(VERSION)/ebin
@ln -sf $(PWD)/src/$(APPLICATION) temp/lib/$(APPLICATION)-$(VERSION)/src
@ln -sf $(PWD)/include temp/lib/$(APPLICATION)-$(VERSION)/include
@ln -sf $(PWD)/priv temp/lib/$(APPLICATION)-$(VERSION)/priv
@@ -308,14 +308,15 @@ priv/tsung.boot: builder.beam $(SRC_APPFILES)
&& echo $(BUILD_OPTIONS) > $(BUILD_OPTIONS_FILE) \
&& $(ERL) -noshell -s builder go -s init stop >> $(BUILDER_LOG) 2>&1 \
)
+ @cp temp/lib/$(APPLICATION)-$(VERSION)/ebin/*.app ebin
@rm -rf temp
@echo "done"
priv/tsung_controller.boot: builder.beam $(CONTROLLER_SRC_APPFILES)
# use builder to make boot file
@rm -rf temp
- @mkdir -p temp/lib/$(CONTROLLER_APPLICATION)-$(VERSION)
- @ln -sf $(PWD)/ebin temp/lib/$(CONTROLLER_APPLICATION)-$(VERSION)/ebin
+ @mkdir -p temp/lib/$(CONTROLLER_APPLICATION)-$(VERSION)/ebin
+ @cp $(CONTROLLER_TARGET) temp/lib/$(CONTROLLER_APPLICATION)-$(VERSION)/ebin
@ln -sf $(PWD)/src/$(CONTROLLER_APPLICATION) temp/lib/$(CONTROLLER_APPLICATION)-$(VERSION)/src
@ln -sf $(PWD)/include temp/lib/$(CONTROLLER_APPLICATION)-$(VERSION)/include
@ln -sf $(PWD)/priv temp/lib/$(CONTROLLER_APPLICATION)-$(VERSION)/priv
@@ -325,14 +326,15 @@ priv/tsung_controller.boot: builder.beam $(CONTROLLER_SRC_APPFILES)
&& echo $(BUILD_OPTIONS) > $(BUILD_OPTIONS_FILE) \
&& $(ERL) -noshell -s builder go -s init stop >> $(BUILDER_LOG) 2>&1 \
)
+ @cp temp/lib/$(CONTROLLER_APPLICATION)-$(VERSION)/ebin/*.app ebin
@rm -rf temp
@echo "done"
priv/tsung_recorder.boot: builder.beam $(RECORDER_SRC_APPFILES)
# use builder to make boot file
@rm -rf temp
- @mkdir -p temp/lib/$(RECORDER_APPLICATION)-$(VERSION)
- @ln -sf $(PWD)/ebin temp/lib/$(RECORDER_APPLICATION)-$(VERSION)/ebin
+ @mkdir -p temp/lib/$(RECORDER_APPLICATION)-$(VERSION)/ebin
+ @cp $(RECORDER_TARGET) temp/lib/$(RECORDER_APPLICATION)-$(VERSION)/ebin
@ln -sf $(PWD)/src/$(RECORDER_APPLICATION) temp/lib/$(RECORDER_APPLICATION)-$(VERSION)/src
@ln -sf $(PWD)/include temp/lib/$(RECORDER_APPLICATION)-$(VERSION)/include
@ln -sf $(PWD)/priv temp/lib/$(RECORDER_APPLICATION)-$(VERSION)/priv
@@ -342,6 +344,7 @@ priv/tsung_recorder.boot: builder.beam $(RECORDER_SRC_APPFILES)
&& echo $(BUILD_OPTIONS) > $(BUILD_OPTIONS_FILE) \
&& $(ERL) -noshell -s builder go -s init stop >> $(BUILDER_LOG) 2>&1 \
)
+ @cp temp/lib/$(RECORDER_APPLICATION)-$(VERSION)/ebin/*.app ebin
@rm -rf temp
@echo "done"
193 configure
View
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.63 for tsung 1.3.2.
+# Generated by GNU Autoconf 2.63 for tsung 1.4.0a.
#
# Report bugs to <tsung-users@process-one.net>.
#
@@ -598,8 +598,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='tsung'
PACKAGE_TARNAME='tsung'
-PACKAGE_VERSION='1.3.2'
-PACKAGE_STRING='tsung 1.3.2'
+PACKAGE_VERSION='1.4.0a'
+PACKAGE_STRING='tsung 1.4.0a'
PACKAGE_BUGREPORT='tsung-users@process-one.net'
ac_unique_file="src/tsung/tsung.erl"
@@ -616,6 +616,8 @@ DTD
ERLANG_APPLICATIONS
ERL_OPTS
erlang_cv_orelse
+ERLANG_LIB_VER_public_key
+ERLANG_LIB_DIR_public_key
ERLANG_LIB_VER_crypto
ERLANG_LIB_DIR_crypto
ERLANG_LIB_VER_ssl
@@ -1230,7 +1232,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures tsung 1.3.2 to adapt to many kinds of systems.
+\`configure' configures tsung 1.4.0a to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1291,7 +1293,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of tsung 1.3.2:";;
+ short | recursive ) echo "Configuration of tsung 1.4.0a:";;
esac
cat <<\_ACEOF
@@ -1371,7 +1373,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-tsung configure 1.3.2
+tsung configure 1.4.0a
generated by GNU Autoconf 2.63
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1387,7 +1389,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by tsung $as_me 1.3.2, which was
+It was created by tsung $as_me 1.4.0a, which was
generated by GNU Autoconf 2.63. Invocation command line was
$ $0 $@
@@ -2779,6 +2781,113 @@ ERLANG_LIB_VER_crypto=$erlang_cv_lib_ver_crypto
+{ $as_echo "$as_me:$LINENO: checking for Erlang/OTP 'public_key' library subdirectory" >&5
+$as_echo_n "checking for Erlang/OTP 'public_key' library subdirectory... " >&6; }
+if test "${erlang_cv_lib_dir_public_key+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=erl
+ac_compile='$ERLC $ERLCFLAGS -b beam conftest.$ac_ext >&5'
+ac_link='$ERLC $ERLCFLAGS -b beam conftest.$ac_ext >&5 ; echo "#!/bin/sh" > conftest$ac_exeext ; $as_echo "\"$ERL\" -run conftest start -run init stop -noshell" >> conftest$ac_exeext ; chmod +x conftest$ac_exeext'
+ if test "$cross_compiling" = yes; then
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+-module(conftest).
+-export([start/0]).
+
+start() ->
+ ReturnValue = case code:lib_dir("public_key") of
+ {error, bad_name} ->
+ file:write_file("conftest.out", "not found\n"),
+ 1;
+ LibDir ->
+ file:write_file("conftest.out", LibDir),
+ 0
+ end,
+ halt(ReturnValue)
+.
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ erlang_cv_lib_dir_public_key=`cat conftest.out`
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test ! -f conftest.out; then
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: test Erlang program execution failed
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: test Erlang program execution failed
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }; }
+ else
+ erlang_cv_lib_dir_public_key="not found"
+ fi
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+ ac_ext=erl
+ac_compile='$ERLC $ERLCFLAGS -b beam conftest.$ac_ext >&5'
+ac_link='$ERLC $ERLCFLAGS -b beam conftest.$ac_ext >&5 ; echo "#!/bin/sh" > conftest$ac_exeext ; $as_echo "\"$ERL\" -run conftest start -run init stop -noshell" >> conftest$ac_exeext ; chmod +x conftest$ac_exeext'
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $erlang_cv_lib_dir_public_key" >&5
+$as_echo "$erlang_cv_lib_dir_public_key" >&6; }
+{ $as_echo "$as_me:$LINENO: checking for Erlang/OTP 'public_key' library version" >&5
+$as_echo_n "checking for Erlang/OTP 'public_key' library version... " >&6; }
+if test "${erlang_cv_lib_ver_public_key+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test "$erlang_cv_lib_dir_public_key" = "not found"; then
+ erlang_cv_lib_ver_public_key="not found"
+else
+ erlang_cv_lib_ver_public_key=`$as_echo "$erlang_cv_lib_dir_public_key" | sed -n -e 's,^.*-\([^/-]*\)$,\1,p'`
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $erlang_cv_lib_ver_public_key" >&5
+$as_echo "$erlang_cv_lib_ver_public_key" >&6; }
+ERLANG_LIB_DIR_public_key=$erlang_cv_lib_dir_public_key
+
+ERLANG_LIB_VER_public_key=$erlang_cv_lib_ver_public_key
+
+
+
{ $as_echo "$as_me:$LINENO: checking if Erlang/OTP SSL application is running fine" >&5
$as_echo_n "checking if Erlang/OTP SSL application is running fine... " >&6; }
@@ -2838,8 +2947,63 @@ $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
( exit $ac_status )
+
+ if test "$cross_compiling" = yes; then
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+-module(conftest).
+-export([start/0]).
+
+start() ->
+ application:start(crypto),
+ application:start(public_key),
+ case application:start(ssl) of
+ ok -> ok;
+ Err -> halt(1)
+ end,
+ halt(0)
+.
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ erlang_cv_ssl_runnable=yes
+ ERLANG_APPLICATIONS="kernel,stdlib,crypto,public_key,ssl"
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
ERLANG_APPLICATIONS="kernel,stdlib"
- { $as_echo "$as_me:$LINENO: result: WARNING: ssl application is not working properly !!!" >&5
+ { $as_echo "$as_me:$LINENO: result: WARNING: ssl application is not working properly !!!" >&5
$as_echo "WARNING: ssl application is not working properly !!!" >&6; }
fi
rm -rf conftest.dSYM
@@ -2849,9 +3013,18 @@ fi
fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+fi
{ $as_echo "$as_me:$LINENO: result: $erlang_cv_ssl_runnable" >&5
$as_echo "$erlang_cv_ssl_runnable" >&6; }
+
+
{ $as_echo "$as_me:$LINENO: checking if Erlang/OTP crypto application is running fine" >&5
$as_echo_n "checking if Erlang/OTP crypto application is running fine... " >&6; }
if test "${erlang_cv_crypto_runnable+set}" = set; then
@@ -3683,7 +3856,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by tsung $as_me 1.3.2, which was
+This file was extended by tsung $as_me 1.4.0a, which was
generated by GNU Autoconf 2.63. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -3733,7 +3906,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
-tsung config.status 1.3.2
+tsung config.status 1.4.0a
configured by $0, generated by GNU Autoconf 2.63,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
20 configure.in
View
@@ -33,6 +33,7 @@ dnl check for xmerl include path
AC_ERLANG_CHECK_LIB(xmerl)
AC_ERLANG_CHECK_LIB(ssl)
AC_ERLANG_CHECK_LIB(crypto)
+AC_ERLANG_CHECK_LIB(public_key)
dnl check if ssl is working
AC_CACHE_CHECK([if Erlang/OTP SSL application is running fine],
@@ -47,10 +48,25 @@ AC_CACHE_CHECK([if Erlang/OTP SSL application is running fine],
halt(0)])],
[erlang_cv_ssl_runnable=yes
ERLANG_APPLICATIONS="kernel,stdlib,ssl"],
- [ERLANG_APPLICATIONS="kernel,stdlib"
- AC_MSG_RESULT(WARNING: ssl application is not working properly !!!)])
+ [
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([], [dnl
+ application:start(crypto),
+ application:start(public_key),
+ case application:start(ssl) of
+ ok -> ok;
+ Err -> halt(1)
+ end,
+ halt(0)])],
+ [erlang_cv_ssl_runnable=yes
+ ERLANG_APPLICATIONS="kernel,stdlib,crypto,public_key,ssl"],
+ [ERLANG_APPLICATIONS="kernel,stdlib"
+ AC_MSG_RESULT(WARNING: ssl application is not working properly !!!)])
+ ])
])
+
+
dnl check if crypto is working
AC_CACHE_CHECK([if Erlang/OTP crypto application is running fine],
[erlang_cv_crypto_runnable],
6 debian/changelog
View
@@ -1,3 +1,9 @@
+tsung (1.3.3-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- Nicolas Niclausse <nicolas.niclausse@niclux.org> Wed, 17 Aug 2010 18:11:05 +0200
+
tsung (1.3.2-1) unstable; urgency=low
* New upstream release
159 doc/user_manual.html
View
@@ -95,8 +95,8 @@
<!--ENDHTML-->
<!--CUT DEF section 1 --><H1 ALIGN=center>Tsung User’s manual</H1><DIV CLASS="center">
-<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1><TR><TD ALIGN=left NOWRAP bgcolor="#F2F2F2"> Version:</TD><TD ALIGN=left NOWRAP>1.3.2</TD></TR>
-<TR><TD ALIGN=left NOWRAP bgcolor="#F2F2F2"> Date :</TD><TD ALIGN=left NOWRAP>June 20, 2010</TD></TR>
+<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1><TR><TD ALIGN=left NOWRAP bgcolor="#F2F2F2"> Version:</TD><TD ALIGN=left NOWRAP>1.3.3</TD></TR>
+<TR><TD ALIGN=left NOWRAP bgcolor="#F2F2F2"> Date :</TD><TD ALIGN=left NOWRAP>September 13, 2010</TD></TR>
</TABLE>
</DIV><!--TOC section Contents-->
<H2 CLASS="section"><!--SEC ANCHOR -->Contents</H2><!--SEC END --><UL CLASS="toc"><LI CLASS="li-toc">
@@ -192,7 +192,7 @@ <H2 CLASS="section"><!--SEC ANCHOR -->Contents</H2><!--SEC END --><UL CLASS="toc
</LI><LI CLASS="li-toc"><A HREF="#htoc64">6.7.2  Reading external file</A>
</LI><LI CLASS="li-toc"><A HREF="#htoc65">6.7.3  Dynamic variables</A>
</LI><LI CLASS="li-toc"><A HREF="#htoc66">6.7.4  Checking the server’s response</A>
-</LI><LI CLASS="li-toc"><A HREF="#htoc67">6.7.5  Loops, If</A>
+</LI><LI CLASS="li-toc"><A HREF="#htoc67">6.7.5  Loops, If, Foreach</A>
</LI></UL>
</LI></UL>
</LI><LI CLASS="li-toc"><A HREF="#htoc68">7  Statistics and reports</A>
@@ -1305,6 +1305,23 @@ <H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc55">6.6.1</A>  Thinkt
</TD></TR>
</TABLE></TD></TR>
</TABLE></TD></TR>
+</TABLE><P><B>Since version 1.4.0</B>, you can use a dynamic variable to set
+the thinktime value:
+</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
+CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD><TD><TABLE BORDER=0 CELLPADDING="1" CELLSPACING=0><TR><TD><PRE CLASS="verbatim">&lt;thinktime value='%%_rndthink%%' random='true'&gt;&lt;/thinktime&gt;
+</PRE></TD></TR>
+</TABLE></TD><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+</TABLE></TD></TR>
</TABLE><!--TOC subsubsection HTTP-->
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc56">6.6.2</A>  HTTP</H4><!--SEC END --><P>This example shows several features of the HTTP protocol support in
Tsung: GET and POST request, basic authentication, transaction for
@@ -1359,7 +1376,10 @@ <H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc56">6.6.2</A>  HTTP</
</TD></TR>
</TABLE></TD></TR>
</TABLE></TD></TR>
-</TABLE><P><B>New in 1.2.2:</B> You can add any HTTP header now, as in:
+</TABLE><P>If you use an absolute URL, the server used in the URL will override
+the one specified in the <TT>&lt;server&gt;</TT> section. The following relative
+requests in the session will also use this new server value (until a
+new absolute URL is set).</P><P><B>New in 1.2.2:</B> You can add any HTTP header now, as in:
</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
</TD></TR>
@@ -1721,7 +1741,7 @@ <H5 CLASS="paragraph"><!--SEC ANCHOR -->VHost</H5><!--SEC END --><P>VHost suppor
</TABLE><P>When each client starts a session, it chooses randomly a domain (each domain has the
same probability).</P><!--TOC paragraph raw XML-->
<H5 CLASS="paragraph"><!--SEC ANCHOR -->raw XML</H5><!--SEC END --><P>
-You can send raw XML date to the server using the <TT>raw</TT> type:
+You can send raw XML data to the server using the <TT>raw</TT> type:
</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
</TD></TR>
@@ -2267,7 +2287,7 @@ <H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc64">6.7.2</A>  Readin
</TABLE></TD></TR>
</TABLE></TD></TR>
</TABLE><P>Much simpler than the old method !</P><!--TOC subsubsection Dynamic variables-->
-<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc65">6.7.3</A>  Dynamic variables</H4><!--SEC END --><P>In some cases, you may want to use a value given by the server in a
+<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc65">6.7.3</A>  Dynamic variables</H4><!--SEC END --><P><A NAME="Dynamic variables"></A></P><P>In some cases, you may want to use a value given by the server in a
response later in the session, and this value is <B>dynamically
generated</B> by the server for each user. For this, you can use
<FONT COLOR=purple>&lt;dyn_variable&gt;</FONT> in the scenario</P><P>Let’s take an example with HTTP. You can easily grab a value in a HTML
@@ -2333,7 +2353,29 @@ <H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc65">6.7.3</A>  Dynami
</TABLE></TD></TR>
</TABLE><!--TOC paragraph Regexp-->
<H5 CLASS="paragraph"><!--SEC ANCHOR -->Regexp</H5><!--SEC END --><P>If the dynamic value is not a form variable, you can set a regexp by
-hand, for example to get the title of a HTML page:
+hand, for example to get the title of a HTML page: the regexp engine
+uses the <TT>re</TT> module, a Perl like regular expressions module
+for Erlang.</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
+CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD><TD><TABLE BORDER=0 CELLPADDING="1" CELLSPACING=0><TR><TD><PRE CLASS="verbatim"> &lt;request&gt;
+ &lt;dyn_variable name="mytitlevar"
+ re="&amp;lt;title&amp;gt;(.*)&amp;lt;/title&amp;gt;"/&gt;
+ &lt;http url="/testtsung.html" method="GET" version="1.0"&gt;&lt;/http&gt;
+ &lt;/request&gt;
+</PRE></TD></TR>
+</TABLE></TD><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+</TABLE></TD></TR>
+</TABLE><P>Previously (before 1.4.0), Tsung uses the old <TT>regexp</TT> module
+from erlang. This is now deprecated. The syntax was:
</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
</TD></TR>
@@ -2386,7 +2428,7 @@ <H5 CLASS="paragraph"><!--SEC ANCHOR -->XPath</H5><!--SEC END --><P>A new way to
</TABLE></TD></TR>
</TABLE><P>There is a bug in the xpath engine, result nodes from "descendant-or-self" aren’t returned in document order. This isn’t a problem for the most common cases.
However, queries like <FONT COLOR=purple>//img[1]/@src</FONT> are not recommended, as the order of the <FONT COLOR=purple>&lt;img&gt;</FONT> elements returned from //img is not the expected.
-The order is respected for paths without "descendant-or-self" axis, so this: <FONT COLOR=purple>/html/body/div[2]/img[3]/@src</FONT> is interpreted as expected and can be safely used.</P><P>Basic tests shows a x4 improvement in speed over the <EM>regexp</EM> implementation.</P><!--TOC paragraph JSONPath-->
+The order is respected for paths without "descendant-or-self" axis, so this: <FONT COLOR=purple>/html/body/div[2]/img[3]/@src</FONT> is interpreted as expected and can be safely used.</P><P>Basic tests shows a x4 improvement in speed over the <EM>regexp</EM> implementation.</P><P>It is possible to use Xpath to get a list of elements from an html page, allowing dynamic retrieval of objects. You can either create embedded erlang code to parse the list produced, or use foreach that was introduced in release <B>(</B>1.4.0).</P><!--TOC paragraph JSONPath-->
<H5 CLASS="paragraph"><!--SEC ANCHOR -->JSONPath</H5><!--SEC END --><P>Another way to analyze the server response has been introduced in the
release <B>1.3.2</B> when the server is sending JSON data. It is only for the HTTP plugin. This feature uses the mochiweb library
and <B>only works with erlang R13B and newer version</B>.</P><P>Tsung implements a (very) limited subset of JSONPath as defined here <A HREF="http://goessner.net/articles/JsonPath/"><TT>http://goessner.net/articles/JsonPath/</TT></A></P><P>To utilize jsonpath expression, use a <TT>jsonpath</TT> attribute when
@@ -2584,7 +2626,10 @@ <H5 CLASS="paragraph"><!--SEC ANCHOR -->set_dynvars</H5><!--SEC END --><P><B>Sin
</TD></TR>
</TABLE></TD></TR>
</TABLE></TD></TR>
-</TABLE></LI></OL><P>A <TT>setdynvars</TT> can be defined anywhere in a session.</P><!--TOC subsubsection Checking the server’s response-->
+</TABLE><P>In this case, we use tsung function <TT>ts_dynvars:lookup</TT> to retrieve the
+dynamic variable named <TT>md5data</TT>. This dyn_variable <TT>md5data</TT>
+can be set in any of the ways described in the Dynamic variables
+section <A HREF="#Dynamic variables">6.7.3</A>.</P></LI></OL><P>A <TT>setdynvars</TT> can be defined anywhere in a session.</P><!--TOC subsubsection Checking the server’s response-->
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc66">6.7.4</A>  Checking the server’s response</H4><!--SEC END --><P>With the tag <TT>match</TT> in a <TT>request</TT> tag, you can check
the server’s response against a given string, and do some actions
depending on the result. In any case, if it matches, this will
@@ -2680,8 +2725,8 @@ <H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc66">6.7.4</A>  Checki
</TD></TR>
</TABLE></TD></TR>
</TABLE></TD></TR>
-</TABLE><!--TOC subsubsection Loops, If-->
-<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc67">6.7.5</A>  Loops, If</H4><!--SEC END --><P><B>Since 1.3.0</B>, it’s now possible to add conditional/unconditional loops in a session:</P><!--TOC paragraph &lt;for&gt;-->
+</TABLE><!--TOC subsubsection Loops, If, Foreach-->
+<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc67">6.7.5</A>  Loops, If, Foreach</H4><!--SEC END --><P><B>Since 1.3.0</B>, it’s now possible to add conditional/unconditional loops in a session.</P><P><B>Since 1.4.0</B>, it is possible to loop through a list of dynamic variables thanks to foreach.</P><!--TOC paragraph &lt;for&gt;-->
<H5 CLASS="paragraph"><!--SEC ANCHOR -->&lt;for&gt;</H5><!--SEC END --><P>Repeat the enclosing actions a fixed number of times. A dynamic
variable is used as counter, so the current iteration could be used in
requests. List of attributes:</P><DL CLASS="description"><DT CLASS="dt-description">
@@ -2763,7 +2808,80 @@ <H5 CLASS="paragraph"><!--SEC ANCHOR -->&lt;if&gt;</H5><!--SEC END --><TABLE BOR
</TD></TR>
</TABLE></TD></TR>
</TABLE></TD></TR>
-</TABLE><P>You can use <TT>eq</TT> or <TT>neq</TT> to check the variable.</P><!--TOC section Statistics and reports-->
+</TABLE><P>You can use <TT>eq</TT> or <TT>neq</TT> to check the variable.</P><!--TOC paragraph &lt;foreach&gt;-->
+<H5 CLASS="paragraph"><!--SEC ANCHOR -->&lt;foreach&gt;</H5><!--SEC END --><P>Repeat the enclosing actions for all the elements contained in the list specified. The basic syntax is as follows:</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
+CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD><TD><TABLE BORDER=0 CELLPADDING="1" CELLSPACING=0><TR><TD><PRE CLASS="verbatim">&lt;foreach name="element" in="list"&gt;
+ &lt;request subst="true"&gt;
+ &lt;http url="%%_element%%" method="GET" version="1.1"/&gt;
+ &lt;/request&gt;
+&lt;/foreach&gt;
+</PRE></TD></TR>
+</TABLE></TD><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+</TABLE></TD></TR>
+</TABLE><P>It is possible to limit the list of elements you’re looping through, thanks to the use of the <FONT COLOR=purple>include</FONT> or <FONT COLOR=purple>exclude</FONT> attributes inside the foreach statement.</P><P>As an example, if you want to include only elements with a local path you can write:</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
+CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD><TD><TABLE BORDER=0 CELLPADDING="1" CELLSPACING=0><TR><TD><PRE CLASS="verbatim">&lt;foreach name="element" in="list" include="^/.*$"&gt;
+</PRE></TD></TR>
+</TABLE></TD><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+</TABLE></TD></TR>
+</TABLE><P>If you want to exclude all the elements from a specific URI, you would write:</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
+CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD><TD><TABLE BORDER=0 CELLPADDING="1" CELLSPACING=0><TR><TD><PRE CLASS="verbatim">&lt;foreach name="element" in="list" exclude="http:\/\/.*\.tld\.com\/.*$"&gt;
+</PRE></TD></TR>
+</TABLE></TD><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+</TABLE></TD></TR>
+</TABLE><P>You can combine this with a xpath query. For instance the following scenario will retrieve all the images specified on a web page:</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
+CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD><TD><TABLE BORDER=0 CELLPADDING="1" CELLSPACING=0><TR><TD><PRE CLASS="verbatim">&lt;request subst="true"&gt;
+ &lt;dyn_variable name="img_list" xpath="//img/@src"/&gt;
+ &lt;http url="/mypage.html" method="GET" version="1.1"/&gt;
+&lt;/request&gt;
+&lt;foreach name="img" in="img_list"&gt;
+ &lt;request subst="true"&gt;
+ &lt;http url="%%_img%%" method="GET" version="1.1"/&gt;
+ &lt;/request&gt;
+&lt;/foreach&gt;
+</PRE></TD></TR>
+</TABLE></TD><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+<TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
+</TD></TR>
+</TABLE></TD></TR>
+</TABLE></TD></TR>
+</TABLE><!--TOC section Statistics and reports-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc68">7</A>  Statistics and reports</H2><!--SEC END --><P>
<A NAME="sec:statistics-reports"></A></P><!--TOC subsection Available stats-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc69">7.1</A>  Available stats</H3><!--SEC END --><UL CLASS="itemize"><LI CLASS="li-itemize">
@@ -2849,6 +2967,8 @@ <H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc71">7.3</A>  Generating
[--tdir &lt;template_dir&gt;] (Path to the HTML tsung templates)
[--noextra (don't generate graphics from extra data (os monitor, etc)
[--stats &lt;file&gt;] (stats file to analyse, default=tsung.log)
+ [--img_format &lt;format&gt;] (output format for images, default=png
+ available format: ps, svg, png, pdf)
</PRE></TD></TR>
</TABLE></TD><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
</TD></TR>
@@ -3197,7 +3317,8 @@ <H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc84">A.6</A>  What is the
response time ?-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc85">A.7</A>  How can I compute percentile/quartiles/median for transactions or requests
response time ?</H3><!--SEC END --><P>It’s not directly possible. But since <B>version 1.3.0</B>, you can
-use a new experimental statistic backend: set <FONT COLOR=purple>backend="fullstats"</FONT></P><P>This will print every statistics data in a raw format in a file named
+use a new experimental statistic backend: set <FONT COLOR=purple>backend="fullstats"</FONT> in the
+<FONT COLOR=purple>&lt;tsung&gt;</FONT> section of your configuration file.</P><P>This will print every statistics data in a raw format in a file named
<TT>tsung-fullstats.log</TT>. <B>Warning</B>: this may impact the performance of
the controller node (a lot of data has to be written to disk).</P><P>The data looks like:
</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
@@ -3326,7 +3447,17 @@ <H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc89">C</A>  CHANGELOG</H2><!
CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
</TD></TR>
</TABLE></TD></TR>
-<TR><TD><TABLE BORDER=0 CELLPADDING="1" CELLSPACING=0><TR><TD><PRE CLASS="verbatim"><I>1.3.1 -&gt; 1.3.2 Major bugfixes and enhancements (14 Jun 2010)
+<TR><TD><TABLE BORDER=0 CELLPADDING="1" CELLSPACING=0><TR><TD><PRE CLASS="verbatim"><I>1.3.2 -&gt; 1.3.3 Minor bugfixes (17 Aug 2010)
+Bugfix:
+ * [TSUN-154] - parent proxy doesn't work anymore in 1.3.x (tested with 1.3.2 and 1.3.0).
+ * [TSUN-155] - url substitution is broken in some cases
+ * [TSUN-156] - Tsung not using sessions with low probabilities
+ * [TSUN-157] - ssl doesn't work with erlang R14A
+ * [TSUN-158] - failure when a proxy is used and an URL substitution is set
+ * [TSUN-159] - HTTP cookies support is broken when a proxy is used
+ * [TSUN-160] - tsung can sometimes hang at the beginning using distributed setup
+ * [TSUN-161] - if statement not allowed in a transaction
+1.3.1 -&gt; 1.3.2 Major bugfixes and enhancements (14 Jun 2010)
Bugfix:
* [TSUN-128] - Apostrophes cause string to convert to deep list in setdynvars with Erlang function.
* [TSUN-130] - static users starting time is wrong
92 doc/user_manual.tex
View
@@ -14,7 +14,7 @@
%\addauthor{Nicolas}{Niclausse}{nicolas.niclausse@niclux.org}
\doccopyright{Nicolas Niclausse.}
-\docversion{1.3.2}
+\docversion{1.3.3}
\docreldate{\date{}}
\docref{tsung-user-manual}
@@ -1091,6 +1091,12 @@ \subsubsection{Thinktimes}
<thinktime min="2" max="10" random="true"></thinktime>
\end{Verbatim}
+\strong{Since version 1.4.0}, you can use a dynamic variable to set
+the thinktime value:
+\begin{Verbatim}
+<thinktime value='%%_rndthink%%' random='true'></thinktime>
+\end{Verbatim}
+
\subsubsection{HTTP}
@@ -1140,6 +1146,12 @@ \subsubsection{HTTP}
</sessions>
\end{Verbatim}
+
+If you use an absolute URL, the server used in the URL will override
+the one specified in the \varname{<server>} section. The following relative
+requests in the session will also use this new server value (until a
+new absolute URL is set).
+
\strong{New in 1.2.2:} You can add any HTTP header now, as in:
\begin{Verbatim}
<request>
@@ -1434,7 +1446,7 @@ \subsubsection{Jabber/XMPP}
same probability).
\paragraph{raw XML}
-You can send raw XML date to the server using the \varname{raw} type:
+You can send raw XML data to the server using the \varname{raw} type:
\begin{Verbatim}
<jabber type="raw" ack="no_ack" data="&lt;stream&gt;foo&lt;/stream&gt;"></jabber>
\end{Verbatim}
@@ -1848,7 +1860,7 @@ \subsubsection{Reading external file}
Much simpler than the old method !
-\subsubsection{Dynamic variables}
+\subsubsection{Dynamic variables}\label{Dynamic variables}
In some cases, you may want to use a value given by the server in a
response later in the session, and this value is \strong{dynamically
@@ -1888,7 +1900,21 @@ \subsubsection{Dynamic variables}
\paragraph{Regexp}
If the dynamic value is not a form variable, you can set a regexp by
-hand, for example to get the title of a HTML page:
+hand, for example to get the title of a HTML page: the regexp engine
+uses the \varname{re} module, a Perl like regular expressions module
+for Erlang.
+
+\begin{Verbatim}
+ <request>
+ <dyn_variable name="mytitlevar"
+ re="&lt;title&gt;(.*)&lt;/title&gt;"/>
+ <http url="/testtsung.html" method="GET" version="1.0"></http>
+ </request>
+\end{Verbatim}
+
+
+Previously (before 1.4.0), Tsung uses the old \varname{regexp} module
+from erlang. This is now deprecated. The syntax was:
\begin{Verbatim}
<request>
<dyn_variable name="mytitlevar"
@@ -1930,6 +1956,8 @@ \subsubsection{Dynamic variables}
Basic tests shows a x4 improvement in speed over the \emph{regexp} implementation.
+It is possible to use Xpath to get a list of elements from an html page, allowing dynamic retrieval of objects. You can either create embedded erlang code to parse the list produced, or use foreach that was introduced in release \strong(1.4.0).
+
\paragraph{JSONPath}
Another way to analyze the server response has been introduced in the
@@ -2042,6 +2070,11 @@ \subsubsection{Dynamic variables}
</setdynvars>
\end{Verbatim}
+In this case, we use tsung function \varname{ts\_dynvars:lookup} to retrieve the
+dynamic variable named \varname{md5data}. This dyn\_variable \varname{md5data}
+can be set in any of the ways described in the Dynamic variables
+section \ref{Dynamic variables}.
+
\end{enumerate}
A \varname{setdynvars} can be defined anywhere in a session.
@@ -2111,9 +2144,11 @@ \subsubsection{Checking the server's response}
<http url="/" method="GET"/>
\end{Verbatim}
-\subsubsection{Loops, If}
+\subsubsection{Loops, If, Foreach}
-\strong{Since 1.3.0}, it's now possible to add conditional/unconditional loops in a session:
+\strong{Since 1.3.0}, it's now possible to add conditional/unconditional loops in a session.
+
+\strong{Since 1.4.0}, it is possible to loop through a list of dynamic variables thanks to foreach.
\paragraph{<for>}
@@ -2176,6 +2211,46 @@ \subsubsection{Loops, If}
You can use \varname{eq} or \varname{neq} to check the variable.
+\paragraph{<foreach>}
+
+Repeat the enclosing actions for all the elements contained in the list specified. The basic syntax is as follows:
+
+\begin{Verbatim}
+<foreach name="element" in="list">
+ <request subst="true">
+ <http url="%%_element%%" method="GET" version="1.1"/>
+ </request>
+</foreach>
+\end{Verbatim}
+
+It is possible to limit the list of elements you're looping through, thanks to the use of the \userinput{include} or \userinput{exclude} attributes inside the foreach statement.
+
+As an example, if you want to include only elements with a local path you can write:
+
+\begin{Verbatim}
+<foreach name="element" in="list" include="^/.*$">
+\end{Verbatim}
+
+If you want to exclude all the elements from a specific URI, you would write:
+
+\begin{Verbatim}
+<foreach name="element" in="list" exclude="http:\/\/.*\.tld\.com\/.*$">
+\end{Verbatim}
+
+You can combine this with a xpath query. For instance the following scenario will retrieve all the images specified on a web page:
+
+\begin{Verbatim}
+<request subst="true">
+ <dyn_variable name="img_list" xpath="//img/@src"/>
+ <http url="/mypage.html" method="GET" version="1.1"/>
+</request>
+<foreach name="img" in="img_list">
+ <request subst="true">
+ <http url="%%_img%%" method="GET" version="1.1"/>
+ </request>
+</foreach>
+\end{Verbatim}
+
\section{Statistics and reports}
\label{sec:statistics-reports}
@@ -2272,6 +2347,8 @@ \subsection{Generating the report}
[--tdir <template_dir>] (Path to the HTML tsung templates)
[--noextra (don't generate graphics from extra data (os monitor, etc)
[--stats <file>] (stats file to analyse, default=tsung.log)
+ [--img_format <format>] (output format for images, default=png
+ available format: ps, svg, png, pdf)
\end{Verbatim}
\subsection{Tsung summary}
@@ -2561,7 +2638,8 @@ \subsection{How can I compute percentile/quartiles/median for transactions or re
response time ?}
It's not directly possible. But since \strong{version 1.3.0}, you can
-use a new experimental statistic backend: set \userinput{backend="fullstats"}
+use a new experimental statistic backend: set \userinput{backend="fullstats"} in the
+\userinput{<tsung>} section of your configuration file.
This will print every statistics data in a raw format in a file named
\file{tsung-fullstats.log}. \strong{Warning}: this may impact the performance of
7 include/ts_config.hrl
View
@@ -33,6 +33,9 @@
-define(DEF_REGEXP_DYNVAR_BEGIN, "name=(\"|')").%'
-define(DEF_REGEXP_DYNVAR_END, "(\"|') ([^>]* )?value=(\"|')\\([^(\"|')]*\\)(\"|')").%'
+-define(DEF_RE_DYNVAR_BEGIN, "name=[\"']").%'
+-define(DEF_RE_DYNVAR_END, "[\"'] (?:[^>]* )?value=[\"']([^\"']*)[\"']").%'
+
-record(config, {
name,
duration, % max duration of test (by default: end when all clients are done)
@@ -96,7 +99,7 @@
{phase,
duration,
unit,
- number, %% ?
intensity,
- maxnumber
+ maxnumber,
+ curnumber = 0
}).
7 include/ts_http.hrl
View
@@ -71,12 +71,13 @@
%% the parsing of the response
-record(http, {content_length= 0, % HTTP header: content length
body_size = 0, % current size of body,
- chunk_toread = -1, % chunk data to be read (-1 = not chunked)
- status = none, % HTTP resp. status :200, etc. 'none'
+ chunk_toread = -1, % chunk data to be read (-1 = not chunked, -2 = not chunked, but last response was)
+ status = {none,none}, % HTTP resp. status :200, etc. 'none'
% if no current cnx.
close = false, % true if HTTP/1.0 or 'connection: close'
% has been received
partial=false, % true if headers are partially received
+ compressed={false,false}, % type of compression if body is compressed
cookie=[]
}).
@@ -107,3 +108,5 @@
-define(USER_AGENT, "Tsung").
-define(USER_AGENT_ERROR_MSG, "Total sum of user agents frequency is not equal to 100").
+-define(MAX_HEADER_SIZE, 65536). % used for http_chunk:decode
+
3  include/ts_jabber.hrl
View
@@ -24,13 +24,14 @@
-vc('$Id$ ').
-author('nicolas.niclausse@niclux.org').
--record(jabber_dyndata, {id}).
+-record(jabber_dyndata, {id, regexp}).
-record(jabber, {dest,
size,
data,
type,
jud_param,
+ regexp,
cle,
id = 0,
domain, %% jabber domain
47 include/ts_shell.hrl
View
@@ -0,0 +1,47 @@
+%%%
+%%% Copyright 2010 © INRIA
+%%%
+%%% Author : Nicolas Niclausse <nniclaus@sophia.inria.fr>
+%%% Created: 13 january 2010 by Nicolas Niclausse <nniclaus@sophia.inria.fr>
+%%%
+%%% This program is free software; you can redistribute it and/or modify
+%%% it under the terms of the GNU General Public License as published by
+%%% the Free Software Foundation; either version 2 of the License, or
+%%% (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%%% GNU General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License
+%%% along with this program; if not, write to the Free Software
+%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+%%%
+%%% In addition, as a special exception, you have the permission to
+%%% link the code of this program with any library released under
+%%% the EPL license and distribute linked combinations including
+%%% the two.
+
+
+-vc('$Id$ ').
+-author('nicolas.niclausse@niclux.org').
+
+%% use by the client to create the request
+
+-record(shell_dyndata,
+ {
+ fixme
+ }
+ ).
+
+-record(shell, {
+ command,
+ args
+ }).
+
+-record(shell_sess, {
+ fixme
+ }).
+
+
2  src/lib/mochijson2.erl
View
@@ -510,8 +510,8 @@ tokenize(B, S=#decoder{offset=O}) ->
%%
%% Tests
%%
--include_lib("eunit/include/eunit.hrl").
-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
%% testing constructs borrowed from the Yaws JSON implementation.
949 src/lib/snmp_mgr.erl
View
@@ -1,949 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(snmp_mgr).
-
-%%----------------------------------------------------------------------
-%% This module implements a simple SNMP manager for Erlang.
-%%----------------------------------------------------------------------
-
-%% c(snmp_mgr).
-%% snmp_mgr:start().
-%% snmp_mgr:g([[sysContact,0]]).
-
-%% snmp_mgr:start([{engine_id, "mbjk's engine"}, v3, {agent, "clip"}, {mibs, ["../mibs/SNMPv2-MIB"]}]).
-
-%% snmp_mgr:start([{engine_id, "agentEngine"}, {user, "iwl_test"}, {dir, "mgr_conf"}, {sec_level, authPriv}, v3, {agent, "clip"}]).
-
-%% User interface
--export([start_link/1, start/1, stop/0,
- d/0, g/1, s/1, gn/1, gn/0, r/0, gb/3, rpl/1,
- send_bytes/1,
- expect/2,expect/3,expect/4,expect/6,get_response/2,
- receive_response/0,
- oid_to_name/1, name_to_oid/1]).
-
-%% Internal exports
--export([get_oid_from_varbind/1,
- var_and_value_to_varbind/2, flatten_oid/2, make_vb/1]).
--export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
-
--include_lib("snmp/include/snmp_types.hrl").
--include_lib("snmp/src/misc/snmp_debug.hrl").
--include_lib("snmp/include/STANDARD-MIB.hrl").
-
--record(state,{dbg = true,
- quiet,
- parent,
- timeout = 3500,
- print_traps = true,
- mini_mib,
- packet_server,
- last_sent_pdu,
- last_received_pdu}).
-
-start_link(Options) ->
- gen_server:start_link({local, snmp_mgr}, snmp_mgr, {Options, self()}, []).
-
-start(Options) ->
- gen_server:start({local, snmp_mgr}, snmp_mgr, {Options, self()}, []).
-
-stop() ->
- gen_server:call(snmp_mgr, stop, infinity).
-
-d() ->
- gen_server:call(snmp_mgr,discovery,infinity).
-
-g(Oids) ->
- snmp_mgr ! {get, Oids}, ok.
-
-%% VarsAndValues is: {PlainOid, o|s|i, Value} (unknown mibs) | {Oid, Value}
-s(VarsAndValues) ->
- snmp_mgr ! {set, VarsAndValues}, ok.
-
-gn(Oids) when list(Oids) ->
- snmp_mgr ! {get_next, Oids}, ok;
-gn(N) when integer(N) ->
- snmp_mgr ! {iter_get_next, N}, ok.
-gn() ->
- snmp_mgr ! iter_get_next, ok.
-
-r() ->
- snmp_mgr ! resend_pdu, ok.
-
-gb(NonRepeaters, MaxRepetitions, Oids) ->
- snmp_mgr ! {bulk, {NonRepeaters, MaxRepetitions, Oids}}, ok.
-
-rpl(RespPdu) ->
- snmp_mgr ! {response, RespPdu}.
-
-send_bytes(Bytes) ->
- snmp_mgr ! {send_bytes, Bytes}, ok.
-
-oid_to_name(Oid) ->
- gen_server:call(snmp_mgr, {oid_to_name, Oid}, infinity).
-
-name_to_oid(Name) ->
- gen_server:call(snmp_mgr, {name_to_oid, Name}, infinity).
-
-
-%%----------------------------------------------------------------------
-%% Purpose: For writing test sequences
-%% Args: Y=any (varbinds) | trap | timeout | VarBinds | ErrStatus
-%% Returns: ok|{error, Id, Reason}
-%%----------------------------------------------------------------------
-expect(Id,Y) -> echo_errors(expect_impl(Id,Y)).
-expect(Id,v2trap,VBs) -> echo_errors(expect_impl(Id,v2trap,VBs));
-expect(Id,report,VBs) -> echo_errors(expect_impl(Id,report,VBs));
-expect(Id,{inform, Reply},VBs) ->
- echo_errors(expect_impl(Id,{inform,Reply},VBs)).
-expect(Id,Err,Idx,VBs) -> echo_errors(expect_impl(Id,Err,Idx,VBs)).
-expect(Id,trap, Enterp, Generic, Specific, ExpectedVarbinds) ->
- echo_errors(expect_impl(Id,trap,Enterp,Generic,
- Specific,ExpectedVarbinds)).
-
-%%-----------------------------------------------------------------
-%% Purpose: For writing test sequences
-%%-----------------------------------------------------------------
-get_response(Id, Vars) -> echo_errors(get_response_impl(Id, Vars)).
-
-%%----------------------------------------------------------------------
-%% Receives a response from the agent.
-%% Returns: a PDU or {error, Reason}.
-%% It doesn't receive traps though.
-%%----------------------------------------------------------------------
-receive_response() ->
- receive_response(get_timeout()).
-
-receive_response(Timeout) ->
- d("await reponse within ~w ms",[Timeout]),
- receive
- {snmp_pdu, PDU} when record(PDU, pdu) ->
- d("received PDU: ~n\t~p",[PDU]),
- PDU
- after Timeout ->
- d("response timeout",[]),
- {error, timeout}
- end.
-
-
-get_timeout() ->
- get_timeout(os:type()).
-
-get_timeout(vxworks) -> 7000;
-get_timeout(_) -> 3500.
-
-%%----------------------------------------------------------------------
-%% Receives a trap from the agent.
-%% Returns: TrapPdu|{error, Reason}
-%%----------------------------------------------------------------------
-receive_trap(Timeout) ->
- d("await trap within ~w ms",[Timeout]),
- receive
- {snmp_pdu, PDU} when record(PDU, trappdu) ->
- d("received trap-PDU: ~n\t~p",[PDU]),
- PDU
- after Timeout ->
- d("trap timeout",[]),
- {error, timeout}
- end.
-
-%%----------------------------------------------------------------------
-%% Options: List of
-%% {agent_udp, UDPPort}, {agent, Agent}
-%% Optional:
-%% {community, String ("public" is default}, quiet,
-%% {mibs, List of Filenames}, {trap_udp, UDPPort (default 5000)},
-%%----------------------------------------------------------------------
-init({Options, CallerPid}) ->
- {A1,A2,A3} = erlang:now(),
- random:seed(A1,A2,A3),
- case (catch is_options_ok(Options)) of
- true ->
- put(debug,get_value(debug,Options,false)),
- d("init -> (~p) extract options",[self()]),
- PacksDbg = get_value(packet_server_debug,Options,false),
- RecBufSz = get_value(recbuf,Options,1024),
- Mibs = get_value(mibs, Options, []),
- Udp = get_value(agent_udp, Options, 4000),
- User = get_value(user, Options, "initial"),
- EngineId = get_value(engine_id, Options, "agentEngine"),
- CtxEngineId = get_value(context_engine_id, Options, EngineId),
- TrapUdp = get_value(trap_udp, Options, 5000),
- Dir = get_value(dir, Options, "."),
- SecLevel = get_value(sec_level, Options, noAuthNoPriv),
- MiniMIB = case ts_utils:release_is_newer_or_eq("5.5") of
- true ->
- snmp_mini_mib:create(Mibs);
- false ->
- snmp_misc:make_mini_mib(Mibs)
- end,
- Version = case lists:member(v2,Options) of
- true -> 'version-2';
- false ->
- case lists:member(v3,Options) of
- true -> 'version-3';
- false -> 'version-1'
- end
- end,
- Com = case Version of
- 'version-3' ->
- get_value(context, Options, "");
- _ ->
- get_value(community, Options, "public")
- end,
- VsnHdrD =
- {Com, User, EngineId, CtxEngineId, mk_seclevel(SecLevel)},
- AgIp = case snmp_misc:assq(agent, Options) of
- {value, Tuple4} when tuple(Tuple4),size(Tuple4)==4 ->
- Tuple4;
- {value, Host} when list(Host) ->
- {ok, Ip} = snmp_misc:ip(Host),
- Ip
- end,
- Quiet = lists:member(quiet, Options),
- PackServ = start_packet_server(Quiet, Options, CallerPid,
- AgIp, Udp, TrapUdp,
- VsnHdrD, Version, Dir, RecBufSz,
- PacksDbg),
- d("init -> packet server: ~p",[PackServ]),
- State = #state{parent = CallerPid,
- quiet = Quiet,
- mini_mib = MiniMIB,
- packet_server = PackServ},
- d("init -> done",[]),
- {ok, State};
-
- {error, Reason} ->
- {stop,Reason}
- end.
-
-start_packet_server(false, _Options, _CallerPid, AgIp, Udp, TrapUdp,
- VsnHdrD, Version, Dir, RecBufSz, PacksDbg) ->
- d("start_packet_server -> entry", []),
- snmp_mgr_misc:start_link_packet({msg, self()},
- AgIp, Udp, TrapUdp,
- VsnHdrD, Version, Dir, RecBufSz,
- PacksDbg);
-start_packet_server(true, Options, CallerPid, AgIp, Udp, TrapUdp,
- VsnHdrD, Version, Dir, RecBufSz, PacksDbg) ->
- Type = get_value(receive_type, Options, pdu),
- d("start_packet_server -> entry with"
- "~n CallerPid: ~p"
- "~n when"
- "~n Type: ~p",[CallerPid, Type]),
- snmp_mgr_misc:start_link_packet({Type, CallerPid},
- AgIp, Udp, TrapUdp,
- VsnHdrD, Version, Dir, RecBufSz,
- PacksDbg).
-
-is_options_ok([{mibs,List}|Opts]) when list(List) ->
- is_options_ok(Opts);
-is_options_ok([quiet|Opts]) ->
- is_options_ok(Opts);
-is_options_ok([{agent,_}|Opts]) ->
- is_options_ok(Opts);
-is_options_ok([{agent_udp,Int}|Opts]) when integer(Int) ->
- is_options_ok(Opts);
-is_options_ok([{trap_udp,Int}|Opts]) when integer(Int) ->
- is_options_ok(Opts);
-is_options_ok([{community,List}|Opts]) when list(List) ->
- is_options_ok(Opts);
-is_options_ok([{dir,List}|Opts]) when list(List) ->
- is_options_ok(Opts);
-is_options_ok([{sec_level,noAuthNoPriv}|Opts]) ->
- is_options_ok(Opts);
-is_options_ok([{sec_level,authNoPriv}|Opts]) ->
- is_options_ok(Opts);
-is_options_ok([{sec_level,authPriv}|Opts]) ->
- is_options_ok(Opts);
-is_options_ok([{context,List}|Opts]) when list(List) ->
- is_options_ok(Opts);
-is_options_ok([{user,List}|Opts]) when list(List) ->
- is_options_ok(Opts);
-is_options_ok([{engine_id,List}|Opts]) when list(List) ->
- is_options_ok(Opts);
-is_options_ok([{context_engine_id,List}|Opts]) when list(List) ->
- is_options_ok(Opts);
-is_options_ok([v1|Opts]) ->
- is_options_ok(Opts);
-is_options_ok([v2|Opts]) ->
- is_options_ok(Opts);
-is_options_ok([v3|Opts]) ->
- is_options_ok(Opts);
-is_options_ok([{debug,Bool}|Opts]) ->
- case is_bool(Bool) of
- ok ->
- is_options_ok(Opts);
- error ->
- {error, {bad_option, debug, Bool}}
- end;
-is_options_ok([{packet_server_debug,Bool}|Opts]) ->
- case is_bool(Bool) of
- ok ->
- is_options_ok(Opts);
- error ->
- {error, {bad_option, packet_server_debug, Bool}}
- end;
-is_options_ok([{recbuf,Sz}|Opts]) when 0 < Sz, Sz =< 65535 ->
- is_options_ok(Opts);
-is_options_ok([{receive_type, msg}|Opts]) ->
- is_options_ok(Opts);
-is_options_ok([{receive_type, pdu}|Opts]) ->
- is_options_ok(Opts);
-is_options_ok([InvOpt|_]) ->
- {error,{invalid_option,InvOpt}};
-is_options_ok([]) -> true.
-
-is_bool(true) -> ok;
-is_bool(false) -> ok;
-is_bool(_) -> error.
-
-mk_seclevel(noAuthNoPriv) -> 0;
-mk_seclevel(authNoPriv) -> 1;
-mk_seclevel(authPriv) -> 3.
-
-
-handle_info({get, Oids}, State) ->
- d("handle_info -> get request for ~p",[Oids]),
- {noreply, execute_request(get, Oids, State)};
-
-handle_info({set, VariablesAndValues}, State) ->
- d("handle_info -> set request for ~p",[VariablesAndValues]),
- {noreply, execute_request(set, VariablesAndValues, State)};
-
-handle_info({bulk, Args}, State) ->
- d("handle_info -> bulk request for ~p",[Args]),
- {noreply, execute_request(bulk, Args, State)};
-
-handle_info({response, RespPdu}, State) ->
- d("handle_info -> response request with ~p",[RespPdu]),
- snmp_mgr_misc:send_pdu(RespPdu, State#state.packet_server),
- {noreply, State};
-
-handle_info({snmp_msg, Msg, Ip, Udp}, State) ->
- io:format("* Got PDU: ~s", [snmp_mgr_misc:format_hdr(Msg)]),
- PDU = snmp_mgr_misc:get_pdu(Msg),
- echo_pdu(PDU, State#state.mini_mib),
- case PDU#pdu.type of
- 'inform-request' ->
- %% Generate a response...
- RespPDU = PDU#pdu{type = 'get-response',
- error_status = noError,
- error_index = 0},
- RespMsg = snmp_mgr_misc:set_pdu(Msg, RespPDU),
- snmp_mgr_misc:send_msg(RespMsg, State#state.packet_server, Ip, Udp);
- _Else ->
- ok
- end,
- {noreply, State#state{last_received_pdu = PDU}};
-
-handle_info({get_next, Oids}, State) ->
- d("handle_info -> get-next request for ~p",[Oids]),
- {noreply, execute_request(get_next, Oids, State)};
-
-handle_info(resend_pdu, State) ->
- PDU = State#state.last_sent_pdu,
- d("handle_info -> resend_pdu request when last sent pdu: ~n\t~p",[PDU]),
- send_pdu(PDU#pdu{request_id = make_request_id()},
- State#state.mini_mib,
- State#state.packet_server),
- {noreply, State};
-
-handle_info(iter_get_next, State)
- when record(State#state.last_received_pdu, pdu) ->
- d("handle_info -> iter_get_next request",[]),
- PrevPDU = State#state.last_received_pdu,
- Oids = snmp_misc:map({snmp_mgr, get_oid_from_varbind}, [],
- PrevPDU#pdu.varbinds),
- {noreply, execute_request(get_next, Oids, State)};
-
-handle_info(iter_get_next, State) ->
- snmp_mgr_misc:error("[Iterated get-next] No Response PDU to "
- "start iterating from.", []),
- {noreply, State};
-
-handle_info({iter_get_next, N}, State) ->
- d("handle_info -> iter_get_next(~p) request",[N]),
- if
- record(State#state.last_received_pdu, pdu) ->
- PDU = get_next_iter_impl(N, State#state.last_received_pdu,
- State#state.mini_mib,
- State#state.packet_server),
- {noreply, State#state{last_received_pdu = PDU}};
- true ->
- snmp_mgr_misc:error("[Iterated get-next] No Response PDU to "
- "start iterating from.", []),
- {noreply, State}
- end;
-
-handle_info({send_bytes, Bytes}, State) ->
- d("handle_info -> send-bytes request for ~p bytes",
- [sizeOf(Bytes)]),
- snmp_mgr_misc:send_bytes(Bytes, State#state.packet_server),
- {noreply, State}.
-
-
-handle_call({find_pure_oid, XOid}, _From, State) ->
- d("handle_call -> find_pure_oid for ~p",[XOid]),
- {reply, catch flatten_oid(XOid, State#state.mini_mib), State};
-
-handle_call({oid_to_name, Oid}, _From, State) ->
- d("handle_call -> oid_to_name for Oid: ~p",[Oid]),
- Reply =
- case lists:keysearch(Oid, 1, State#state.mini_mib) of
- {value, {_Oid, Name, _Type}} ->
- {ok, Name};
- false ->
- {error, {no_such_oid, Oid}}
- end,
- {reply, Reply, State};
-
-handle_call({name_to_oid, Name}, _From, State) ->
- d("handle_call -> name_to_oid for Name: ~p",[Name]),
- Reply =
- case lists:keysearch(Name, 2, State#state.mini_mib) of
- {value, {Oid, _Name, _Type}} ->
- {ok, Oid};
- false ->
- {error, {no_such_name, Name}}
- end,
- {reply, Reply, State};
-
-handle_call(stop, _From, State) ->
- d("handle_call -> stop request",[]),
- {stop, normal, ok, State};
-
-handle_call(discovery, _From, State) ->
- d("handle_call -> discovery",[]),
- {Reply, NewState} = execute_discovery(State),
- {reply, Reply, NewState}.
-
-handle_cast(Msg, State) ->
- d("handle_cast -> unknown message: ~n\t~p",[Msg]),
- {noreply, State}.
-
-terminate(Reason, State) ->
- d("terminate -> with Reason: ~n\t~p",[Reason]),
- snmp_mgr_misc:stop(State#state.packet_server).
-
-
-%%----------------------------------------------------------------------
-%% Returns: A new State
-%%----------------------------------------------------------------------
-execute_discovery(State) ->
- Pdu = make_discovery_pdu(),
- Reply = snmp_mgr_misc:send_discovery_pdu(Pdu,State#state.packet_server),
- {Reply,State#state{last_sent_pdu = Pdu}}.
-
-
-execute_request(Operation, Data, State) ->
- case (catch make_pdu(Operation, Data, State#state.mini_mib)) of
- {error, {Format, Data2}} ->
- report_error(State, Format, Data2),
- State;
- {error, _Reason} ->
- State;
- PDU when record(PDU, pdu) ->
- send_pdu(PDU, State#state.mini_mib, State#state.packet_server),
- State#state{last_sent_pdu = PDU}
- end.
-
-report_error(#state{quiet = true, parent = Pid}, Format, Args) ->
- Reason = lists:flatten(io_lib:format(Format, Args)),
- Pid ! {oid_error, Reason};
-report_error(_, Format, Args) ->
- snmp_mgr_misc:error(Format, Args).
-
-
-get_oid_from_varbind(#varbind{oid = Oid}) -> Oid.
-
-send_pdu(PDU, _MiniMIB, PackServ) ->
- snmp_mgr_misc:send_pdu(PDU, PackServ).
-
-%%----------------------------------------------------------------------
-%% Purpose: Unnesting of oids like [myTable, 3, 4, "hej", 45] to
-%% [1,2,3,3,4,104,101,106,45]
-%%----------------------------------------------------------------------
-flatten_oid(XOid, DB) ->
- Oid2 = case XOid of
- [A|T] when atom(A) -> [remove_atom(A, DB)|T];
- L when list(L) -> XOid;
- Shit ->
- throw({error,
- {"Invalid oid, not a list of integers: ~w", [Shit]}})
- end,
- check_is_pure_oid(lists:flatten(Oid2)).
-
-remove_atom(AliasName, DB) when atom(AliasName) ->
- case snmp_misc:oid(DB, AliasName) of
- false ->
- throw({error, {"Unknown aliasname in oid: ~w", [AliasName]}});
- Oid -> Oid
- end;
-remove_atom(X, _DB) -> X.
-
-%%----------------------------------------------------------------------
-%% Throws if not a list of integers
-%%----------------------------------------------------------------------
-check_is_pure_oid([]) -> [];
-check_is_pure_oid([X | T]) when integer(X), X >= 0 ->
- [X | check_is_pure_oid(T)];
-check_is_pure_oid([X | _T]) ->
- throw({error, {"Invalid oid, it contains a non-integer: ~w", [X]}}).
-
-get_next_iter_impl(0, PrevPDU, _MiniMIB, _PackServ) -> PrevPDU;
-get_next_iter_impl(N, PrevPDU, MiniMIB, PackServ) ->
- Oids = snmp_misc:map({snmp_mgr, get_oid_from_varbind}, [],
- PrevPDU#pdu.varbinds),
- PDU = make_pdu(get_next, Oids, MiniMIB),
- send_pdu(PDU, MiniMIB, PackServ),
- case receive_response() of
- {error, timeout} ->
- io:format("(timeout)~n"),
- get_next_iter_impl(N, PrevPDU, MiniMIB, PackServ);
- {error, _Reason} ->
- PrevPDU;
- RPDU when record(RPDU, pdu) ->
- io:format("(~w)", [N]),
- echo_pdu(RPDU, MiniMIB),
- get_next_iter_impl(N-1, RPDU, MiniMIB, PackServ)
- end.
-
-%%--------------------------------------------------
-%% Used to resend a PDU. Takes the old PDU and
-%% generates a fresh one (with a new requestID).
-%%--------------------------------------------------
-
-make_pdu(set, VarsAndValues, MiniMIB) ->
- VBs = snmp_misc:map({snmp_mgr, var_and_value_to_varbind}, [MiniMIB],
- VarsAndValues),
- make_pdu_impl(set, VBs);
-make_pdu(bulk, {NonRepeaters, MaxRepetitions, Oids}, MiniMIB) ->
- Foids = snmp_misc:map({snmp_mgr, flatten_oid}, [MiniMIB], Oids),
- #pdu{type = 'get-bulk-request',request_id = make_request_id(),
- error_status = NonRepeaters, error_index = MaxRepetitions,
- varbinds = snmp_misc:map({snmp_mgr, make_vb}, [], Foids)};
-make_pdu(Operation, Oids, MiniMIB) ->
- make_pdu_impl(Operation,
- snmp_misc:map({snmp_mgr, flatten_oid}, [MiniMIB], Oids)).
-
-make_pdu_impl(get, Oids) ->
- #pdu{type = 'get-request',request_id = make_request_id(),
- error_status = noError, error_index = 0,
- varbinds = snmp_misc:map({snmp_mgr, make_vb}, [], Oids)};
-
-make_pdu_impl(get_next, Oids) ->
- #pdu{type = 'get-next-request', request_id = make_request_id(),
- error_status = noError, error_index = 0,
- varbinds = snmp_misc:map({snmp_mgr, make_vb}, [], Oids)};
-
-make_pdu_impl(set, Varbinds) ->
- #pdu{type = 'set-request', request_id = make_request_id(),
- error_status = noError, error_index = 0, varbinds = Varbinds}.
-
-make_discovery_pdu() ->
- #pdu{type = 'get-request',request_id = make_request_id(),
- error_status = noError, error_index = 0,
- varbinds = snmp_misc:map({snmp_mgr, make_vb}, [],
- [?sysDescr_instance])}.
-
-var_and_value_to_varbind({Oid, Type, Value}, MiniMIB) ->
- Oid2 = flatten_oid(Oid, MiniMIB),
- #varbind{oid = Oid2, variabletype = char_to_type(Type), value = Value};
-var_and_value_to_varbind({XOid, Value}, MiniMIB) ->
- Oid = flatten_oid(XOid, MiniMIB),
- #varbind{oid = Oid, variabletype = snmp_misc:type(MiniMIB, Oid),
- value = Value}.
-
-char_to_type(o) ->
- 'OBJECT IDENTIFIER';
-char_to_type(i) ->
- 'INTEGER';
-char_to_type(u) ->
- 'Unsigned32';
-char_to_type(g) -> % Gauge, Gauge32
- 'Unsigned32';
-char_to_type(s) ->
- 'OCTET STRING'.
-
-make_vb(Oid) ->
- #varbind{oid = Oid, variabletype = 'NULL', value = 'NULL'}.
-
-make_request_id() ->
- random:uniform(16#FFFFFFF-1).
-
-echo_pdu(PDU,MiniMIB) ->
- io:format("~s",[snmp_misc:format_pdu(PDU,MiniMIB)]).
-
-%%----------------------------------------------------------------------
-%% Test Sequence
-%%----------------------------------------------------------------------
-echo_errors({error, Id, {ExpectedFormat, ExpectedData}, {Format, Data}})->
- io:format("* Unexpected Behaviour * Id: ~w.~n"
- " Expected: " ++ ExpectedFormat ++ "~n"
- " Got: " ++ Format ++ "~n",
- [Id] ++ ExpectedData ++ Data),
- {error, Id, {ExpectedFormat, ExpectedData}, {Format, Data}};
-echo_errors(ok) -> ok;
-echo_errors({ok, Val}) -> {ok, Val}.
-
-get_response_impl(Id, Vars) ->
- case receive_response() of
- #pdu{type = 'get-response',
- error_status = noError,
- error_index = 0,
- varbinds = VBs} ->
- match_vars(Id, find_pure_oids2(Vars), VBs, []);
-
- #pdu{type = Type2,
- request_id = ReqId,
- error_status = Err2,
- error_index = Index2} ->
- {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
- ['get-response', noError, 0, ReqId]},
- {"Type: ~w ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
-
- {error, Reason} ->
- format_reason(Id, Reason)
- end.
-
-
-
-%%----------------------------------------------------------------------
-%% Returns: ok | {error, Id, {ExpectedFormat, ExpectedData}, {Format, Data}}
-%%----------------------------------------------------------------------
-expect_impl(Id, any) ->
- case receive_response() of
- PDU when record(PDU, pdu) -> ok;
- {error, Reason} -> format_reason(Id, Reason)
- end;
-
-expect_impl(Id, return) ->
- case receive_response() of
- PDU when record(PDU, pdu) -> {ok, PDU};
- {error, Reason} -> format_reason(Id, Reason)
- end;
-
-expect_impl(Id, trap) ->
- case receive_trap(3500) of
- PDU when record(PDU, trappdu) -> ok;
- {error, Reason} -> format_reason(Id, Reason)
- end;
-
-expect_impl(Id, timeout) ->
- receive
- X -> {error, Id, {"Timeout", []}, {"Message ~w", [X]}}
- after 3500 ->
- ok
- end;
-
-expect_impl(Id, Err) when atom(Err) ->
- case receive_response() of
- #pdu{error_status = Err} ->
- ok;
-
- #pdu{request_id = ReqId,
- error_status = OtherErr} ->
- {error, Id, {"ErrorStatus: ~w, RequestId: ~w", [Err,ReqId]},
- {"ErrorStatus: ~w", [OtherErr]}};
-
- {error, Reason} ->
- format_reason(Id, Reason)
- end;
-
-expect_impl(Id, ExpectedVarbinds) when list(ExpectedVarbinds) ->
- case receive_response() of
- #pdu{type = 'get-response',
- error_status = noError,
- error_index = 0,
- varbinds = VBs} ->
- check_vars(Id, find_pure_oids(ExpectedVarbinds), VBs);
-
- #pdu{type = Type2,
- request_id = ReqId,
- error_status = Err2,
- error_index = Index2} ->
- {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
- ['get-response', noError, 0, ReqId]},
- {"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
-
- {error, Reason} ->
- format_reason(Id, Reason)
- end.
-
-expect_impl(Id, v2trap, ExpectedVarbinds) when list(ExpectedVarbinds) ->
- case receive_response() of
- #pdu{type = 'snmpv2-trap',
- error_status = noError,
- error_index = 0,
- varbinds = VBs} ->
- check_vars(Id, find_pure_oids(ExpectedVarbinds), VBs);
-
- #pdu{type = Type2,
- request_id = ReqId,
- error_status = Err2,
- error_index = Index2} ->
- {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
- ['snmpv2-trap', noError, 0, ReqId]},
- {"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
-
- {error, Reason} ->
- format_reason(Id, Reason)
- end;
-
-expect_impl(Id, report, ExpectedVarbinds) when list(ExpectedVarbinds) ->
- case receive_response() of
- #pdu{type = 'report',
- error_status = noError,
- error_index = 0,
- varbinds = VBs} ->
- check_vars(Id, find_pure_oids(ExpectedVarbinds), VBs);
-
- #pdu{type = Type2,
- request_id = ReqId,
- error_status = Err2,
- error_index = Index2} ->
- {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
- [report, noError, 0, ReqId]},
- {"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
-
- {error, Reason} ->
- format_reason(Id, Reason)
- end;
-
-expect_impl(Id, {inform, Reply}, ExpectedVarbinds) when
- list(ExpectedVarbinds) ->
- Resp = receive_response(),
- case Resp of
- #pdu{type = 'inform-request',
- error_status = noError,
- error_index = 0,
- varbinds = VBs} ->
- case check_vars(Id, find_pure_oids(ExpectedVarbinds), VBs) of
- ok when Reply == true ->
- RespPDU = Resp#pdu{type = 'get-response',
- error_status = noError,
- error_index = 0},
- snmp_mgr:rpl(RespPDU),
- ok;
- ok when element(1, Reply) == error ->
- {error, Status, Index} = Reply,
- RespPDU = Resp#pdu{type = 'get-response',
- error_status = Status,
- error_index = Index},
- snmp_mgr:rpl(RespPDU),
- ok;
- ok when Reply == false ->
- ok;
- Else ->
- Else
- end;
-
- #pdu{type = Type2,
- request_id = ReqId,
- error_status = Err2,
- error_index = Index2} ->
- {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
- ['inform-request', noError, 0, ReqId]},
- {"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
-
- {error, Reason} ->
- format_reason(Id, Reason)
- end.
-
-expect_impl(Id, Err, Index, any) ->
- case receive_response() of
- #pdu{type = 'get-response',
- error_status = Err,
- error_index = Index} ->
- ok;
-
- #pdu{type = 'get-response', error_status = Err} when Index == any ->
- ok;
-
- #pdu{type = 'get-response',
- request_id = ReqId,
- error_status = Err,
- error_index = Idx} when list(Index) ->
- case lists:member(Idx, Index) of
- true ->
- ok;
- false ->
- {error, Id, {"ErrStat: ~w, Idx: ~w, RequestId: ~w",
- [Err, Index, ReqId]},
- {"ErrStat: ~w, Idx: ~w", [Err, Idx]}}
- end;
-
- #pdu{type = Type2,
- request_id = ReqId,
- error_status = Err2,
- error_index = Index2} ->
- {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
- ['get-response', Err, Index, ReqId]},
- {"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
-
- {error, Reason} ->
- format_reason(Id, Reason)
- end;
-
-expect_impl(Id, Err, Index, ExpectedVarbinds) ->
- PureVBs = find_pure_oids(ExpectedVarbinds),
- case receive_response() of
- #pdu{type = 'get-response',
- error_status = Err,
- error_index = Index,
- varbinds = VBs} ->
- check_vars(Id, PureVBs, VBs);
-
- #pdu{type = 'get-response',
- error_status = Err,
- varbinds = VBs} when Index == any ->
- check_vars(Id, PureVBs, VBs);
-
- #pdu{type = 'get-response',
- request_id = ReqId,
- error_status = Err,
- error_index = Idx,
- varbinds = VBs} when list(Index) ->
- case lists:member(Idx, Index) of
- true ->
- check_vars(Id, PureVBs, VBs);
- false ->
- {error,Id,
- {"ErrStat: ~w, Idx: ~w, Varbinds: ~w, RequestId: ~w",
- [Err,Index,PureVBs,ReqId]},
- {"ErrStat: ~w, Idx: ~w, Varbinds: ~w",
- [Err,Idx,VBs]}}
- end;
-
- #pdu{type = Type2,
- request_id = ReqId,
- error_status = Err2,
- error_index = Index2,
- varbinds = VBs} ->
- {error,Id,
- {"Type: ~w, ErrStat: ~w, Idx: ~w, Varbinds: ~w, RequestId: ~w",
- ['get-response',Err,Index,PureVBs,ReqId]},
- {"Type: ~w, ErrStat: ~w Idx: ~w Varbinds: ~w",
- [Type2,Err2,Index2,VBs]}};
-
- {error, Reason} ->
- format_reason(Id, Reason)
- end.
-
-expect_impl(Id, trap, Enterp, Generic, Specific, ExpectedVarbinds) ->
- PureE = find_pure_oid(Enterp),
- case receive_trap(3500) of
- #trappdu{enterprise = PureE,
- generic_trap = Generic,
- specific_trap = Specific,
- varbinds = VBs} ->
- check_vars(Id, find_pure_oids(ExpectedVarbinds), VBs);
-
- #trappdu{enterprise = Ent2,
- generic_trap = G2,
- specific_trap = Spec2,
- varbinds = VBs} ->
- {error, Id,
- {"Enterprise: ~w, Generic: ~w, Specific: ~w, Varbinds: ~w",
- [PureE, Generic, Specific, ExpectedVarbinds]},
- {"Enterprise: ~w, Generic: ~w, Specific: ~w, Varbinds: ~w",
- [Ent2, G2, Spec2, VBs]}};
-
- {error, Reason} ->
- format_reason(Id, Reason)
- end.
-
-format_reason(Id, Reason) ->
- {error, Id, {"?", []}, {"~w", [Reason]}}.
-
-%%----------------------------------------------------------------------
-%% Args: Id, ExpectedVarbinds, GotVarbinds
-%% Returns: ok
-%% Fails: if not ok
-%%----------------------------------------------------------------------
-check_vars(_Id,[], []) ->
- ok;
-check_vars(Id,Vars, []) ->
- {error, Id, {"More Varbinds (~w)", [Vars]}, {"Too few", []}};
-check_vars(Id,[], Varbinds) ->
- {error,Id, {"Fewer Varbinds", []}, {"Too many (~w)", [Varbinds]}};
-check_vars(Id,[{_XOid, any} | Vars], [#varbind{oid = _Oid} |Vbs]) ->
- check_vars(Id,Vars, Vbs);
-check_vars(Id,[{Oid, Val} | Vars], [#varbind{oid = Oid, value = Val} |Vbs]) ->
- check_vars(Id,Vars, Vbs);
-check_vars(Id,[{Oid, Val} | _], [#varbind{oid = Oid, value = Val2} |_]) ->
- {error, Id, {" Varbind: ~w = ~w", [Oid, Val]}, {"Value: ~w", [Val2]}};
-check_vars(Id,[{Oid, _Val} | _], [#varbind{oid = Oid2, value = _Val2} |_]) ->
- {error, Id, {"Oid: ~w", [Oid]}, {"Oid: ~w", [Oid2]}}.
-
-match_vars(Id, [Oid|T], [#varbind{oid = Oid, value = Value} | Vbs], Res) ->
- match_vars(Id, T, Vbs, [Value | Res]);
-match_vars(_Id, [], [], Res) ->
- {ok, lists:reverse(Res)};
-match_vars(Id, [Oid | _], [#varbind{oid = Oid2}], _Res) ->
- {error, Id, {" Oid: ~w", [Oid]}, {"Oid2: ~w", [Oid2]}};
-match_vars(Id, Vars, [], _Res) ->
- {error, Id, {"More Varbinds (~w)", [Vars]}, {"Too few", []}};
-match_vars(Id, [], Varbinds, _Res) ->
- {error,Id, {"Fewer Varbinds", []}, {"Too many (~w)", [Varbinds]}}.
-
-
-
-find_pure_oids([]) -> [];
-find_pure_oids([{XOid, Q}|T]) ->
- [{find_pure_oid(XOid), Q} | find_pure_oids(T)].
-
-find_pure_oids2([]) -> [];
-find_pure_oids2([XOid|T]) ->
- [find_pure_oid(XOid) | find_pure_oids2(T)].
-
-%%----------------------------------------------------------------------
-%% Returns: Oid
-%% Fails: malformed oids
-%%----------------------------------------------------------------------
-find_pure_oid(XOid) ->
- case gen_server:call(snmp_mgr, {find_pure_oid, XOid}, infinity) of
- {error, {Format, Data}} ->
- ok = io:format(Format, Data),
- exit(malformed_oid);
- Oid when list(Oid) -> Oid
- end.
-
-get_value(Opt, Opts, Default) ->
- case snmp_misc:assq(Opt,Opts) of
- {value, C} -> C;
- false -> Default
- end.
-
-
-%%----------------------------------------------------------------------
-%% Debug
-%%----------------------------------------------------------------------
-
-sizeOf(L) when list(L) ->
- length(lists:flatten(L));
-sizeOf(B) when binary(B) ->
- size(B).
-
-d(F,A) -> d(get(debug),F,A).
-
-d(true,F,A) ->
- io:format("MGR_DBG:" ++ F ++ "~n",A);
-d(_,_F,_A) ->
- ok.
713 src/lib/snmp_mgr_misc.erl
View
@@ -1,713 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(snmp_mgr_misc).
-%% c(snmp_mgr_misc).
-
-%% API
--export([start_link_packet/8, start_link_packet/9,
- stop/1,
- send_discovery_pdu/2, send_pdu/2, send_msg/4, send_bytes/2,
- error/2,
- get_pdu/1, set_pdu/2, format_hdr/1]).
-
-%% internal exports
--export([init_packet/10]).
-
--define(SNMP_USE_V3, true).
--include_lib("snmp/include/snmp_types.hrl").
--include_lib("snmp/src/misc/snmp_debug.hrl").
-
--record(mini_mib_elem,{aliasname, oid, type}).
-
-%%----------------------------------------------------------------------
-%% The InHandler process will receive messages on the form {snmp_pdu, Pdu}.
-%%----------------------------------------------------------------------
-start_link_packet(InHandler,
- AgentIp, UdpPort, TrapUdp,
- VsnHdr, Version, Dir, BufSz) ->
- start_link_packet(InHandler,
- AgentIp, UdpPort, TrapUdp,
- VsnHdr, Version, Dir, BufSz,
- false).
-
-start_link_packet(InHandler,
- AgentIp, UdpPort, TrapUdp,
- VsnHdr, Version, Dir, BufSz,
- Dbg) when integer(UdpPort) ->
- Args = [self(), InHandler,
- AgentIp, UdpPort, TrapUdp,
- VsnHdr, Version, Dir, BufSz,
- Dbg],
- proc_lib:start_link(snmp_mgr_misc, init_packet, Args).
-
-stop(Pid) ->
- Pid ! {stop, self()},
- receive
- {Pid, stopped} -> ok
- end.
-
-
-send_discovery_pdu(Pdu, PacketPid) when record(Pdu, pdu) ->
- PacketPid ! {send_discovery_pdu, self(), Pdu},
- await_discovery_response_pdu().
-
-await_discovery_response_pdu() ->
- receive
- {discovery_response,Reply} ->
- Reply;
- _ ->
- await_discovery_response_pdu()
- end.
-
-
-send_pdu(Pdu, PacketPid) when record(Pdu, pdu) ->
- PacketPid ! {send_pdu, Pdu}.
-
-send_msg(Msg, PacketPid, Ip, Udp) when record(Msg, message) ->
- PacketPid ! {send_msg, Msg, Ip, Udp}.
-
-send_bytes(Bytes, PacketPid) ->
- PacketPid ! {send_bytes, Bytes}.
-
-%%--------------------------------------------------
-%% The SNMP encode/decode process
-%%--------------------------------------------------
-init_packet(Parent, SnmpMgr,
- AgentIp, UdpPort, TrapUdp,
- VsnHdr, Version, Dir, BufSz, DbgOptions) ->
- put(sname,mgr_misc),
- init_debug(DbgOptions),
- {ok, UdpId} = gen_udp:open(TrapUdp, [{recbuf,BufSz},{reuseaddr, true}]),
- put(msg_id, 1),
- proc_lib:init_ack(Parent, self()),
- init_usm(Version, Dir),
- packet_loop(SnmpMgr, UdpId, AgentIp, UdpPort, VsnHdr, Version, []).
-
-init_debug(Dbg) when atom(Dbg) ->
- put(debug,Dbg),
- put(verbosity,silence);
-init_debug(DbgOptions) when list(DbgOptions) ->
- case lists:keysearch(debug, 1, DbgOptions) of
- {value, {_, Dbg}} when atom(Dbg) ->
- put(debug,Dbg);
- _ ->
- put(debug, false)
- end,
- case lists:keysearch(verbosity, 1, DbgOptions) of
- {value, {_, Ver}} when atom(ver) ->
- put(verbosity,Ver);
- _ ->
- put(verbosity, silence)
- end,
- ok.
-
-
-packet_loop(SnmpMgr, UdpId, AgentIp, UdpPort, VsnHdr, Version, MsgData) ->
- receive
- {send_discovery_pdu, From, Pdu} ->
- d("packet_loop -> received send_discovery_pdu with"
- "~n From: ~p"
- "~n Pdu: ~p", [From, Pdu]),
- case mk_discovery_msg(Version, Pdu, VsnHdr, "") of
- error ->
- ok;
- {M, B} when list(B) ->
- put(discovery,{M,From}),
- display_outgoing_message(M),
- udp_send(UdpId, AgentIp, UdpPort, B)
- end,
- packet_loop(SnmpMgr,UdpId,AgentIp,UdpPort,VsnHdr,Version,[]);
- {send_pdu, Pdu} ->
- d("packet_loop -> received send_pdu with"
- "~n Pdu: ~p", [Pdu]),
- case mk_msg(Version, Pdu, VsnHdr, MsgData) of
- error ->
- ok;
- B when list(B) ->
- udp_send(UdpId, AgentIp, UdpPort, B)
- end,
- packet_loop(SnmpMgr,UdpId,AgentIp,UdpPort,VsnHdr,Version,[]);
- {send_msg, Msg, Ip, Udp} ->
- d("packet_loop -> received send_msg with"
- "~n Msg: ~p"
- "~n Ip: ~p"
- "~n Udp: ~p", [Msg,Ip,Udp]),
- case catch snmp_pdus:enc_message(Msg) of
- {'EXIT', Reason} ->
- error("Encoding error. Msg: ~w. Reason: ~w",[Msg,Reason]);
- B when list(B) ->
- udp_send(UdpId, Ip, Udp, B)
- end,
- packet_loop(SnmpMgr,UdpId,AgentIp,UdpPort,VsnHdr,Version,[]);
- {udp, UdpId, Ip, UdpPort, Bytes} ->
- d("packet_loop -> received udp with"
- "~n UdpId: ~p"
- "~n Ip: ~p"
- "~n UdpPort: ~p"
- "~n sz(Bytes): ~p", [UdpId, Ip, UdpPort, sz(Bytes)]),
- MsgData3 = handle_udp_packet(Version,erase(discovery),
- UdpId, Ip, UdpPort, Bytes,
- SnmpMgr, AgentIp),
- packet_loop(SnmpMgr,UdpId,AgentIp,UdpPort,VsnHdr,Version,
- MsgData3);
- {send_bytes, B} ->
- d("packet_loop -> received send_bytes with"
- "~n sz(B): ~p", [sz(B)]),
- udp_send(UdpId, AgentIp, UdpPort, B),
- packet_loop(SnmpMgr,UdpId,AgentIp,UdpPort,VsnHdr,Version,[]);
- {stop, Pid} ->
- d("packet_loop -> received stop from ~p", [Pid]),
- gen_udp:close(UdpId),
- Pid ! {self(), stopped},
- exit(normal);
- Other ->
- d("packet_loop -> received unknown"
- "~n ~p", [Other]),
- exit({snmp_packet_got_other, Other})
- end.
-
-
-handle_udp_packet(_V,undefined,UdpId,Ip,UdpPort,Bytes,SnmpMgr,AgentIp) ->
- M =