From d593d23d9acec3467625480a8a027babacec3618 Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Wed, 22 Apr 2009 14:27:55 +0000 Subject: Ticket #706: Merged branch vs-reorg into trunk: - Currently supported platforms are Win32 & WM6 std/pro. - Renamed project test_pjsip with pjsip_test, also source directory 'test-pjsip' to 'test'. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2638 74dad513-b988-da41-8d7b-12977e46ad98 --- build/vs/pjproject-vs8-common-defaults.vsprops | 27 + build/vs/pjproject-vs8-debug-defaults.vsprops | 19 + .../pjproject-vs8-debug-dynamic-defaults.vsprops | 12 + .../vs/pjproject-vs8-debug-static-defaults.vsprops | 12 + build/vs/pjproject-vs8-release-defaults.vsprops | 17 + .../pjproject-vs8-release-dynamic-defaults.vsprops | 12 + .../pjproject-vs8-release-static-defaults.vsprops | 12 + .../vs/pjproject-vs8-win32-common-defaults.vsprops | 20 + .../pjproject-vs8-win32-release-defaults.vsprops | 8 + build/vs/pjproject-vs8-wm6-common-defaults.vsprops | 25 + .../vs/pjproject-vs8-wm6-release-defaults.vsprops | 8 + pjlib-util/build/pjlib_util.vcproj | 829 +++++-- pjlib-util/build/pjlib_util_test.vcproj | 778 +++++-- pjlib/build/pjlib.vcproj | 1673 +++++++++++--- pjlib/build/pjlib_test.vcproj | 826 +++++-- pjmedia/build/pjmedia.vcproj | 691 ++++-- pjmedia/build/pjmedia_audiodev.vcproj | 2004 ++++++++++++++-- pjmedia/build/pjmedia_codec.vcproj | 697 ++++-- pjmedia/build/pjmedia_test.vcproj | 1022 ++++++--- pjnath/build/pjnath.vcproj | 793 +++++-- pjnath/build/pjnath_test.vcproj | 831 ++++--- pjnath/build/pjstun_srv_test.vcproj | 87 +- pjnath/build/pjturn_client.vcproj | 87 +- pjproject-vs8.sln | 1304 +++++++++-- pjsip-apps/build/Samples-vc.mak | 17 +- pjsip-apps/build/pjsua.vcproj | 676 +----- pjsip-apps/build/py_pjsua.vcproj | 88 +- pjsip-apps/build/sample_debug.vcproj | 688 +----- pjsip-apps/build/samples.vcproj | 412 +--- pjsip-apps/src/pjsua_wince/pjsua_wince.cpp | 4 +- pjsip-apps/src/pjsua_wince/pjsua_wince.vcproj | 2136 +++++++++++++++++ pjsip-apps/src/pocketpj/PocketPJ.rc | 4 +- pjsip/build/pjsip_core.vcproj | 698 ++++-- pjsip/build/pjsip_simple.vcproj | 695 ++++-- pjsip/build/pjsip_test.vcproj | 2427 ++++++++++++++++++++ pjsip/build/pjsip_ua.vcproj | 698 ++++-- pjsip/build/pjsua_lib.vcproj | 697 ++++-- pjsip/build/test_pjsip.vcproj | 2175 ------------------ pjsip/src/test-pjsip/dlg_core_test.c | 23 - pjsip/src/test-pjsip/dns_test.c | 618 ----- pjsip/src/test-pjsip/inv_offer_answer_test.c | 677 ------ pjsip/src/test-pjsip/main.c | 90 - pjsip/src/test-pjsip/main_rtems.c | 12 - pjsip/src/test-pjsip/main_win32.c | 1 - pjsip/src/test-pjsip/msg_err_test.c | 101 - pjsip/src/test-pjsip/msg_logger.c | 104 - pjsip/src/test-pjsip/msg_test.c | 2058 ----------------- pjsip/src/test-pjsip/regc_test.c | 1162 ---------- pjsip/src/test-pjsip/test.c | 392 ---- pjsip/src/test-pjsip/test.h | 125 - pjsip/src/test-pjsip/transport_loop_test.c | 127 - pjsip/src/test-pjsip/transport_tcp_test.c | 155 -- pjsip/src/test-pjsip/transport_test.c | 760 ------ pjsip/src/test-pjsip/transport_udp_test.c | 128 -- pjsip/src/test-pjsip/tsx_basic_test.c | 157 -- pjsip/src/test-pjsip/tsx_bench.c | 280 --- pjsip/src/test-pjsip/tsx_uac_test.c | 1450 ------------ pjsip/src/test-pjsip/tsx_uas_test.c | 1656 ------------- pjsip/src/test-pjsip/txdata_test.c | 847 ------- pjsip/src/test-pjsip/uri_test.c | 1091 --------- pjsip/src/test/dlg_core_test.c | 23 + pjsip/src/test/dns_test.c | 618 +++++ pjsip/src/test/inv_offer_answer_test.c | 677 ++++++ pjsip/src/test/main.c | 90 + pjsip/src/test/main_rtems.c | 12 + pjsip/src/test/main_win32.c | 1 + pjsip/src/test/msg_err_test.c | 101 + pjsip/src/test/msg_logger.c | 104 + pjsip/src/test/msg_test.c | 2058 +++++++++++++++++ pjsip/src/test/regc_test.c | 1162 ++++++++++ pjsip/src/test/test.c | 392 ++++ pjsip/src/test/test.h | 125 + pjsip/src/test/transport_loop_test.c | 127 + pjsip/src/test/transport_tcp_test.c | 155 ++ pjsip/src/test/transport_test.c | 760 ++++++ pjsip/src/test/transport_udp_test.c | 128 ++ pjsip/src/test/tsx_basic_test.c | 157 ++ pjsip/src/test/tsx_bench.c | 280 +++ pjsip/src/test/tsx_uac_test.c | 1450 ++++++++++++ pjsip/src/test/tsx_uas_test.c | 1656 +++++++++++++ pjsip/src/test/txdata_test.c | 847 +++++++ pjsip/src/test/uri_test.c | 1091 +++++++++ third_party/build/g7221/libg7221codec.vcproj | 1931 +++++++++++++--- third_party/build/gsm/libgsmcodec.vcproj | 822 +++++-- third_party/build/ilbc/libilbccodec.vcproj | 816 +++++-- third_party/build/milenage/libmilenage.vcproj | 689 ++++-- third_party/build/portaudio/libportaudio.vcproj | 797 +++++-- third_party/build/resample/libresample.vcproj | 815 +++++-- third_party/build/resample/libresample_dll.vcproj | 734 +----- third_party/build/speex/libspeex.vcproj | 800 +++++-- third_party/build/srtp/libsrtp.vcproj | 625 +++-- 91 files changed, 33190 insertions(+), 22076 deletions(-) create mode 100644 build/vs/pjproject-vs8-common-defaults.vsprops create mode 100644 build/vs/pjproject-vs8-debug-defaults.vsprops create mode 100644 build/vs/pjproject-vs8-debug-dynamic-defaults.vsprops create mode 100644 build/vs/pjproject-vs8-debug-static-defaults.vsprops create mode 100644 build/vs/pjproject-vs8-release-defaults.vsprops create mode 100644 build/vs/pjproject-vs8-release-dynamic-defaults.vsprops create mode 100644 build/vs/pjproject-vs8-release-static-defaults.vsprops create mode 100644 build/vs/pjproject-vs8-win32-common-defaults.vsprops create mode 100644 build/vs/pjproject-vs8-win32-release-defaults.vsprops create mode 100644 build/vs/pjproject-vs8-wm6-common-defaults.vsprops create mode 100644 build/vs/pjproject-vs8-wm6-release-defaults.vsprops create mode 100644 pjsip-apps/src/pjsua_wince/pjsua_wince.vcproj create mode 100644 pjsip/build/pjsip_test.vcproj delete mode 100644 pjsip/build/test_pjsip.vcproj delete mode 100644 pjsip/src/test-pjsip/dlg_core_test.c delete mode 100644 pjsip/src/test-pjsip/dns_test.c delete mode 100644 pjsip/src/test-pjsip/inv_offer_answer_test.c delete mode 100644 pjsip/src/test-pjsip/main.c delete mode 100644 pjsip/src/test-pjsip/main_rtems.c delete mode 100644 pjsip/src/test-pjsip/main_win32.c delete mode 100644 pjsip/src/test-pjsip/msg_err_test.c delete mode 100644 pjsip/src/test-pjsip/msg_logger.c delete mode 100644 pjsip/src/test-pjsip/msg_test.c delete mode 100644 pjsip/src/test-pjsip/regc_test.c delete mode 100644 pjsip/src/test-pjsip/test.c delete mode 100644 pjsip/src/test-pjsip/test.h delete mode 100644 pjsip/src/test-pjsip/transport_loop_test.c delete mode 100644 pjsip/src/test-pjsip/transport_tcp_test.c delete mode 100644 pjsip/src/test-pjsip/transport_test.c delete mode 100644 pjsip/src/test-pjsip/transport_udp_test.c delete mode 100644 pjsip/src/test-pjsip/tsx_basic_test.c delete mode 100644 pjsip/src/test-pjsip/tsx_bench.c delete mode 100644 pjsip/src/test-pjsip/tsx_uac_test.c delete mode 100644 pjsip/src/test-pjsip/tsx_uas_test.c delete mode 100644 pjsip/src/test-pjsip/txdata_test.c delete mode 100644 pjsip/src/test-pjsip/uri_test.c create mode 100644 pjsip/src/test/dlg_core_test.c create mode 100644 pjsip/src/test/dns_test.c create mode 100644 pjsip/src/test/inv_offer_answer_test.c create mode 100644 pjsip/src/test/main.c create mode 100644 pjsip/src/test/main_rtems.c create mode 100644 pjsip/src/test/main_win32.c create mode 100644 pjsip/src/test/msg_err_test.c create mode 100644 pjsip/src/test/msg_logger.c create mode 100644 pjsip/src/test/msg_test.c create mode 100644 pjsip/src/test/regc_test.c create mode 100644 pjsip/src/test/test.c create mode 100644 pjsip/src/test/test.h create mode 100644 pjsip/src/test/transport_loop_test.c create mode 100644 pjsip/src/test/transport_tcp_test.c create mode 100644 pjsip/src/test/transport_test.c create mode 100644 pjsip/src/test/transport_udp_test.c create mode 100644 pjsip/src/test/tsx_basic_test.c create mode 100644 pjsip/src/test/tsx_bench.c create mode 100644 pjsip/src/test/tsx_uac_test.c create mode 100644 pjsip/src/test/tsx_uas_test.c create mode 100644 pjsip/src/test/txdata_test.c create mode 100644 pjsip/src/test/uri_test.c diff --git a/build/vs/pjproject-vs8-common-defaults.vsprops b/build/vs/pjproject-vs8-common-defaults.vsprops new file mode 100644 index 00000000..91c3b86d --- /dev/null +++ b/build/vs/pjproject-vs8-common-defaults.vsprops @@ -0,0 +1,27 @@ + + + + + + + diff --git a/build/vs/pjproject-vs8-debug-defaults.vsprops b/build/vs/pjproject-vs8-debug-defaults.vsprops new file mode 100644 index 00000000..0049dfad --- /dev/null +++ b/build/vs/pjproject-vs8-debug-defaults.vsprops @@ -0,0 +1,19 @@ + + + + + diff --git a/build/vs/pjproject-vs8-debug-dynamic-defaults.vsprops b/build/vs/pjproject-vs8-debug-dynamic-defaults.vsprops new file mode 100644 index 00000000..90603570 --- /dev/null +++ b/build/vs/pjproject-vs8-debug-dynamic-defaults.vsprops @@ -0,0 +1,12 @@ + + + + diff --git a/build/vs/pjproject-vs8-debug-static-defaults.vsprops b/build/vs/pjproject-vs8-debug-static-defaults.vsprops new file mode 100644 index 00000000..b1757619 --- /dev/null +++ b/build/vs/pjproject-vs8-debug-static-defaults.vsprops @@ -0,0 +1,12 @@ + + + + diff --git a/build/vs/pjproject-vs8-release-defaults.vsprops b/build/vs/pjproject-vs8-release-defaults.vsprops new file mode 100644 index 00000000..20531548 --- /dev/null +++ b/build/vs/pjproject-vs8-release-defaults.vsprops @@ -0,0 +1,17 @@ + + + + + diff --git a/build/vs/pjproject-vs8-release-dynamic-defaults.vsprops b/build/vs/pjproject-vs8-release-dynamic-defaults.vsprops new file mode 100644 index 00000000..bdafe61e --- /dev/null +++ b/build/vs/pjproject-vs8-release-dynamic-defaults.vsprops @@ -0,0 +1,12 @@ + + + + diff --git a/build/vs/pjproject-vs8-release-static-defaults.vsprops b/build/vs/pjproject-vs8-release-static-defaults.vsprops new file mode 100644 index 00000000..06a77f56 --- /dev/null +++ b/build/vs/pjproject-vs8-release-static-defaults.vsprops @@ -0,0 +1,12 @@ + + + + diff --git a/build/vs/pjproject-vs8-win32-common-defaults.vsprops b/build/vs/pjproject-vs8-win32-common-defaults.vsprops new file mode 100644 index 00000000..58e42a1a --- /dev/null +++ b/build/vs/pjproject-vs8-win32-common-defaults.vsprops @@ -0,0 +1,20 @@ + + + + + + diff --git a/build/vs/pjproject-vs8-win32-release-defaults.vsprops b/build/vs/pjproject-vs8-win32-release-defaults.vsprops new file mode 100644 index 00000000..33fdc507 --- /dev/null +++ b/build/vs/pjproject-vs8-win32-release-defaults.vsprops @@ -0,0 +1,8 @@ + + + diff --git a/build/vs/pjproject-vs8-wm6-common-defaults.vsprops b/build/vs/pjproject-vs8-wm6-common-defaults.vsprops new file mode 100644 index 00000000..f13e2b26 --- /dev/null +++ b/build/vs/pjproject-vs8-wm6-common-defaults.vsprops @@ -0,0 +1,25 @@ + + + + + + + diff --git a/build/vs/pjproject-vs8-wm6-release-defaults.vsprops b/build/vs/pjproject-vs8-wm6-release-defaults.vsprops new file mode 100644 index 00000000..b2c0e1ae --- /dev/null +++ b/build/vs/pjproject-vs8-wm6-release-defaults.vsprops @@ -0,0 +1,8 @@ + + + diff --git a/pjlib-util/build/pjlib_util.vcproj b/pjlib-util/build/pjlib_util.vcproj index cf2e2660..e288b8ad 100644 --- a/pjlib-util/build/pjlib_util.vcproj +++ b/pjlib-util/build/pjlib_util.vcproj @@ -13,19 +13,20 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2000,6 +2349,14 @@ Name="VCCLCompilerTool" /> + + + @@ -2017,6 +2374,14 @@ Name="VCCLCompilerTool" /> + + + @@ -2034,6 +2399,14 @@ Name="VCCLCompilerTool" /> + + + @@ -2051,6 +2424,14 @@ Name="VCCLCompilerTool" /> + + + @@ -2068,6 +2449,14 @@ Name="VCCLCompilerTool" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1985,6 +2332,14 @@ Name="VCCLCompilerTool" /> + + + + + + @@ -2020,6 +2383,14 @@ Name="VCCLCompilerTool" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pjlib/build/pjlib_test.vcproj b/pjlib/build/pjlib_test.vcproj index acfba0b5..0cb02efb 100644 --- a/pjlib/build/pjlib_test.vcproj +++ b/pjlib/build/pjlib_test.vcproj @@ -13,16 +13,17 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -919,6 +2405,24 @@ PreprocessorDefinitions="" /> + + + + + + @@ -928,6 +2432,24 @@ PreprocessorDefinitions="" /> + + + + + + @@ -937,6 +2459,24 @@ PreprocessorDefinitions="" /> + + + + + + @@ -946,6 +2486,24 @@ PreprocessorDefinitions="" /> + + + + + + @@ -955,6 +2513,24 @@ PreprocessorDefinitions="" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pjsip-apps/build/py_pjsua.vcproj b/pjsip-apps/build/py_pjsua.vcproj index 533bd038..443c53f6 100644 --- a/pjsip-apps/build/py_pjsua.vcproj +++ b/pjsip-apps/build/py_pjsua.vcproj @@ -15,13 +15,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pjsip-apps/build/samples.vcproj b/pjsip-apps/build/samples.vcproj index 95ed4874..14da38fb 100644 --- a/pjsip-apps/build/samples.vcproj +++ b/pjsip-apps/build/samples.vcproj @@ -11,21 +11,19 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pjsip-apps/src/pjsua_wince/pjsua_wince.cpp b/pjsip-apps/src/pjsua_wince/pjsua_wince.cpp index 1e9bbb16..e98d0b32 100644 --- a/pjsip-apps/src/pjsua_wince/pjsua_wince.cpp +++ b/pjsip-apps/src/pjsua_wince/pjsua_wince.cpp @@ -53,7 +53,7 @@ static HWND hwndActionButton, hwndExitButton; // // STUN server -#if 1 +#if 0 // Use this to have the STUN server resolved normally # define STUN_DOMAIN NULL # define STUN_SERVER "stun.fwdnet.net" @@ -70,7 +70,7 @@ static HWND hwndActionButton, hwndExitButton; // // Use ICE? // -#define USE_ICE 1 +#define USE_ICE 0 // diff --git a/pjsip-apps/src/pjsua_wince/pjsua_wince.vcproj b/pjsip-apps/src/pjsua_wince/pjsua_wince.vcproj new file mode 100644 index 00000000..96c91d43 --- /dev/null +++ b/pjsip-apps/src/pjsua_wince/pjsua_wince.vcproj @@ -0,0 +1,2136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pjsip-apps/src/pocketpj/PocketPJ.rc b/pjsip-apps/src/pocketpj/PocketPJ.rc index f5488fdb..89729740 100644 --- a/pjsip-apps/src/pocketpj/PocketPJ.rc +++ b/pjsip-apps/src/pocketpj/PocketPJ.rc @@ -98,7 +98,7 @@ BEGIN END IDD_SETTING DIALOG DISCARDABLE 0, 0, 140, 143 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "PocketPJ Settings.." FONT 8, "System" BEGIN @@ -308,7 +308,7 @@ LANGUAGE 9, 1 #endif //_WIN32 #include "res\PocketPJ.rc2" // non-Microsoft eMbedded Visual C++ edited resources #include "afxres.rc" // Standard components -#include "wceres.rc" // WCE-specific components +// #include "wceres.rc" // WCE-specific components #endif ///////////////////////////////////////////////////////////////////////////// diff --git a/pjsip/build/pjsip_core.vcproj b/pjsip/build/pjsip_core.vcproj index 04ddffc4..1081a13e 100644 --- a/pjsip/build/pjsip_core.vcproj +++ b/pjsip/build/pjsip_core.vcproj @@ -4,6 +4,7 @@ Version="8.00" Name="pjsip_core" ProjectGUID="{2BB84911-C1B4-4747-B93D-36AA82CC5031}" + RootNamespace="pjsip_core" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pjsip/build/pjsip_ua.vcproj b/pjsip/build/pjsip_ua.vcproj index 5be7c6d9..b3a6fb66 100644 --- a/pjsip/build/pjsip_ua.vcproj +++ b/pjsip/build/pjsip_ua.vcproj @@ -4,6 +4,7 @@ Version="8.00" Name="pjsip_ua" ProjectGUID="{B8719FD5-E8A6-4A36-943C-891D07F5DD21}" + RootNamespace="pjsip_ua" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pjsip/src/test-pjsip/dlg_core_test.c b/pjsip/src/test-pjsip/dlg_core_test.c deleted file mode 100644 index ae278cbd..00000000 --- a/pjsip/src/test-pjsip/dlg_core_test.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - -#include "test.h" -#include - diff --git a/pjsip/src/test-pjsip/dns_test.c b/pjsip/src/test-pjsip/dns_test.c deleted file mode 100644 index a9ffec01..00000000 --- a/pjsip/src/test-pjsip/dns_test.c +++ /dev/null @@ -1,618 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ -#include "test.h" -#include -#include -#include - -/* For logging purpose. */ -#define THIS_FILE "dns_test.c" - -struct result -{ - pj_status_t status; - pjsip_server_addresses servers; -}; - - -static void cb(pj_status_t status, - void *token, - const struct pjsip_server_addresses *addr) -{ - struct result *result = (struct result*) token; - - result->status = status; - if (status == PJ_SUCCESS) - pj_memcpy(&result->servers, addr, sizeof(*addr)); -} - - -static void add_dns_entries(pj_dns_resolver *resv) -{ - /* Inject DNS SRV entry */ - pj_dns_parsed_packet pkt; - pj_dns_parsed_query q; - pj_dns_parsed_rr ans[4]; - pj_dns_parsed_rr ar[5]; - pj_str_t tmp; - unsigned i; - - /* - * This is answer to SRV query to "example.com" domain, and - * the answer contains full reference to the A records of - * the server. The full DNS records is : - - _sip._udp.example.com 3600 IN SRV 0 0 5060 sip01.example.com. - _sip._udp.example.com 3600 IN SRV 0 20 5060 sip02.example.com. - _sip._udp.example.com 3600 IN SRV 0 10 5060 sip03.example.com. - _sip._udp.example.com 3600 IN SRV 1 0 5060 sip04.example.com. - - sip01.example.com. 3600 IN A 1.1.1.1 - sip02.example.com. 3600 IN A 2.2.2.2 - sip03.example.com. 3600 IN A 3.3.3.3 - sip04.example.com. 3600 IN A 4.4.4.4 - - ; Additionally, add A record for "example.com" - example.com. 3600 IN A 5.5.5.5 - - */ - pj_bzero(&pkt, sizeof(pkt)); - pj_bzero(ans, sizeof(ans)); - pj_bzero(ar, sizeof(ar)); - - pkt.hdr.flags = PJ_DNS_SET_QR(1); - pkt.hdr.anscount = PJ_ARRAY_SIZE(ans); - pkt.hdr.arcount = 0; - pkt.ans = ans; - pkt.arr = ar; - - ans[0].name = pj_str("_sip._udp.example.com"); - ans[0].type = PJ_DNS_TYPE_SRV; - ans[0].dnsclass = PJ_DNS_CLASS_IN; - ans[0].ttl = 3600; - ans[0].rdata.srv.prio = 0; - ans[0].rdata.srv.weight = 0; - ans[0].rdata.srv.port = 5060; - ans[0].rdata.srv.target = pj_str("sip01.example.com"); - - ans[1].name = pj_str("_sip._udp.example.com"); - ans[1].type = PJ_DNS_TYPE_SRV; - ans[1].dnsclass = PJ_DNS_CLASS_IN; - ans[1].ttl = 3600; - ans[1].rdata.srv.prio = 0; - ans[1].rdata.srv.weight = 20; - ans[1].rdata.srv.port = 5060; - ans[1].rdata.srv.target = pj_str("sip02.example.com"); - - ans[2].name = pj_str("_sip._udp.example.com"); - ans[2].type = PJ_DNS_TYPE_SRV; - ans[2].dnsclass = PJ_DNS_CLASS_IN; - ans[2].ttl = 3600; - ans[2].rdata.srv.prio = 0; - ans[2].rdata.srv.weight = 10; - ans[2].rdata.srv.port = 5060; - ans[2].rdata.srv.target = pj_str("sip03.example.com"); - - ans[3].name = pj_str("_sip._udp.example.com"); - ans[3].type = PJ_DNS_TYPE_SRV; - ans[3].dnsclass = PJ_DNS_CLASS_IN; - ans[3].ttl = 3600; - ans[3].rdata.srv.prio = 1; - ans[3].rdata.srv.weight = 0; - ans[3].rdata.srv.port = 5060; - ans[3].rdata.srv.target = pj_str("sip04.example.com"); - - pj_dns_resolver_add_entry( resv, &pkt, PJ_FALSE); - - ar[0].name = pj_str("sip01.example.com"); - ar[0].type = PJ_DNS_TYPE_A; - ar[0].dnsclass = PJ_DNS_CLASS_IN; - ar[0].ttl = 3600; - ar[0].rdata.a.ip_addr = pj_inet_addr(pj_cstr(&tmp, "1.1.1.1")); - - ar[1].name = pj_str("sip02.example.com"); - ar[1].type = PJ_DNS_TYPE_A; - ar[1].dnsclass = PJ_DNS_CLASS_IN; - ar[1].ttl = 3600; - ar[1].rdata.a.ip_addr = pj_inet_addr(pj_cstr(&tmp, "2.2.2.2")); - - ar[2].name = pj_str("sip03.example.com"); - ar[2].type = PJ_DNS_TYPE_A; - ar[2].dnsclass = PJ_DNS_CLASS_IN; - ar[2].ttl = 3600; - ar[2].rdata.a.ip_addr = pj_inet_addr(pj_cstr(&tmp, "3.3.3.3")); - - ar[3].name = pj_str("sip04.example.com"); - ar[3].type = PJ_DNS_TYPE_A; - ar[3].dnsclass = PJ_DNS_CLASS_IN; - ar[3].ttl = 3600; - ar[3].rdata.a.ip_addr = pj_inet_addr(pj_cstr(&tmp, "4.4.4.4")); - - ar[4].name = pj_str("example.com"); - ar[4].type = PJ_DNS_TYPE_A; - ar[4].dnsclass = PJ_DNS_CLASS_IN; - ar[4].ttl = 3600; - ar[4].rdata.a.ip_addr = pj_inet_addr(pj_cstr(&tmp, "5.5.5.5")); - - /* - * Create individual A records for all hosts in "example.com" domain. - */ - for (i=0; icount != result.servers.count) { - PJ_LOG(3,(THIS_FILE, " test_resolve() error 10: result count mismatch")); - return 10; - } - - for (i=0; icount; ++i) { - pj_sockaddr_in *ra = (pj_sockaddr_in *)&ref->entry[i].addr; - pj_sockaddr_in *rb = (pj_sockaddr_in *)&result.servers.entry[i].addr; - - if (ra->sin_addr.s_addr != rb->sin_addr.s_addr) { - PJ_LOG(3,(THIS_FILE, " test_resolve() error 20: IP address mismatch")); - return 20; - } - if (ra->sin_port != rb->sin_port) { - PJ_LOG(3,(THIS_FILE, " test_resolve() error 30: port mismatch")); - return 30; - } - if (ref->entry[i].addr_len != result.servers.entry[i].addr_len) { - PJ_LOG(3,(THIS_FILE, " test_resolve() error 40: addr_len mismatch")); - return 40; - } - if (ref->entry[i].type != result.servers.entry[i].type) { - PJ_LOG(3,(THIS_FILE, " test_resolve() error 50: transport type mismatch")); - return 50; - } - } - } - - return PJ_SUCCESS; -} - -/* - * Perform round-robin/load balance test. - */ -static int round_robin_test(pj_pool_t *pool) -{ - enum { COUNT = 400, PCT_ALLOWANCE = 5 }; - unsigned i; - struct server_hit - { - char *ip_addr; - unsigned percent; - unsigned hits; - } server_hit[] = - { - { "1.1.1.1", 3, 0 }, - { "2.2.2.2", 65, 0 }, - { "3.3.3.3", 32, 0 }, - { "4.4.4.4", 0, 0 } - }; - - PJ_LOG(3,(THIS_FILE, " Performing round-robin/load-balance test..")); - - /* Do multiple resolve request to "example.com". - * The resolver should select the server based on the weight proportion - * the the servers in the SRV entry. - */ - for (i=0; isin_addr.s_addr) { - server_hit[j].hits++; - break; - } - } - - if (j == PJ_ARRAY_SIZE(server_hit)) { - PJ_LOG(1,(THIS_FILE, "..round_robin_test() error 10: returned address mismatch")); - return 10; - } - } - - /* Print the actual hit rate */ - for (i=0; i (int)server_hit[i].percent) - { - PJ_LOG(1,(THIS_FILE, - "..round_robin_test() error 20: " - "hit rate difference for server %s (%d%%) is more than " - "tolerable allowance (%d%%)", - server_hit[i].ip_addr, - actual_pct - server_hit[i].percent, - PCT_ALLOWANCE)); - return 20; - } - } - - PJ_LOG(3,(THIS_FILE, - " Load balance test success, hit-rate is " - "within %d%% allowance", PCT_ALLOWANCE)); - return PJ_SUCCESS; -} - - -#define C(expr) status = expr; \ - if (status != PJ_SUCCESS) app_perror(THIS_FILE, "Error", status); - -static void add_ref(pjsip_server_addresses *r, - pjsip_transport_type_e type, - char *addr, - int port) -{ - pj_sockaddr_in *a; - pj_str_t tmp; - - r->entry[r->count].type = type; - r->entry[r->count].priority = 0; - r->entry[r->count].weight = 0; - r->entry[r->count].addr_len = sizeof(pj_sockaddr_in); - - a = (pj_sockaddr_in *)&r->entry[r->count].addr; - a->sin_family = pj_AF_INET(); - tmp = pj_str(addr); - a->sin_addr = pj_inet_addr(&tmp); - a->sin_port = pj_htons((pj_uint16_t)port); - - r->count++; -} - -static void create_ref(pjsip_server_addresses *r, - pjsip_transport_type_e type, - char *addr, - int port) -{ - r->count = 0; - add_ref(r, type, addr, port); -} - - -/* - * Main test entry. - */ -int resolve_test(void) -{ - pj_pool_t *pool; - pj_dns_resolver *resv; - pj_str_t nameserver; - pj_uint16_t port = 5353; - pj_status_t status; - - pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000); - - status = pjsip_endpt_create_resolver(endpt, &resv); - - nameserver = pj_str("192.168.0.106"); - pj_dns_resolver_set_ns(resv, 1, &nameserver, &port); - pjsip_endpt_set_resolver(endpt, resv); - - add_dns_entries(resv); - - /* These all should be resolved as IP addresses (DNS A query) */ - { - pjsip_server_addresses ref; - create_ref(&ref, PJSIP_TRANSPORT_UDP, "1.1.1.1", 5060); - status = test_resolve("IP address without transport and port", pool, PJSIP_TRANSPORT_UNSPECIFIED, "1.1.1.1", 0, &ref); - if (status != PJ_SUCCESS) - return -100; - } - { - pjsip_server_addresses ref; - create_ref(&ref, PJSIP_TRANSPORT_UDP, "1.1.1.1", 5060); - status = test_resolve("IP address with explicit port", pool, PJSIP_TRANSPORT_UNSPECIFIED, "1.1.1.1", 5060, &ref); - if (status != PJ_SUCCESS) - return -110; - } - { - pjsip_server_addresses ref; - create_ref(&ref, PJSIP_TRANSPORT_TCP, "1.1.1.1", 5060); - status = test_resolve("IP address without port (TCP)", pool, PJSIP_TRANSPORT_TCP,"1.1.1.1", 0, &ref); - if (status != PJ_SUCCESS) - return -120; - } - { - pjsip_server_addresses ref; - create_ref(&ref, PJSIP_TRANSPORT_TLS, "1.1.1.1", 5061); - status = test_resolve("IP address without port (TLS)", pool, PJSIP_TRANSPORT_TLS, "1.1.1.1", 0, &ref); - if (status != PJ_SUCCESS) - return -130; - } - - /* This should be resolved as DNS A record (because port is present) */ - { - pjsip_server_addresses ref; - create_ref(&ref, PJSIP_TRANSPORT_UDP, "5.5.5.5", 5060); - status = test_resolve("domain name with port should resolve to A record", pool, PJSIP_TRANSPORT_UNSPECIFIED, "example.com", 5060, &ref); - if (status != PJ_SUCCESS) - return -140; - } - - /* This will fail to be resolved as SRV, resolver should fallback to - * resolving to A record. - */ - { - pjsip_server_addresses ref; - create_ref(&ref, PJSIP_TRANSPORT_UDP, "2.2.2.2", 5060); - status = test_resolve("failure with SRV fallback to A record", pool, PJSIP_TRANSPORT_UNSPECIFIED, "sip02.example.com", 0, &ref); - if (status != PJ_SUCCESS) - return -150; - } - - /* Same as above, but explicitly for TLS. */ - { - pjsip_server_addresses ref; - create_ref(&ref, PJSIP_TRANSPORT_TLS, "2.2.2.2", 5061); - status = test_resolve("failure with SRV fallback to A record (for TLS)", pool, PJSIP_TRANSPORT_TLS, "sip02.example.com", 0, &ref); - if (status != PJ_SUCCESS) - return -150; - } - - /* Standard DNS SRV followed by A recolution */ - { - pjsip_server_addresses ref; - create_ref(&ref, PJSIP_TRANSPORT_UDP, "6.6.6.6", 50060); - status = test_resolve("standard SRV resolution", pool, PJSIP_TRANSPORT_UNSPECIFIED, "domain.com", 0, &ref); - if (status != PJ_SUCCESS) - return -155; - } - - /* Standard DNS SRV followed by A recolution (explicit transport) */ - { - pjsip_server_addresses ref; - create_ref(&ref, PJSIP_TRANSPORT_TCP, "6.6.6.6", 50060); - add_ref(&ref, PJSIP_TRANSPORT_TCP, "7.7.7.7", 50060); - status = test_resolve("standard SRV resolution with explicit transport (TCP)", pool, PJSIP_TRANSPORT_TCP, "domain.com", 0, &ref); - if (status != PJ_SUCCESS) - return -160; - } - - - /* Round robin/load balance test */ - if (round_robin_test(pool) != 0) - return -170; - - /* Timeout test */ - { - status = test_resolve("timeout test", pool, PJSIP_TRANSPORT_UNSPECIFIED, "an.invalid.address", 0, NULL); - if (status == PJ_SUCCESS) - return -150; - } - - return 0; -} - diff --git a/pjsip/src/test-pjsip/inv_offer_answer_test.c b/pjsip/src/test-pjsip/inv_offer_answer_test.c deleted file mode 100644 index 22809ddf..00000000 --- a/pjsip/src/test-pjsip/inv_offer_answer_test.c +++ /dev/null @@ -1,677 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - -#include "test.h" -#include -#include -#include - -#define THIS_FILE "inv_offer_answer_test.c" -#define PORT 5068 -#define CONTACT "sip:127.0.0.1:5068" -#define TRACE_(x) PJ_LOG(3,x) - -static struct oa_sdp_t -{ - const char *offer; - const char *answer; - unsigned pt_result; -} oa_sdp[] = -{ - { - /* Offer: */ - "v=0\r\n" - "o=alice 1 1 IN IP4 host.anywhere.com\r\n" - "s= \r\n" - "c=IN IP4 host.anywhere.com\r\n" - "t=0 0\r\n" - "m=audio 49170 RTP/AVP 0\r\n" - "a=rtpmap:0 PCMU/8000\r\n", - - /* Answer: */ - "v=0\r\n" - "o=bob 1 1 IN IP4 host.example.com\r\n" - "s= \r\n" - "c=IN IP4 host.example.com\r\n" - "t=0 0\r\n" - "m=audio 49920 RTP/AVP 0\r\n" - "a=rtpmap:0 PCMU/8000\r\n" - "m=video 0 RTP/AVP 31\r\n", - - 0 - }, - - { - /* Offer: */ - "v=0\r\n" - "o=alice 2 2 IN IP4 host.anywhere.com\r\n" - "s= \r\n" - "c=IN IP4 host.anywhere.com\r\n" - "t=0 0\r\n" - "m=audio 49170 RTP/AVP 8\r\n" - "a=rtpmap:0 PCMA/8000\r\n", - - /* Answer: */ - "v=0\r\n" - "o=bob 2 2 IN IP4 host.example.com\r\n" - "s= \r\n" - "c=IN IP4 host.example.com\r\n" - "t=0 0\r\n" - "m=audio 49920 RTP/AVP 8\r\n" - "a=rtpmap:0 PCMA/8000\r\n", - - 8 - }, - - { - /* Offer: */ - "v=0\r\n" - "o=alice 3 3 IN IP4 host.anywhere.com\r\n" - "s= \r\n" - "c=IN IP4 host.anywhere.com\r\n" - "t=0 0\r\n" - "m=audio 49170 RTP/AVP 3\r\n", - - /* Answer: */ - "v=0\r\n" - "o=bob 3 3 IN IP4 host.example.com\r\n" - "s= \r\n" - "c=IN IP4 host.example.com\r\n" - "t=0 0\r\n" - "m=audio 49920 RTP/AVP 3\r\n", - - 3 - }, - - { - /* Offer: */ - "v=0\r\n" - "o=alice 4 4 IN IP4 host.anywhere.com\r\n" - "s= \r\n" - "c=IN IP4 host.anywhere.com\r\n" - "t=0 0\r\n" - "m=audio 49170 RTP/AVP 4\r\n", - - /* Answer: */ - "v=0\r\n" - "o=bob 4 4 IN IP4 host.example.com\r\n" - "s= \r\n" - "c=IN IP4 host.example.com\r\n" - "t=0 0\r\n" - "m=audio 49920 RTP/AVP 4\r\n", - - 4 - } -}; - - - -typedef enum oa_t -{ - OFFERER_NONE, - OFFERER_UAC, - OFFERER_UAS -} oa_t; - -typedef struct inv_test_param_t -{ - char *title; - unsigned inv_option; - pj_bool_t need_established; - unsigned count; - oa_t oa[4]; -} inv_test_param_t; - -typedef struct inv_test_t -{ - inv_test_param_t param; - pjsip_inv_session *uac; - pjsip_inv_session *uas; - - pj_bool_t complete; - pj_bool_t uas_complete, - uac_complete; - - unsigned oa_index; - unsigned uac_update_cnt, - uas_update_cnt; -} inv_test_t; - - -/**************** GLOBALS ******************/ -static inv_test_t inv_test; -static unsigned job_cnt; - -typedef enum job_type -{ - SEND_OFFER, - ESTABLISH_CALL -} job_type; - -typedef struct job_t -{ - job_type type; - pjsip_role_e who; -} job_t; - -static job_t jobs[128]; - - -/**************** UTILS ******************/ -static pjmedia_sdp_session *create_sdp(pj_pool_t *pool, const char *body) -{ - pjmedia_sdp_session *sdp; - pj_str_t dup; - pj_status_t status; - - pj_strdup2_with_null(pool, &dup, body); - status = pjmedia_sdp_parse(pool, dup.ptr, dup.slen, &sdp); - pj_assert(status == PJ_SUCCESS); - - return sdp; -} - -/**************** INVITE SESSION CALLBACKS ******************/ -static void on_rx_offer(pjsip_inv_session *inv, - const pjmedia_sdp_session *offer) -{ - pjmedia_sdp_session *sdp; - - sdp = create_sdp(inv->dlg->pool, oa_sdp[inv_test.oa_index].answer); - pjsip_inv_set_sdp_answer(inv, sdp); - - if (inv_test.oa_index == inv_test.param.count-1 && - inv_test.param.need_established) - { - jobs[job_cnt].type = ESTABLISH_CALL; - jobs[job_cnt].who = PJSIP_ROLE_UAS; - job_cnt++; - } -} - - -static void on_create_offer(pjsip_inv_session *inv, - pjmedia_sdp_session **p_offer) -{ - pj_assert(!"Should not happen"); -} - -static void on_media_update(pjsip_inv_session *inv_ses, - pj_status_t status) -{ - if (inv_ses == inv_test.uas) { - inv_test.uas_update_cnt++; - pj_assert(inv_test.uas_update_cnt - inv_test.uac_update_cnt <= 1); - TRACE_((THIS_FILE, " Callee media is established")); - } else if (inv_ses == inv_test.uac) { - inv_test.uac_update_cnt++; - pj_assert(inv_test.uac_update_cnt - inv_test.uas_update_cnt <= 1); - TRACE_((THIS_FILE, " Caller media is established")); - - } else { - pj_assert(!"Unknown session!"); - } - - if (inv_test.uac_update_cnt == inv_test.uas_update_cnt) { - inv_test.oa_index++; - - if (inv_test.oa_index < inv_test.param.count) { - switch (inv_test.param.oa[inv_test.oa_index]) { - case OFFERER_UAC: - jobs[job_cnt].type = SEND_OFFER; - jobs[job_cnt].who = PJSIP_ROLE_UAC; - job_cnt++; - break; - case OFFERER_UAS: - jobs[job_cnt].type = SEND_OFFER; - jobs[job_cnt].who = PJSIP_ROLE_UAS; - job_cnt++; - break; - default: - pj_assert(!"Invalid oa"); - } - } - - pj_assert(job_cnt <= PJ_ARRAY_SIZE(jobs)); - } -} - -static void on_state_changed(pjsip_inv_session *inv, pjsip_event *e) -{ - const char *who = NULL; - - if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { - TRACE_((THIS_FILE, " %s call disconnected", - (inv==inv_test.uas ? "Callee" : "Caller"))); - return; - } - - if (inv->state != PJSIP_INV_STATE_CONFIRMED) - return; - - if (inv == inv_test.uas) { - inv_test.uas_complete = PJ_TRUE; - who = "Callee"; - } else if (inv == inv_test.uac) { - inv_test.uac_complete = PJ_TRUE; - who = "Caller"; - } else - pj_assert(!"No session"); - - TRACE_((THIS_FILE, " %s call is confirmed", who)); - - if (inv_test.uac_complete && inv_test.uas_complete) - inv_test.complete = PJ_TRUE; -} - - -/**************** MODULE TO RECEIVE INITIAL INVITE ******************/ - -static pj_bool_t on_rx_request(pjsip_rx_data *rdata) -{ - if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG && - rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) - { - pjsip_dialog *dlg; - pjmedia_sdp_session *sdp = NULL; - pj_str_t uri; - pjsip_tx_data *tdata; - pj_status_t status; - - /* - * Create UAS - */ - uri = pj_str(CONTACT); - status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, - &uri, &dlg); - pj_assert(status == PJ_SUCCESS); - - if (inv_test.param.oa[0] == OFFERER_UAC) - sdp = create_sdp(rdata->tp_info.pool, oa_sdp[0].answer); - else if (inv_test.param.oa[0] == OFFERER_UAS) - sdp = create_sdp(rdata->tp_info.pool, oa_sdp[0].offer); - else - pj_assert(!"Invalid offerer type"); - - status = pjsip_inv_create_uas(dlg, rdata, sdp, inv_test.param.inv_option, &inv_test.uas); - pj_assert(status == PJ_SUCCESS); - - TRACE_((THIS_FILE, " Sending 183 with SDP")); - - /* - * Answer with 183 - */ - status = pjsip_inv_initial_answer(inv_test.uas, rdata, 183, NULL, - NULL, &tdata); - pj_assert(status == PJ_SUCCESS); - - status = pjsip_inv_send_msg(inv_test.uas, tdata); - pj_assert(status == PJ_SUCCESS); - - return PJ_TRUE; - } - - return PJ_FALSE; -} - -static pjsip_module mod_inv_oa_test = -{ - NULL, NULL, /* prev, next. */ - { "mod-inv-oa-test", 15 }, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &on_rx_request, /* on_rx_request() */ - NULL, /* on_rx_response() */ - NULL, /* on_tx_request. */ - NULL, /* on_tx_response() */ - NULL, /* on_tsx_state() */ -}; - - -/**************** THE TEST ******************/ -static void run_job(job_t *j) -{ - pjsip_inv_session *inv; - pjsip_tx_data *tdata; - pjmedia_sdp_session *sdp; - pj_status_t status; - - if (j->who == PJSIP_ROLE_UAC) - inv = inv_test.uac; - else - inv = inv_test.uas; - - switch (j->type) { - case SEND_OFFER: - sdp = create_sdp(inv->dlg->pool, oa_sdp[inv_test.oa_index].offer); - - TRACE_((THIS_FILE, " Sending UPDATE with offer")); - status = pjsip_inv_update(inv, NULL, sdp, &tdata); - pj_assert(status == PJ_SUCCESS); - - status = pjsip_inv_send_msg(inv, tdata); - pj_assert(status == PJ_SUCCESS); - break; - case ESTABLISH_CALL: - TRACE_((THIS_FILE, " Sending 200/OK")); - status = pjsip_inv_answer(inv, 200, NULL, NULL, &tdata); - pj_assert(status == PJ_SUCCESS); - - status = pjsip_inv_send_msg(inv, tdata); - pj_assert(status == PJ_SUCCESS); - break; - } -} - - -static int perform_test(inv_test_param_t *param) -{ - pj_str_t uri; - pjsip_dialog *dlg; - pjmedia_sdp_session *sdp; - pjsip_tx_data *tdata; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, " %s", param->title)); - - pj_bzero(&inv_test, sizeof(inv_test)); - pj_memcpy(&inv_test.param, param, sizeof(*param)); - job_cnt = 0; - - uri = pj_str(CONTACT); - - /* - * Create UAC - */ - status = pjsip_dlg_create_uac(pjsip_ua_instance(), - &uri, &uri, &uri, &uri, &dlg); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, -10); - - if (inv_test.param.oa[0] == OFFERER_UAC) - sdp = create_sdp(dlg->pool, oa_sdp[0].offer); - else - sdp = NULL; - - status = pjsip_inv_create_uac(dlg, sdp, inv_test.param.inv_option, &inv_test.uac); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, -20); - - TRACE_((THIS_FILE, " Sending INVITE %s offer", (sdp ? "with" : "without"))); - - /* - * Make call! - */ - status = pjsip_inv_invite(inv_test.uac, &tdata); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30); - - status = pjsip_inv_send_msg(inv_test.uac, tdata); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30); - - /* - * Wait until test completes - */ - while (!inv_test.complete) { - pj_time_val delay = {0, 20}; - - pjsip_endpt_handle_events(endpt, &delay); - - while (job_cnt) { - job_t j; - - j = jobs[0]; - pj_array_erase(jobs, sizeof(jobs[0]), job_cnt, 0); - --job_cnt; - - run_job(&j); - } - } - - flush_events(100); - - /* - * Hangup - */ - TRACE_((THIS_FILE, " Disconnecting call")); - status = pjsip_inv_end_session(inv_test.uas, PJSIP_SC_DECLINE, 0, &tdata); - pj_assert(status == PJ_SUCCESS); - - status = pjsip_inv_send_msg(inv_test.uas, tdata); - pj_assert(status == PJ_SUCCESS); - - flush_events(500); - - return 0; -} - - -static pj_bool_t log_on_rx_msg(pjsip_rx_data *rdata) -{ - pjsip_msg *msg = rdata->msg_info.msg; - char info[80]; - - if (msg->type == PJSIP_REQUEST_MSG) - pj_ansi_snprintf(info, sizeof(info), "%.*s", - (int)msg->line.req.method.name.slen, - msg->line.req.method.name.ptr); - else - pj_ansi_snprintf(info, sizeof(info), "%d/%.*s", - msg->line.status.code, - (int)rdata->msg_info.cseq->method.name.slen, - rdata->msg_info.cseq->method.name.ptr); - - TRACE_((THIS_FILE, " Received %s %s sdp", info, - (msg->body ? "with" : "without"))); - - return PJ_FALSE; -} - - -/* Message logger module. */ -static pjsip_module mod_msg_logger = -{ - NULL, NULL, /* prev and next */ - { "mod-msg-loggee", 14}, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &log_on_rx_msg, /* on_rx_request() */ - &log_on_rx_msg, /* on_rx_response() */ - NULL, /* on_tx_request() */ - NULL, /* on_tx_response() */ - NULL, /* on_tsx_state() */ -}; - -static inv_test_param_t test_params[] = -{ -/* Normal scenario: - - UAC UAS - INVITE (offer) --> - 200/INVITE (answer) <-- - ACK --> - */ -#if 0 - { - "Standard INVITE with offer", - 0, - PJ_TRUE, - 1, - { OFFERER_UAC } - }, - - { - "Standard INVITE with offer, with 100rel", - PJSIP_INV_REQUIRE_100REL, - PJ_TRUE, - 1, - { OFFERER_UAC } - }, -#endif - -/* Delayed offer: - UAC UAS - INVITE (no SDP) --> - 200/INVITE (offer) <-- - ACK (answer) --> - */ -#if 1 - { - "INVITE with no offer", - 0, - PJ_TRUE, - 1, - { OFFERER_UAS } - }, - - { - "INVITE with no offer, with 100rel", - PJSIP_INV_REQUIRE_100REL, - PJ_TRUE, - 1, - { OFFERER_UAS } - }, -#endif - -/* Subsequent UAC offer with UPDATE: - - UAC UAS - INVITE (offer) --> - 180/rel (answer) <-- - UPDATE (offer) --> inv_update() on_rx_offer() - set_sdp_answer() - 200/UPDATE (answer) <-- - 200/INVITE <-- - ACK --> -*/ -#if 1 - { - "INVITE and UPDATE by UAC", - 0, - PJ_TRUE, - 2, - { OFFERER_UAC, OFFERER_UAC } - }, - { - "INVITE and UPDATE by UAC, with 100rel", - PJSIP_INV_REQUIRE_100REL, - PJ_TRUE, - 2, - { OFFERER_UAC, OFFERER_UAC } - }, -#endif - -/* Subsequent UAS offer with UPDATE: - - INVITE (offer --> - 180/rel (answer) <-- - UPDATE (offer) <-- inv_update() - on_rx_offer() - set_sdp_answer() - 200/UPDATE (answer) --> - UPDATE (offer) --> on_rx_offer() - set_sdp_answer() - 200/UPDATE (answer) <-- - 200/INVITE <-- - ACK --> - - */ - { - "INVITE and many UPDATE by UAC and UAS", - 0, - PJ_TRUE, - 4, - { OFFERER_UAC, OFFERER_UAS, OFFERER_UAC, OFFERER_UAS } - }, - -}; - - -static pjsip_dialog* on_dlg_forked(pjsip_dialog *first_set, pjsip_rx_data *res) -{ - return NULL; -} - - -static void on_new_session(pjsip_inv_session *inv, pjsip_event *e) -{ -} - - -int inv_offer_answer_test(void) -{ - unsigned i; - int rc = 0; - - /* Init UA layer */ - if (pjsip_ua_instance()->id == -1) { - pjsip_ua_init_param ua_param; - pj_bzero(&ua_param, sizeof(ua_param)); - ua_param.on_dlg_forked = &on_dlg_forked; - pjsip_ua_init_module(endpt, &ua_param); - } - - /* Init inv-usage */ - if (pjsip_inv_usage_instance()->id == -1) { - pjsip_inv_callback inv_cb; - pj_bzero(&inv_cb, sizeof(inv_cb)); - inv_cb.on_media_update = &on_media_update; - inv_cb.on_rx_offer = &on_rx_offer; - inv_cb.on_create_offer = &on_create_offer; - inv_cb.on_state_changed = &on_state_changed; - inv_cb.on_new_session = &on_new_session; - pjsip_inv_usage_init(endpt, &inv_cb); - } - - /* 100rel module */ - pjsip_100rel_init_module(endpt); - - /* Our module */ - pjsip_endpt_register_module(endpt, &mod_inv_oa_test); - pjsip_endpt_register_module(endpt, &mod_msg_logger); - - /* Create SIP UDP transport */ - { - pj_sockaddr_in addr; - pjsip_transport *tp; - pj_status_t status; - - pj_sockaddr_in_init(&addr, NULL, PORT); - status = pjsip_udp_transport_start(endpt, &addr, NULL, 1, &tp); - pj_assert(status == PJ_SUCCESS); - } - - /* Do tests */ - for (i=0; i - * - * 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 - */ -#include "test.h" -#include -#include -#include - -extern const char *system_name; - -static void usage() -{ - puts("Usage: test-pjsip"); - puts("Options:"); - puts(" -i,--interractive Key input at the end."); - puts(" -h,--help Show this screen"); - puts(" -l,--log-level N Set log level (0-6)"); -} - -int main(int argc, char *argv[]) -{ - int interractive = 0; - int retval; - char **opt_arg; - - /* Parse arguments. */ - opt_arg = argv+1; - while (*opt_arg) { - if (strcmp(*opt_arg, "-i") == 0 || - strcmp(*opt_arg, "--interractive") == 0) - { - interractive = 1; - } else if (strcmp(*opt_arg, "-h") == 0 || - strcmp(*opt_arg, "--help") == 0) - { - usage(); - return 1; - } else if (strcmp(*opt_arg, "-l") == 0 || - strcmp(*opt_arg, "--log-level") == 0) - { - ++opt_arg; - if (!opt_arg) { - usage(); - return 1; - } - log_level = atoi(*opt_arg); - } else if (strcmp(*opt_arg, "-s") == 0 || - strcmp(*opt_arg, "--system") == 0) - { - ++opt_arg; - if (!opt_arg) { - usage(); - return 1; - } - system_name = *opt_arg; - } else { - usage(); - return 1; - } - - ++opt_arg; - } - - retval = test_main(); - - if (interractive) { - char s[10]; - printf("\n"); fflush(stdout); - if (fgets(s, sizeof(s), stdin) == NULL) - return retval; - } - - return retval; -} diff --git a/pjsip/src/test-pjsip/main_rtems.c b/pjsip/src/test-pjsip/main_rtems.c deleted file mode 100644 index a4d14e5a..00000000 --- a/pjsip/src/test-pjsip/main_rtems.c +++ /dev/null @@ -1,12 +0,0 @@ - -/* - * !! OIY OIY !! - * - * The purpose of this file is only to get pjsip-test linked. I haven't - * actually tried to run pjsip-test on RTEMS!! - * - */ - -#include "../../pjlib/src/pjlib-test/main_rtems.c" - - diff --git a/pjsip/src/test-pjsip/main_win32.c b/pjsip/src/test-pjsip/main_win32.c deleted file mode 100644 index 3043a395..00000000 --- a/pjsip/src/test-pjsip/main_win32.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../pjlib/src/pjlib-test/main_win32.c" diff --git a/pjsip/src/test-pjsip/msg_err_test.c b/pjsip/src/test-pjsip/msg_err_test.c deleted file mode 100644 index 46d28f15..00000000 --- a/pjsip/src/test-pjsip/msg_err_test.c +++ /dev/null @@ -1,101 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ -#include "test.h" -#include -#include - -#define THIS_FILE "msg_err_test.c" - - -static pj_bool_t verify_success(pjsip_msg *msg, - pjsip_parser_err_report *err_list) -{ - return PJ_TRUE; -} - -static struct test_entry -{ - char msg[1024]; - pj_bool_t (*verify)(pjsip_msg *msg, - pjsip_parser_err_report *err_list); - -} test_entries[] = -{ - /* Syntax error in status line */ - { - "SIP/2.0 200\r\n" - "H-Name: H-Value\r\n" - "\r\n", - &verify_success - }, - - /* Syntax error in header */ - { - "SIP/2.0 200 OK\r\n" - "Via: SIP/2.0\r\n" - "H-Name: H-Value\r\n" - "\r\n", - &verify_success - }, - - /* Multiple syntax errors in headers */ - { - "SIP/2.0 200 OK\r\n" - "Via: SIP/2.0\r\n" - "H-Name: H-Value\r\n" - "Via: SIP/2.0\r\n" - "\r\n", - &verify_success - } -}; - - -int msg_err_test(void) -{ - pj_pool_t *pool; - unsigned i; - - PJ_LOG(3,(THIS_FILE, "Testing parsing error")); - - pool = pjsip_endpt_create_pool(endpt, "msgerrtest", 4000, 4000); - - for (i=0; iline, e->col, - (int)e->hname.slen, - e->hname.ptr)); - e = e->next; - } - } - - pj_pool_release(pool); - return 0; -} diff --git a/pjsip/src/test-pjsip/msg_logger.c b/pjsip/src/test-pjsip/msg_logger.c deleted file mode 100644 index 8a71adcb..00000000 --- a/pjsip/src/test-pjsip/msg_logger.c +++ /dev/null @@ -1,104 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ -#include "test.h" -#include -#include - -#define THIS_FILE "msg_logger.c" - -static pj_bool_t msg_log_enabled; - -static pj_bool_t on_rx_msg(pjsip_rx_data *rdata) -{ - if (msg_log_enabled) { - PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%s:%d:\n" - "%.*s\n" - "--end msg--", - rdata->msg_info.len, - pjsip_rx_data_get_info(rdata), - rdata->tp_info.transport->type_name, - rdata->pkt_info.src_name, - rdata->pkt_info.src_port, - rdata->msg_info.len, - rdata->msg_info.msg_buf)); - } - - return PJ_FALSE; -} - -static pj_status_t on_tx_msg(pjsip_tx_data *tdata) -{ - if (msg_log_enabled) { - PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%s:%d:\n" - "%.*s\n" - "--end msg--", - (tdata->buf.cur - tdata->buf.start), - pjsip_tx_data_get_info(tdata), - tdata->tp_info.transport->type_name, - tdata->tp_info.dst_name, - tdata->tp_info.dst_port, - (tdata->buf.cur - tdata->buf.start), - tdata->buf.start)); - } - return PJ_SUCCESS; -} - - -/* Message logger module. */ -static pjsip_module mod_msg_logger = -{ - NULL, NULL, /* prev and next */ - { "mod-msg-logger", 14}, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &on_rx_msg, /* on_rx_request() */ - &on_rx_msg, /* on_rx_response() */ - &on_tx_msg, /* on_tx_request() */ - &on_tx_msg, /* on_tx_response() */ - NULL, /* on_tsx_state() */ -}; - -int init_msg_logger(void) -{ - pj_status_t status; - - if (mod_msg_logger.id != -1) - return 0; - - status = pjsip_endpt_register_module(endpt, &mod_msg_logger); - if (status != PJ_SUCCESS) { - app_perror(" error registering module", status); - return -10; - } - - return 0; -} - -int msg_logger_set_enabled(pj_bool_t enabled) -{ - int val = msg_log_enabled; - msg_log_enabled = enabled; - return val; -} - diff --git a/pjsip/src/test-pjsip/msg_test.c b/pjsip/src/test-pjsip/msg_test.c deleted file mode 100644 index 840c40ff..00000000 --- a/pjsip/src/test-pjsip/msg_test.c +++ /dev/null @@ -1,2058 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ -#include "test.h" -#include -#include - -#define POOL_SIZE 8000 -#if defined(PJ_DEBUG) && PJ_DEBUG!=0 -# define LOOP 10000 -#else -# define LOOP 100000 -#endif -#define AVERAGE_MSG_LEN 800 -#define THIS_FILE "msg_test.c" - -static pjsip_msg *create_msg0(pj_pool_t *pool); -static pjsip_msg *create_msg1(pj_pool_t *pool); - -#define STATUS_PARTIAL 1 -#define STATUS_SYNTAX_ERROR 2 - -#define FLAG_DETECT_ONLY 1 -#define FLAG_PARSE_ONLY 4 -#define FLAG_PRINT_ONLY 8 - -struct test_msg -{ - char msg[1024]; - pjsip_msg *(*creator)(pj_pool_t *pool); - pj_size_t len; - int expected_status; -} test_array[] = -{ -{ - /* 'Normal' message with all headers. */ - "INVITE sip:user@foo SIP/2.0\n" - "from: Hi I'm Joe ;tag=123457890123456\r" - "To: Fellow User \r\n" - "Call-ID: 12345678901234567890@bar\r\n" - "Content-Length: 0\r\n" - "CSeq: 123456 INVITE\n" - "Contact: ; q=0.5;expires=3600,sip:user@host;q=0.500\r" - " ,sip:user2@host2\n" - "Content-Type: text/html ; charset=ISO-8859-4\r" - "Route: ,\r\n" - " \r" - "Record-Route: ,\r\n" /* multiple routes+folding*/ - " \n" - "v: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c230\n" - "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n" /* folding. */ - " ;received=192.0.2.1\r\n" - "Via: SIP/2.0/UDP 10.2.1.1, SIP/2.0/TCP 192.168.1.1\n" - "Organization: \r" - "Max-Forwards: 70\n" - "X-Header: \r\n" /* empty header */ - "P-Associated-URI:\r\n" /* empty header without space */ - "\r\n", - &create_msg0, - 0, - PJ_SUCCESS -}, -{ - /* Typical response message. */ - "SIP/2.0 200 OK\r\n" - "Via: SIP/2.0/SCTP server10.biloxi.com;branch=z9hG4bKnashds8;rport;received=192.0.2.1\r\n" - "Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2\r\n" - "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds ;received=192.0.2.3\r\n" - "Route: \r\n" - "Route: \r\n" - "Max-Forwards: 70\r\n" - "To: Bob ;tag=a6c85cf\r\n" - "From: Alice ;tag=1928301774\r\n" - "Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n" - "CSeq: 314159 INVITE\r\n" - "Contact: \r\n" - "Content-Type: application/sdp\r\n" - "Content-Length: 150\r\n" - "\r\n" - "v=0\r\n" - "o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com\r\n" - "s=-\r\n" - "t=0 0\r\n" - "c=IN IP4 pc33.atlanta.com\r\n" - "m=audio 3456 RTP/AVP 0 1 3 99\r\n" - "a=rtpmap:0 PCMU/8000\r\n", - &create_msg1, - 0, - PJ_SUCCESS -}, -{ - /* Torture message from RFC 4475 - * 3.1.1.1 A short tortuous INVITE - */ - "INVITE sip:vivekg@chair-dnrc.example.com;unknownparam SIP/2.0\n" - "TO :\n" - " sip:vivekg@chair-dnrc.example.com ; tag = 1918181833n\n" - "from : \"J Rosenberg \\\\\\\"\" \n" - " ;\n" - " tag = 98asjd8\n" - "MaX-fOrWaRdS: 0068\n" - "Call-ID: wsinv.ndaksdj@192.0.2.1\n" - "Content-Length : 150\n" - "cseq: 0009\n" - " INVITE\n" - "Via : SIP / 2.0\n" - " /UDP\n" - " 192.0.2.2;rport;branch=390skdjuw\n" - "s :\n" - "NewFangledHeader: newfangled value\n" - " continued newfangled value\n" - "UnknownHeaderWithUnusualValue: ;;,,;;,;\n" - "Content-Type: application/sdp\n" - "Route:\n" - " \n" - "v: SIP / 2.0 / TCP spindle.example.com ;\n" - " branch = z9hG4bK9ikj8 ,\n" - " SIP / 2.0 / UDP 192.168.255.111 ; branch=\n" - " z9hG4bK30239\n" - "m:\"Quoted string \\\"\\\"\" ; newparam =\n" - " newvalue ;\n" - " secondparam ; q = 0.33\r\n" - "\r\n" - "v=0\r\n" - "o=mhandley 29739 7272939 IN IP4 192.0.2.3\r\n" - "s=-\r\n" - "c=IN IP4 192.0.2.4\r\n" - "t=0 0\r\n" - "m=audio 49217 RTP/AVP 0 12\r\n" - "m=video 3227 RTP/AVP 31\r\n" - "a=rtpmap:31 LPC\r\n", - NULL, - 0, - PJ_SUCCESS -}, -{ - /* Torture message from RFC 4475 - * 3.1.1.2 Wide Range of Valid Characters - */ - "!interesting-Method0123456789_*+`.%indeed'~ sip:1_unusual.URI~(to-be!sure)&isn't+it$/crazy?,/;;*:&it+has=1,weird!*pas$wo~d_too.(doesn't-it)@example.com SIP/2.0\n" - "Via: SIP/2.0/UDP host1.example.com;rport;branch=z9hG4bK-.!%66*_+`'~\n" - "To: \"BEL:\\\x07 NUL:\\\x00 DEL:\\\x7F\" \n" - "From: token1~` token2'+_ token3*%!.- ;fromParam''~+*_!.-%=\"\xD1\x80\xD0\xB0\xD0\xB1\xD0\xBE\xD1\x82\xD0\xB0\xD1\x8E\xD1\x89\xD0\xB8\xD0\xB9\";tag=_token~1'+`*%!-.\n" - "Call-ID: intmeth.word%ZK-!.*_+'@word`~)(><:\\/\"][?}{\n" - "CSeq: 139122385 !interesting-Method0123456789_*+`.%indeed'~\n" - "Max-Forwards: 255\n" - "extensionHeader-!.%*+_`'~: \xEF\xBB\xBF\xE5\xA4\xA7\xE5\x81\x9C\xE9\x9B\xBB\n" - "Content-Length: 0\r\n\r\n", - NULL, - 641, - PJ_SUCCESS -}, -{ - /* Torture message from RFC 4475 - * 3.1.1.3 Valid Use of the % Escaping Mechanism - */ - "INVITE sip:sips%3Auser%40example.com@example.net SIP/2.0\n" - "To: sip:%75se%72@example.com\n" - "From: ;tag=1234\n" - "Max-Forwards: 87\n" - "i: esc01.239409asdfakjkn23onasd0-3234\n" - "CSeq: 234234 INVITE\n" - "Via: SIP/2.0/UDP host5.example.net;rport;branch=z9hG4bKkdjuw\n" - "C: application/sdp\n" - "Contact:\n" - " \n" - "Content-Length: 150\r\n" - "\r\n" - "v=0\r\n" - "o=mhandley 29739 7272939 IN IP4 192.0.2.1\r\n" - "s=-\r\n" - "c=IN IP4 192.0.2.1\r\n" - "t=0 0\r\n" - "m=audio 49217 RTP/AVP 0 12\r\n" - "m=video 3227 RTP/AVP 31\r\n" - "a=rtpmap:31 LPC\r\n", - NULL, - 0, - PJ_SUCCESS -}, -{ - /* Torture message from RFC 4475 - * 3.1.1.4 Escaped Nulls in URIs - */ - "REGISTER sip:example.com SIP/2.0\r\n" - "To: sip:null-%00-null@example.com\r\n" - "From: sip:null-%00-null@example.com;tag=839923423\r\n" - "Max-Forwards: 70\r\n" - "Call-ID: escnull.39203ndfvkjdasfkq3w4otrq0adsfdfnavd\r\n" - "CSeq: 14398234 REGISTER\r\n" - "Via: SIP/2.0/UDP host5.example.com;rport;branch=z9hG4bKkdjuw\r\n" - "Contact: \r\n" - "Contact: \r\n" - "L:0\r\n" - "\r\n", - NULL, - 0, - PJ_SUCCESS -}, -{ - /* Torture message from RFC 4475 - * 3.1.1.5 Use of % When It Is Not an Escape - */ - "RE%47IST%45R sip:registrar.example.com SIP/2.0\r\n" - "To: \"%Z%45\" \r\n" - "From: \"%Z%45\" ;tag=f232jadfj23\r\n" - "Call-ID: esc02.asdfnqwo34rq23i34jrjasdcnl23nrlknsdf\r\n" - "Via: SIP/2.0/TCP host.example.com;rport;branch=z9hG4bK209%fzsnel234\r\n" - "CSeq: 29344 RE%47IST%45R\r\n" - "Max-Forwards: 70\r\n" - "Contact: \r\n" - "C%6Fntact: \r\n" - "Contact: \r\n" - "l: 0\r\n" - "\r\n", - NULL, - 0, - PJ_SUCCESS -} -}; - -static struct -{ - int flag; - pj_highprec_t detect_len, parse_len, print_len; - pj_timestamp detect_time, parse_time, print_time; -} var; - -static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry ) -{ - pjsip_msg *parsed_msg, *ref_msg = NULL; - static pjsip_msg *print_msg; - pj_status_t status = PJ_SUCCESS; - int len; - pj_str_t str1, str2; - pjsip_hdr *hdr1, *hdr2; - pj_timestamp t1, t2; - pjsip_parser_err_report err_list; - pj_size_t msg_size; - char msgbuf1[PJSIP_MAX_PKT_LEN]; - char msgbuf2[PJSIP_MAX_PKT_LEN]; - enum { BUFLEN = 512 }; - - if (entry->len==0) - entry->len = pj_ansi_strlen(entry->msg); - - if (var.flag & FLAG_PARSE_ONLY) - goto parse_msg; - - if (var.flag & FLAG_PRINT_ONLY) { - if (print_msg == NULL) - print_msg = entry->creator(pool); - goto print_msg; - } - - /* Detect message. */ - var.detect_len = var.detect_len + entry->len; - pj_get_timestamp(&t1); - status = pjsip_find_msg(entry->msg, entry->len, PJ_FALSE, &msg_size); - if (status != PJ_SUCCESS) { - if (status!=PJSIP_EPARTIALMSG || - entry->expected_status!=STATUS_PARTIAL) - { - app_perror(" error: unable to detect message", status); - return -5; - } - } - if (msg_size != entry->len) { - PJ_LOG(3,(THIS_FILE, " error: size mismatch")); - return -6; - } - pj_get_timestamp(&t2); - pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&var.detect_time, &t2); - - if (var.flag & FLAG_DETECT_ONLY) - return PJ_SUCCESS; - - /* Parse message. */ -parse_msg: - var.parse_len = var.parse_len + entry->len; - pj_get_timestamp(&t1); - pj_list_init(&err_list); - parsed_msg = pjsip_parse_msg(pool, entry->msg, entry->len, &err_list); - if (parsed_msg == NULL) { - if (entry->expected_status != STATUS_SYNTAX_ERROR) { - status = -10; - if (err_list.next != &err_list) { - PJ_LOG(3,(THIS_FILE, " Syntax error in line %d col %d", - err_list.next->line, err_list.next->col)); - } - goto on_return; - } - } - pj_get_timestamp(&t2); - pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&var.parse_time, &t2); - - if ((var.flag & FLAG_PARSE_ONLY) || entry->creator==NULL) - return PJ_SUCCESS; - - /* Create reference message. */ - ref_msg = entry->creator(pool); - - /* Create buffer for comparison. */ - str1.ptr = (char*)pj_pool_alloc(pool, BUFLEN); - str2.ptr = (char*)pj_pool_alloc(pool, BUFLEN); - - /* Compare message type. */ - if (parsed_msg->type != ref_msg->type) { - status = -20; - goto on_return; - } - - /* Compare request or status line. */ - if (parsed_msg->type == PJSIP_REQUEST_MSG) { - pjsip_method *m1 = &parsed_msg->line.req.method; - pjsip_method *m2 = &ref_msg->line.req.method; - - if (pjsip_method_cmp(m1, m2) != 0) { - status = -30; - goto on_return; - } - status = pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, - parsed_msg->line.req.uri, - ref_msg->line.req.uri); - if (status != PJ_SUCCESS) { - app_perror(" error: request URI mismatch", status); - status = -31; - goto on_return; - } - } else { - if (parsed_msg->line.status.code != ref_msg->line.status.code) { - PJ_LOG(3,(THIS_FILE, " error: status code mismatch")); - status = -32; - goto on_return; - } - if (pj_strcmp(&parsed_msg->line.status.reason, - &ref_msg->line.status.reason) != 0) - { - PJ_LOG(3,(THIS_FILE, " error: status text mismatch")); - status = -33; - goto on_return; - } - } - - /* Compare headers. */ - hdr1 = parsed_msg->hdr.next; - hdr2 = ref_msg->hdr.next; - - while (hdr1 != &parsed_msg->hdr && hdr2 != &ref_msg->hdr) { - len = hdr1->vptr->print_on(hdr1, str1.ptr, BUFLEN); - if (len < 1) { - status = -40; - goto on_return; - } - str1.ptr[len] = '\0'; - str1.slen = len; - - len = hdr2->vptr->print_on(hdr2, str2.ptr, BUFLEN); - if (len < 1) { - status = -50; - goto on_return; - } - str2.ptr[len] = '\0'; - str2.slen = len; - - if (pj_strcmp(&str1, &str2) != 0) { - status = -60; - PJ_LOG(3,(THIS_FILE, " error: header string mismatch:\n" - " h1='%s'\n" - " h2='%s'\n", - str1.ptr, str2.ptr)); - goto on_return; - } - - hdr1 = hdr1->next; - hdr2 = hdr2->next; - } - - if (hdr1 != &parsed_msg->hdr || hdr2 != &ref_msg->hdr) { - status = -70; - goto on_return; - } - - /* Compare body? */ - if (parsed_msg->body==NULL && ref_msg->body==NULL) - goto print_msg; - - /* Compare msg body length. */ - if (parsed_msg->body->len != ref_msg->body->len) { - status = -80; - goto on_return; - } - - /* Compare msg body content type. */ - if (pj_strcmp(&parsed_msg->body->content_type.type, - &ref_msg->body->content_type.type) != 0) { - status = -90; - goto on_return; - } - if (pj_strcmp(&parsed_msg->body->content_type.subtype, - &ref_msg->body->content_type.subtype) != 0) { - status = -100; - goto on_return; - } - - /* Compare body content. */ - str1.slen = parsed_msg->body->print_body(parsed_msg->body, - msgbuf1, sizeof(msgbuf1)); - if (str1.slen < 1) { - status = -110; - goto on_return; - } - str1.ptr = msgbuf1; - - str2.slen = ref_msg->body->print_body(ref_msg->body, - msgbuf2, sizeof(msgbuf2)); - if (str2.slen < 1) { - status = -120; - goto on_return; - } - str2.ptr = msgbuf2; - - if (pj_strcmp(&str1, &str2) != 0) { - status = -140; - goto on_return; - } - - /* Print message. */ -print_msg: - var.print_len = var.print_len + entry->len; - pj_get_timestamp(&t1); - if (var.flag && FLAG_PRINT_ONLY) - ref_msg = print_msg; - len = pjsip_msg_print(ref_msg, msgbuf1, PJSIP_MAX_PKT_LEN); - if (len < 1) { - status = -150; - goto on_return; - } - pj_get_timestamp(&t2); - pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&var.print_time, &t2); - - - status = PJ_SUCCESS; - -on_return: - return status; -} - - -static pjsip_msg *create_msg0(pj_pool_t *pool) -{ - - pjsip_msg *msg; - pjsip_name_addr *name_addr; - pjsip_sip_uri *url; - pjsip_fromto_hdr *fromto; - pjsip_cid_hdr *cid; - pjsip_clen_hdr *clen; - pjsip_cseq_hdr *cseq; - pjsip_contact_hdr *contact; - pjsip_ctype_hdr *ctype; - pjsip_routing_hdr *routing; - pjsip_via_hdr *via; - pjsip_generic_string_hdr *generic; - pj_str_t str; - - msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG); - - /* "INVITE sip:user@foo SIP/2.0\n" */ - pjsip_method_set(&msg->line.req.method, PJSIP_INVITE_METHOD); - url = pjsip_sip_uri_create(pool, 0); - msg->line.req.uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "user"); - pj_strdup2(pool, &url->host, "foo"); - - /* "From: Hi I'm Joe ;tag=123457890123456\r" */ - fromto = pjsip_from_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto); - pj_strdup2(pool, &fromto->tag, "123457890123456"); - name_addr = pjsip_name_addr_create(pool); - fromto->uri = (pjsip_uri*)name_addr; - pj_strdup2(pool, &name_addr->display, "Hi I'm Joe"); - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "joe.user"); - pj_strdup2(pool, &url->host, "bar.otherdomain.com"); - - /* "To: Fellow User \r\n" */ - fromto = pjsip_to_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto); - name_addr = pjsip_name_addr_create(pool); - fromto->uri = (pjsip_uri*)name_addr; - pj_strdup2(pool, &name_addr->display, "Fellow User"); - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "user"); - pj_strdup2(pool, &url->host, "foo.bar.domain.com"); - - /* "Call-ID: 12345678901234567890@bar\r\n" */ - cid = pjsip_cid_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)cid); - pj_strdup2(pool, &cid->id, "12345678901234567890@bar"); - - /* "Content-Length: 0\r\n" */ - clen = pjsip_clen_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)clen); - clen->len = 0; - - /* "CSeq: 123456 INVITE\n" */ - cseq = pjsip_cseq_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)cseq); - cseq->cseq = 123456; - pjsip_method_set(&cseq->method, PJSIP_INVITE_METHOD); - - /* "Contact: ;q=0.5;expires=3600*/ - contact = pjsip_contact_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); - contact->q1000 = 500; - contact->expires = 3600; - name_addr = pjsip_name_addr_create(pool); - contact->uri = (pjsip_uri*)name_addr; - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "joe"); - pj_strdup2(pool, &url->host, "bar"); - - /*, sip:user@host;q=0.500\r" */ - contact = pjsip_contact_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); - contact->q1000 = 500; - name_addr = pjsip_name_addr_create(pool); - contact->uri = (pjsip_uri*)name_addr; - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "user"); - pj_strdup2(pool, &url->host, "host"); - - /* " ,sip:user2@host2\n" */ - contact = pjsip_contact_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); - name_addr = pjsip_name_addr_create(pool); - contact->uri = (pjsip_uri*)name_addr; - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "user2"); - pj_strdup2(pool, &url->host, "host2"); - - /* "Content-Type: text/html; charset=ISO-8859-4\r" */ - ctype = pjsip_ctype_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)ctype); - pj_strdup2(pool, &ctype->media.type, "text"); - pj_strdup2(pool, &ctype->media.subtype, "html"); - pj_strdup2(pool, &ctype->media.param, ";charset=ISO-8859-4"); - - /* "Route: ,\r\n" */ - routing = pjsip_route_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); - url = pjsip_sip_uri_create(pool, 0); - routing->name_addr.uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com"); - url->lr_param = 1; - - /* " \r" */ - routing = pjsip_route_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); - url = pjsip_sip_uri_create(pool, 0); - routing->name_addr.uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->host, "server10.biloxi.com"); - url->lr_param = 1; - - /* "Record-Route: ,\r\n" */ - routing = pjsip_rr_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); - url = pjsip_sip_uri_create(pool, 0); - routing->name_addr.uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->host, "server10.biloxi.com"); - url->lr_param = 0; - - /* " \n" */ - routing = pjsip_rr_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); - url = pjsip_sip_uri_create(pool, 0); - routing->name_addr.uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com"); - url->lr_param = 1; - - /* "Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c230\n" */ - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - pj_strdup2(pool, &via->transport, "SCTP"); - pj_strdup2(pool, &via->sent_by.host, "bigbox3.site3.atlanta.com"); - pj_strdup2(pool, &via->branch_param, "z9hG4bK77ef4c230"); - - /* "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n" - " ;received=192.0.2.1\r\n" */ - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - pj_strdup2(pool, &via->transport, "UDP"); - pj_strdup2(pool, &via->sent_by.host, "pc33.atlanta.com"); - pj_strdup2(pool, &via->branch_param, "z9hG4bKnashds8"); - pj_strdup2(pool, &via->recvd_param, "192.0.2.1"); - - - /* "Via: SIP/2.0/UDP 10.2.1.1, */ - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - pj_strdup2(pool, &via->transport, "UDP"); - pj_strdup2(pool, &via->sent_by.host, "10.2.1.1"); - - - /*SIP/2.0/TCP 192.168.1.1\n" */ - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - pj_strdup2(pool, &via->transport, "TCP"); - pj_strdup2(pool, &via->sent_by.host, "192.168.1.1"); - - /* "Organization: \r" */ - str.ptr = "Organization"; - str.slen = 12; - generic = pjsip_generic_string_hdr_create(pool, &str, NULL); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); - generic->hvalue.ptr = NULL; - generic->hvalue.slen = 0; - - /* "Max-Forwards: 70\n" */ - str.ptr = "Max-Forwards"; - str.slen = 12; - generic = pjsip_generic_string_hdr_create(pool, &str, NULL); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); - str.ptr = "70"; - str.slen = 2; - generic->hvalue = str; - - /* "X-Header: \r\n" */ - str.ptr = "X-Header"; - str.slen = 8; - generic = pjsip_generic_string_hdr_create(pool, &str, NULL); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); - str.ptr = NULL; - str.slen = 0; - generic->hvalue = str; - - /* P-Associated-URI:\r\n */ - str.ptr = "P-Associated-URI"; - str.slen = 16; - generic = pjsip_generic_string_hdr_create(pool, &str, NULL); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); - str.ptr = NULL; - str.slen = 0; - generic->hvalue = str; - - return msg; -} - -static pjsip_msg *create_msg1(pj_pool_t *pool) -{ - pjsip_via_hdr *via; - pjsip_route_hdr *route; - pjsip_name_addr *name_addr; - pjsip_sip_uri *url; - pjsip_max_fwd_hdr *max_fwd; - pjsip_to_hdr *to; - pjsip_from_hdr *from; - pjsip_contact_hdr *contact; - pjsip_ctype_hdr *ctype; - pjsip_cid_hdr *cid; - pjsip_clen_hdr *clen; - pjsip_cseq_hdr *cseq; - pjsip_msg *msg = pjsip_msg_create(pool, PJSIP_RESPONSE_MSG); - pjsip_msg_body *body; - - //"SIP/2.0 200 OK\r\n" - msg->line.status.code = 200; - msg->line.status.reason = pj_str("OK"); - - //"Via: SIP/2.0/SCTP server10.biloxi.com;branch=z9hG4bKnashds8;rport;received=192.0.2.1\r\n" - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - via->transport = pj_str("SCTP"); - via->sent_by.host = pj_str("server10.biloxi.com"); - via->branch_param = pj_str("z9hG4bKnashds8"); - via->rport_param = 0; - via->recvd_param = pj_str("192.0.2.1"); - - //"Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2\r\n" - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - via->transport = pj_str("UDP"); - via->sent_by.host = pj_str("bigbox3.site3.atlanta.com"); - via->branch_param = pj_str("z9hG4bK77ef4c2312983.1"); - via->recvd_param = pj_str("192.0.2.2"); - - //"Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds ;received=192.0.2.3\r\n" - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - via->transport = pj_str("UDP"); - via->sent_by.host = pj_str("pc33.atlanta.com"); - via->branch_param = pj_str("z9hG4bK776asdhds"); - via->recvd_param = pj_str("192.0.2.3"); - - //"Route: \r\n" - route = pjsip_route_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)route); - url = pjsip_sip_uri_create(pool, PJ_FALSE); - route->name_addr.uri = (pjsip_uri*)url; - url->host = pj_str("proxy.sipprovider.com"); - - //"Route: \r\n" - route = pjsip_route_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)route); - url = pjsip_sip_uri_create(pool, PJ_FALSE); - route->name_addr.uri = (pjsip_uri*)url; - url->host = pj_str("proxy.supersip.com"); - url->port = 5060; - - //"Max-Forwards: 70\r\n" - max_fwd = pjsip_max_fwd_hdr_create(pool, 70); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)max_fwd); - - //"To: Bob ;tag=a6c85cf\r\n" - to = pjsip_to_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)to); - name_addr = pjsip_name_addr_create(pool); - name_addr->display = pj_str("Bob"); - to->uri = (pjsip_uri*)name_addr; - url = pjsip_sip_uri_create(pool, PJ_FALSE); - name_addr->uri = (pjsip_uri*)url; - url->user = pj_str("bob"); - url->host = pj_str("biloxi.com"); - to->tag = pj_str("a6c85cf"); - - //"From: Alice ;tag=1928301774\r\n" - from = pjsip_from_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)from); - name_addr = pjsip_name_addr_create(pool); - name_addr->display = pj_str("Alice"); - from->uri = (pjsip_uri*)name_addr; - url = pjsip_sip_uri_create(pool, PJ_FALSE); - name_addr->uri = (pjsip_uri*)url; - url->user = pj_str("alice"); - url->host = pj_str("atlanta.com"); - from->tag = pj_str("1928301774"); - - //"Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n" - cid = pjsip_cid_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)cid); - cid->id = pj_str("a84b4c76e66710@pc33.atlanta.com"); - - //"CSeq: 314159 INVITE\r\n" - cseq = pjsip_cseq_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)cseq); - cseq->cseq = 314159; - pjsip_method_set(&cseq->method, PJSIP_INVITE_METHOD); - - //"Contact: \r\n" - contact = pjsip_contact_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); - name_addr = pjsip_name_addr_create(pool); - contact->uri = (pjsip_uri*)name_addr; - url = pjsip_sip_uri_create(pool, PJ_TRUE); - name_addr->uri = (pjsip_uri*)url; - url->user = pj_str("bob"); - url->host = pj_str("192.0.2.4"); - - //"Content-Type: application/sdp\r\n" - ctype = pjsip_ctype_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)ctype); - ctype->media.type = pj_str("application"); - ctype->media.subtype = pj_str("sdp"); - - //"Content-Length: 150\r\n" - clen = pjsip_clen_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)clen); - clen->len = 150; - - // Body - body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body); - msg->body = body; - body->content_type.type = pj_str("application"); - body->content_type.subtype = pj_str("sdp"); - body->data = (void*) - "v=0\r\n" - "o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com\r\n" - "s=-\r\n" - "t=0 0\r\n" - "c=IN IP4 pc33.atlanta.com\r\n" - "m=audio 3456 RTP/AVP 0 1 3 99\r\n" - "a=rtpmap:0 PCMU/8000\r\n"; - body->len = pj_ansi_strlen((const char*) body->data); - body->print_body = &pjsip_print_text_body; - - return msg; -} - -/*****************************************************************************/ - -static pj_status_t simple_test(void) -{ - unsigned i; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, " simple test..")); - for (i=0; i" - -#define HDR_FLAG_PARSE_FAIL 1 -#define HDR_FLAG_DONT_PRINT 2 - -struct hdr_test_t -{ - char *hname; - char *hshort_name; - char *hcontent; - int (*test)(pjsip_hdr*); - unsigned flags; -} hdr_test_data[] = -{ - { - /* Empty Accept */ - "Accept", NULL, - "", - &hdr_test_accept0 - }, - - { - /* Overflowing generic string header */ - "Accept", NULL, - "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ - "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ - "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ - "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ - "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ - "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ - "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ - "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a", - &hdr_test_success, - HDR_FLAG_PARSE_FAIL - }, - - { - /* Normal Accept */ - "Accept", NULL, - "application/*, text/plain", - &hdr_test_accept1 - }, - - { - /* Accept with params */ - "Accept", NULL, - "application/*;p1=v1, text/plain", - &hdr_test_accept2 - }, - - { - /* Empty Allow */ - "Allow", NULL, - "", - &hdr_test_allow0, - }, - - { - /* Authorization, testing which params should be quoted */ - "Authorization", NULL, - "Digest username=\"username\", realm=\"realm\", nonce=\"nonce\", " \ - "uri=\"sip:domain\", response=\"RESPONSE\", algorithm=MD5, " \ - "cnonce=\"CNONCE\", opaque=\"OPAQUE\", qop=auth, nc=00000001", - &hdr_test_authorization - }, - - { - /* Call ID */ - "Call-ID", "i", - "-.!%*_+`'~()<>:\\\"/[]?{}", - &hdr_test_cid, - }, - - { - /* Parameter belong to hparam */ - "Contact", "m", - SIMPLE_ADDR_SPEC ";p1=v1", - &hdr_test_contact0, - HDR_FLAG_DONT_PRINT - }, - - { - /* generic-param in Contact header */ - "Contact", "m", - NAME_ADDR ";" GENERIC_PARAM, - &hdr_test_contact1 - }, - - { - /* q=0 parameter in Contact header */ - "Contact", "m", - NAME_ADDR ";q=0", - &hdr_test_contact_q0, - HDR_FLAG_DONT_PRINT - }, - - { - /* q=0.5 parameter in Contact header */ - "Contact", "m", - NAME_ADDR ";q=0.5", - &hdr_test_contact_q1 - }, - - { - /* q=1 parameter in Contact header */ - "Contact", "m", - NAME_ADDR ";q=1", - &hdr_test_contact_q2 - }, - - { - /* q=1.0 parameter in Contact header */ - "Contact", "m", - NAME_ADDR ";q=1.0", - &hdr_test_contact_q3, - HDR_FLAG_DONT_PRINT - }, - - { - /* q=1.1 parameter in Contact header */ - "Contact", "m", - NAME_ADDR ";q=1.15", - &hdr_test_contact_q4 - }, - - { - /* Content-Length */ - "Content-Length", "l", - "10", - &hdr_test_content_length - }, - - { - /* Content-Type, with generic-param */ - "Content-Type", "c", - "application/sdp" ";" GENERIC_PARAM, - &hdr_test_content_type, - HDR_FLAG_DONT_PRINT - }, - - { - /* From, testing parameters and generic-param */ - "From", "f", - NAME_ADDR ";" GENERIC_PARAM, - &hdr_test_from - }, - - { - /* Proxy-Authenticate, testing which params should be quoted */ - "Proxy-Authenticate", NULL, - "Digest realm=\"realm\",domain=\"sip:domain\",nonce=\"nonce\"," \ - "opaque=\"opaque\",stale=true,algorithm=MD5,qop=\"auth\"", - &hdr_test_proxy_authenticate - }, - - { - /* Record-Route, param belong to header */ - "Record-Route", NULL, - NAME_ADDR ";" GENERIC_PARAM, - &hdr_test_record_route - }, - - { - /* Empty Supported */ - "Supported", "k", - "", - &hdr_test_supported, - }, - - { - /* To */ - "To", "t", - NAME_ADDR ";" GENERIC_PARAM, - &hdr_test_to - }, - - { - /* Via */ - "Via", "v", - "SIP/2.0/XYZ host" ";" GENERIC_PARAM, - &hdr_test_via - }, - - { - /* Via with IPv6 */ - "Via", "v", - "SIP/2.0/UDP [::1]", - &hdr_test_via_ipv6_1 - }, - - { - /* Via with IPv6 */ - "Via", "v", - "SIP/2.0/UDP [::1]:5061", - &hdr_test_via_ipv6_2 - }, - - { - /* Via with IPv6 */ - "Via", "v", - "SIP/2.0/UDP [::1];rport=5061;received=::2", - &hdr_test_via_ipv6_3 - }, - - { - /* Retry-After header with comment */ - "Retry-After", NULL, - "10(Already Pending Register)", - &hdr_test_retry_after1 - }, - - { - /* Non-ASCII UTF-8 characters in Subject */ - "Subject", NULL, - "\xC0\x81", - &hdr_test_subject_utf - } -}; - -static int hdr_test_success(pjsip_hdr *h) -{ - PJ_UNUSED_ARG(h); - return 0; -} - -/* "" */ -static int hdr_test_accept0(pjsip_hdr *h) -{ - pjsip_accept_hdr *hdr = (pjsip_accept_hdr*)h; - - if (h->type != PJSIP_H_ACCEPT) - return -1010; - - if (hdr->count != 0) - return -1020; - - return 0; -} - -/* "application/ *, text/plain\r\n" */ -static int hdr_test_accept1(pjsip_hdr *h) -{ - pjsip_accept_hdr *hdr = (pjsip_accept_hdr*)h; - - if (h->type != PJSIP_H_ACCEPT) - return -1110; - - if (hdr->count != 2) - return -1120; - - if (pj_strcmp2(&hdr->values[0], "application/*")) - return -1130; - - if (pj_strcmp2(&hdr->values[1], "text/plain")) - return -1140; - - return 0; -} - -/* "application/ *;p1=v1, text/plain\r\n" */ -static int hdr_test_accept2(pjsip_hdr *h) -{ - pjsip_accept_hdr *hdr = (pjsip_accept_hdr*)h; - - if (h->type != PJSIP_H_ACCEPT) - return -1210; - - if (hdr->count != 2) - return -1220; - - if (pj_strcmp2(&hdr->values[0], "application/*;p1=v1")) - return -1230; - - if (pj_strcmp2(&hdr->values[1], "text/plain")) - return -1240; - - return 0; -} - -/* "" */ -static int hdr_test_allow0(pjsip_hdr *h) -{ - pjsip_allow_hdr *hdr = (pjsip_allow_hdr*)h; - - if (h->type != PJSIP_H_ALLOW) - return -1310; - - if (hdr->count != 0) - return -1320; - - return 0; - -} - - -/* - "Digest username=\"username\", realm=\"realm\", nonce=\"nonce\", " \ - "uri=\"sip:domain\", response=\"RESPONSE\", algorithm=MD5, " \ - "cnonce=\"CNONCE\", opaque=\"OPAQUE\", qop=auth, nc=00000001", - */ -static int hdr_test_authorization(pjsip_hdr *h) -{ - pjsip_authorization_hdr *hdr = (pjsip_authorization_hdr*)h; - - if (h->type != PJSIP_H_AUTHORIZATION) - return -1410; - - if (pj_strcmp2(&hdr->scheme, "Digest")) - return -1420; - - if (pj_strcmp2(&hdr->credential.digest.username, "username")) - return -1421; - - if (pj_strcmp2(&hdr->credential.digest.realm, "realm")) - return -1422; - - if (pj_strcmp2(&hdr->credential.digest.nonce, "nonce")) - return -1423; - - if (pj_strcmp2(&hdr->credential.digest.uri, "sip:domain")) - return -1424; - - if (pj_strcmp2(&hdr->credential.digest.response, "RESPONSE")) - return -1425; - - if (pj_strcmp2(&hdr->credential.digest.algorithm, "MD5")) - return -1426; - - if (pj_strcmp2(&hdr->credential.digest.cnonce, "CNONCE")) - return -1427; - - if (pj_strcmp2(&hdr->credential.digest.opaque, "OPAQUE")) - return -1428; - - if (pj_strcmp2(&hdr->credential.digest.qop, "auth")) - return -1429; - - if (pj_strcmp2(&hdr->credential.digest.nc, "00000001")) - return -1430; - - return 0; -} - - -/* - "-.!%*_+`'~()<>:\\\"/[]?{}\r\n" - */ -static int hdr_test_cid(pjsip_hdr *h) -{ - pjsip_cid_hdr *hdr = (pjsip_cid_hdr*)h; - - if (h->type != PJSIP_H_CALL_ID) - return -1510; - - if (pj_strcmp2(&hdr->id, "-.!%*_+`'~()<>:\\\"/[]?{}")) - return -1520; - - return 0; -} - -/* - #define SIMPLE_ADDR_SPEC "sip:host" - */ -static int test_simple_addr_spec(pjsip_uri *uri) -{ - pjsip_sip_uri *sip_uri = (pjsip_sip_uri *)pjsip_uri_get_uri(uri); - - if (!PJSIP_URI_SCHEME_IS_SIP(uri)) - return -900; - - if (pj_strcmp2(&sip_uri->host, "host")) - return -910; - - if (sip_uri->port != 0) - return -920; - - return 0; -} - -/* -#define PARAM_CHAR "][/:&+$" -#define SIMPLE_ADDR_SPEC "sip:host" -#define ADDR_SPEC SIMPLE_ADDR_SPEC ";"PARAM_CHAR"="PARAM_CHAR ";p1=\";\"" -#define NAME_ADDR "<" ADDR_SPEC ">" - */ -static int nameaddr_test(void *uri) -{ - pjsip_sip_uri *sip_uri=(pjsip_sip_uri *)pjsip_uri_get_uri((pjsip_uri*)uri); - pjsip_param *param; - int rc; - - if (!PJSIP_URI_SCHEME_IS_SIP(uri)) - return -930; - - rc = test_simple_addr_spec((pjsip_uri*)sip_uri); - if (rc != 0) - return rc; - - if (pj_list_size(&sip_uri->other_param) != 2) - return -940; - - param = sip_uri->other_param.next; - - if (pj_strcmp2(¶m->name, PARAM_CHAR)) - return -942; - - if (pj_strcmp2(¶m->value, PARAM_CHAR)) - return -943; - - param = param->next; - if (pj_strcmp2(¶m->name, "p1")) - return -942; - if (pj_strcmp2(¶m->value, "\";\"")) - return -943; - - return 0; -} - -/* -#define GENERIC_PARAM "p0=a;p1=\"ab:;cd\";p2=ab%3acd;p3" - */ -static int generic_param_test(pjsip_param *param_head) -{ - pjsip_param *param; - - if (pj_list_size(param_head) != 4) - return -950; - - param = param_head->next; - - if (pj_strcmp2(¶m->name, "p0")) - return -952; - if (pj_strcmp2(¶m->value, "a")) - return -953; - - param = param->next; - if (pj_strcmp2(¶m->name, "p1")) - return -954; - if (pj_strcmp2(¶m->value, "\"ab:;cd\"")) - return -955; - - param = param->next; - if (pj_strcmp2(¶m->name, "p2")) - return -956; - if (pj_strcmp2(¶m->value, "ab:cd")) - return -957; - - param = param->next; - if (pj_strcmp2(¶m->name, "p3")) - return -958; - if (pj_strcmp2(¶m->value, "")) - return -959; - - return 0; -} - - - -/* - SIMPLE_ADDR_SPEC ";p1=v1\r\n" - */ -static int hdr_test_contact0(pjsip_hdr *h) -{ - pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; - pjsip_param *param; - int rc; - - if (h->type != PJSIP_H_CONTACT) - return -1610; - - rc = test_simple_addr_spec(hdr->uri); - if (rc != 0) - return rc; - - if (pj_list_size(&hdr->other_param) != 1) - return -1620; - - param = hdr->other_param.next; - - if (pj_strcmp2(¶m->name, "p1")) - return -1630; - - if (pj_strcmp2(¶m->value, "v1")) - return -1640; - - return 0; -} - -/* - NAME_ADDR GENERIC_PARAM "\r\n", - */ -static int hdr_test_contact1(pjsip_hdr *h) -{ - pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; - int rc; - - if (h->type != PJSIP_H_CONTACT) - return -1710; - - rc = nameaddr_test(hdr->uri); - if (rc != 0) - return rc; - - rc = generic_param_test(&hdr->other_param); - if (rc != 0) - return rc; - - return 0; -} - -/* - NAME_ADDR ";q=0" - */ -static int hdr_test_contact_q0(pjsip_hdr *h) -{ - pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; - int rc; - - if (h->type != PJSIP_H_CONTACT) - return -1710; - - rc = nameaddr_test(hdr->uri); - if (rc != 0) - return rc; - - if (hdr->q1000 != 0) - return -1711; - - return 0; -} - -/* - NAME_ADDR ";q=0.5" - */ -static int hdr_test_contact_q1(pjsip_hdr *h) -{ - pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; - int rc; - - if (h->type != PJSIP_H_CONTACT) - return -1710; - - rc = nameaddr_test(hdr->uri); - if (rc != 0) - return rc; - - if (hdr->q1000 != 500) - return -1712; - - return 0; -} - -/* - NAME_ADDR ";q=1" - */ -static int hdr_test_contact_q2(pjsip_hdr *h) -{ - pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; - int rc; - - if (h->type != PJSIP_H_CONTACT) - return -1710; - - rc = nameaddr_test(hdr->uri); - if (rc != 0) - return rc; - - if (hdr->q1000 != 1000) - return -1713; - - return 0; -} - -/* - NAME_ADDR ";q=1.0" - */ -static int hdr_test_contact_q3(pjsip_hdr *h) -{ - pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; - int rc; - - if (h->type != PJSIP_H_CONTACT) - return -1710; - - rc = nameaddr_test(hdr->uri); - if (rc != 0) - return rc; - - if (hdr->q1000 != 1000) - return -1714; - - return 0; -} - -/* - NAME_ADDR ";q=1.15" - */ -static int hdr_test_contact_q4(pjsip_hdr *h) -{ - pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; - int rc; - - if (h->type != PJSIP_H_CONTACT) - return -1710; - - rc = nameaddr_test(hdr->uri); - if (rc != 0) - return rc; - - if (hdr->q1000 != 1150) - return -1715; - - return 0; -} - -/* - "10" - */ -static int hdr_test_content_length(pjsip_hdr *h) -{ - pjsip_clen_hdr *hdr = (pjsip_clen_hdr*)h; - - if (h->type != PJSIP_H_CONTENT_LENGTH) - return -1810; - - if (hdr->len != 10) - return -1820; - - return 0; -} - -/* - "application/sdp" GENERIC_PARAM, - */ -static int hdr_test_content_type(pjsip_hdr *h) -{ - pjsip_ctype_hdr *hdr = (pjsip_ctype_hdr*)h; - - if (h->type != PJSIP_H_CONTENT_TYPE) - return -1910; - - if (pj_strcmp2(&hdr->media.type, "application")) - return -1920; - - if (pj_strcmp2(&hdr->media.subtype, "sdp")) - return -1930; - - /* Currently, if the media parameter contains escaped characters, - * pjsip will print the parameter unescaped. - */ - PJ_TODO(FIX_PARAMETER_IN_MEDIA_TYPE); - - if (pj_strcmp2(&hdr->media.param, ";" GENERIC_PARAM_PARSED)) - return -1940; - - return 0; -} - -/* - NAME_ADDR GENERIC_PARAM, - */ -static int hdr_test_from(pjsip_hdr *h) -{ - pjsip_from_hdr *hdr = (pjsip_from_hdr*)h; - int rc; - - if (h->type != PJSIP_H_FROM) - return -2010; - - rc = nameaddr_test(hdr->uri); - if (rc != 0) - return rc; - - rc = generic_param_test(&hdr->other_param); - if (rc != 0) - return rc; - - return 0; -} - -/* - "Digest realm=\"realm\", domain=\"sip:domain\", nonce=\"nonce\", " \ - "opaque=\"opaque\", stale=true, algorithm=MD5, qop=\"auth\"", - */ -static int hdr_test_proxy_authenticate(pjsip_hdr *h) -{ - pjsip_proxy_authenticate_hdr *hdr = (pjsip_proxy_authenticate_hdr*)h; - - if (h->type != PJSIP_H_PROXY_AUTHENTICATE) - return -2110; - - if (pj_strcmp2(&hdr->scheme, "Digest")) - return -2120; - - if (pj_strcmp2(&hdr->challenge.digest.realm, "realm")) - return -2130; - - if (pj_strcmp2(&hdr->challenge.digest.domain, "sip:domain")) - return -2140; - - if (pj_strcmp2(&hdr->challenge.digest.nonce, "nonce")) - return -2150; - - if (pj_strcmp2(&hdr->challenge.digest.opaque, "opaque")) - return -2160; - - if (hdr->challenge.digest.stale != 1) - return -2170; - - if (pj_strcmp2(&hdr->challenge.digest.algorithm, "MD5")) - return -2180; - - if (pj_strcmp2(&hdr->challenge.digest.qop, "auth")) - return -2190; - - return 0; -} - -/* - NAME_ADDR GENERIC_PARAM, - */ -static int hdr_test_record_route(pjsip_hdr *h) -{ - pjsip_rr_hdr *hdr = (pjsip_rr_hdr*)h; - int rc; - - if (h->type != PJSIP_H_RECORD_ROUTE) - return -2210; - - rc = nameaddr_test(&hdr->name_addr); - if (rc != 0) - return rc; - - rc = generic_param_test(&hdr->other_param); - if (rc != 0) - return rc; - - return 0; - -} - -/* - " \r\n" - */ -static int hdr_test_supported(pjsip_hdr *h) -{ - pjsip_supported_hdr *hdr = (pjsip_supported_hdr*)h; - - if (h->type != PJSIP_H_SUPPORTED) - return -2310; - - if (hdr->count != 0) - return -2320; - - return 0; -} - -/* - NAME_ADDR GENERIC_PARAM, - */ -static int hdr_test_to(pjsip_hdr *h) -{ - pjsip_to_hdr *hdr = (pjsip_to_hdr*)h; - int rc; - - if (h->type != PJSIP_H_TO) - return -2410; - - rc = nameaddr_test(hdr->uri); - if (rc != 0) - return rc; - - rc = generic_param_test(&hdr->other_param); - if (rc != 0) - return rc; - - return 0; -} - -/* - "SIP/2.0 host" GENERIC_PARAM - */ -static int hdr_test_via(pjsip_hdr *h) -{ - pjsip_via_hdr *hdr = (pjsip_via_hdr*)h; - int rc; - - if (h->type != PJSIP_H_VIA) - return -2510; - - if (pj_strcmp2(&hdr->transport, "XYZ")) - return -2515; - - if (pj_strcmp2(&hdr->sent_by.host, "host")) - return -2520; - - if (hdr->sent_by.port != 0) - return -2530; - - rc = generic_param_test(&hdr->other_param); - if (rc != 0) - return rc; - - return 0; -} - - -/* - "SIP/2.0/UDP [::1]" - */ -static int hdr_test_via_ipv6_1(pjsip_hdr *h) -{ - pjsip_via_hdr *hdr = (pjsip_via_hdr*)h; - - if (h->type != PJSIP_H_VIA) - return -2610; - - if (pj_strcmp2(&hdr->transport, "UDP")) - return -2615; - - if (pj_strcmp2(&hdr->sent_by.host, "::1")) - return -2620; - - if (hdr->sent_by.port != 0) - return -2630; - - return 0; -} - -/* "SIP/2.0/UDP [::1]:5061" */ -static int hdr_test_via_ipv6_2(pjsip_hdr *h) -{ - pjsip_via_hdr *hdr = (pjsip_via_hdr*)h; - - if (h->type != PJSIP_H_VIA) - return -2710; - - if (pj_strcmp2(&hdr->transport, "UDP")) - return -2715; - - if (pj_strcmp2(&hdr->sent_by.host, "::1")) - return -2720; - - if (hdr->sent_by.port != 5061) - return -2730; - - return 0; -} - -/* "SIP/2.0/UDP [::1];rport=5061;received=::2" */ -static int hdr_test_via_ipv6_3(pjsip_hdr *h) -{ - pjsip_via_hdr *hdr = (pjsip_via_hdr*)h; - - if (h->type != PJSIP_H_VIA) - return -2810; - - if (pj_strcmp2(&hdr->transport, "UDP")) - return -2815; - - if (pj_strcmp2(&hdr->sent_by.host, "::1")) - return -2820; - - if (hdr->sent_by.port != 0) - return -2830; - - if (pj_strcmp2(&hdr->recvd_param, "::2")) - return -2840; - - if (hdr->rport_param != 5061) - return -2850; - - return 0; -} - -/* "10(Already Pending Register)" */ -static int hdr_test_retry_after1(pjsip_hdr *h) -{ - pjsip_retry_after_hdr *hdr = (pjsip_retry_after_hdr*)h; - - if (h->type != PJSIP_H_RETRY_AFTER) - return -2910; - - if (hdr->ivalue != 10) - return -2920; - - if (pj_strcmp2(&hdr->comment, "Already Pending Register")) - return -2930; - - return 0; -} - -/* Subject: \xC0\x81 */ -static int hdr_test_subject_utf(pjsip_hdr *h) -{ - pjsip_subject_hdr *hdr = (pjsip_subject_hdr*)h; - - if (pj_strcmp2(&h->name, "Subject")) - return -2950; - - if (pj_strcmp2(&hdr->hvalue, "\xC0\x81")) - return -2960; - - return 0; -} - -static int hdr_test(void) -{ - unsigned i; - - PJ_LOG(3,(THIS_FILE, " testing header parsing..")); - - for (i=0; ihname); - len = strlen(test->hcontent); -#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0 - PJ_ASSERT_RETURN(len < sizeof(hcontent), PJSIP_EMSGTOOLONG); - strcpy(hcontent, test->hcontent); -#else - hcontent = test->hcontent; -#endif - - parsed_hdr1 = (pjsip_hdr*) pjsip_parse_hdr(pool, &hname, - hcontent, len, - &parsed_len); - if (parsed_hdr1 == NULL) { - if (test->flags & HDR_FLAG_PARSE_FAIL) { - pj_pool_release(pool); - continue; - } - PJ_LOG(3,(THIS_FILE, " error parsing header %s: %s", test->hname, test->hcontent)); - return -500; - } - - /* Test the parsing result */ - if (test->test && (rc=test->test(parsed_hdr1)) != 0) { - PJ_LOG(3,(THIS_FILE, " validation failed for header %s: %s", test->hname, test->hcontent)); - PJ_LOG(3,(THIS_FILE, " error code is %d", rc)); - return -502; - } - -#if 1 - /* Parse with hshortname, if present */ - if (test->hshort_name) { - hname = pj_str(test->hshort_name); - len = strlen(test->hcontent); -#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0 - PJ_ASSERT_RETURN(len < sizeof(hcontent), PJSIP_EMSGTOOLONG); - strcpy(hcontent, test->hcontent); -#else - hcontent = test->hcontent; -#endif - - parsed_hdr2 = (pjsip_hdr*) pjsip_parse_hdr(pool, &hname, hcontent, len, &parsed_len); - if (parsed_hdr2 == NULL) { - PJ_LOG(3,(THIS_FILE, " error parsing header %s: %s", test->hshort_name, test->hcontent)); - return -510; - } - } -#endif - - if (test->flags & HDR_FLAG_DONT_PRINT) { - pj_pool_release(pool); - continue; - } - - /* Print the original header */ - input = (char*) pj_pool_alloc(pool, 1024); - len = pj_ansi_snprintf(input, 1024, "%s: %s", test->hname, test->hcontent); - if (len < 1 || len >= 1024) - return -520; - - /* Print the parsed header*/ - output = (char*) pj_pool_alloc(pool, 1024); - len = pjsip_hdr_print_on(parsed_hdr1, output, 1024); - if (len < 1 || len >= 1024) { - PJ_LOG(3,(THIS_FILE, " header too long: %s: %s", test->hname, test->hcontent)); - return -530; - } - output[len] = 0; - - if (strcmp(input, output) != 0) { - PJ_LOG(3,(THIS_FILE, " header character by character comparison failed.")); - PJ_LOG(3,(THIS_FILE, " original header=|%s|", input)); - PJ_LOG(3,(THIS_FILE, " parsed header =|%s|", output)); - return -540; - } - - pj_pool_release(pool); - } - - return 0; -} - - -/*****************************************************************************/ - -int msg_test(void) -{ - enum { COUNT = 1, DETECT=0, PARSE=1, PRINT=2 }; - struct { - unsigned detect; - unsigned parse; - unsigned print; - } run[COUNT]; - unsigned i, max, avg_len; - char desc[250]; - pj_status_t status; - - status = hdr_test(); - if (status != 0) - return status; - - status = simple_test(); - if (status != PJ_SUCCESS) - return status; - -#if INCLUDE_BENCHMARKS - for (i=0; i max) max = run[i].detect; - - PJ_LOG(3,("", " Maximum message detection/sec=%u", max)); - - pj_ansi_sprintf(desc, "Number of SIP messages " - "can be pre-parse by pjsip_find_msg() " - "per second (tested with %d message sets with " - "average message length of " - "%d bytes)", (int)PJ_ARRAY_SIZE(test_array), avg_len); - report_ival("msg-detect-per-sec", max, "msg/sec", desc); - - /* Print maximum parse/sec */ - for (i=0, max=0; i max) max = run[i].parse; - - PJ_LOG(3,("", " Maximum message parsing/sec=%u", max)); - - pj_ansi_sprintf(desc, "Number of SIP messages " - "can be parsed by pjsip_parse_msg() " - "per second (tested with %d message sets with " - "average message length of " - "%d bytes)", (int)PJ_ARRAY_SIZE(test_array), avg_len); - report_ival("msg-parse-per-sec", max, "msg/sec", desc); - - /* Msg parsing bandwidth */ - report_ival("msg-parse-bandwidth-mb", avg_len*max/1000000, "MB/sec", - "Message parsing bandwidth in megabytes (number of megabytes" - " worth of SIP messages that can be parsed per second). " - "The value is derived from msg-parse-per-sec above."); - - - /* Print maximum print/sec */ - for (i=0, max=0; i max) max = run[i].print; - - PJ_LOG(3,("", " Maximum message print/sec=%u", max)); - - pj_ansi_sprintf(desc, "Number of SIP messages " - "can be printed by pjsip_msg_print()" - " per second (tested with %d message sets with " - "average message length of " - "%d bytes)", (int)PJ_ARRAY_SIZE(test_array), avg_len); - - report_ival("msg-print-per-sec", max, "msg/sec", desc); - - /* Msg print bandwidth */ - report_ival("msg-printed-bandwidth-mb", avg_len*max/1000000, "MB/sec", - "Message print bandwidth in megabytes (total size of " - "SIP messages printed per second). " - "The value is derived from msg-print-per-sec above."); - -#endif /* INCLUDE_BENCHMARKS */ - - return PJ_SUCCESS; -} - - - - diff --git a/pjsip/src/test-pjsip/regc_test.c b/pjsip/src/test-pjsip/regc_test.c deleted file mode 100644 index 0d668782..00000000 --- a/pjsip/src/test-pjsip/regc_test.c +++ /dev/null @@ -1,1162 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ -#include "test.h" -#include -#include -#include - -#define THIS_FILE "regc_test.c" - - -/************************************************************************/ -/* A module to inject error into outgoing sending operation */ -static pj_status_t mod_send_on_tx_request(pjsip_tx_data *tdata); - -static struct -{ - pjsip_module mod; - unsigned count; - unsigned count_before_reject; -} send_mod = -{ - { - NULL, NULL, /* prev, next. */ - { "mod-send", 8 }, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - NULL, /* on_rx_request() */ - NULL, /* on_rx_response() */ - &mod_send_on_tx_request, /* on_tx_request. */ - NULL, /* on_tx_response() */ - NULL, /* on_tsx_state() */ - }, - 0, - 0xFFFF -}; - - -static pj_status_t mod_send_on_tx_request(pjsip_tx_data *tdata) -{ - PJ_UNUSED_ARG(tdata); - - if (++send_mod.count > send_mod.count_before_reject) - return PJ_ECANCELLED; - else - return PJ_SUCCESS; -}; - - -/************************************************************************/ -/* Registrar for testing */ -static pj_bool_t regs_rx_request(pjsip_rx_data *rdata); - -enum contact_op -{ - NONE, /* don't put Contact header */ - EXACT, /* return exact contact */ - MODIFIED, /* return modified Contact header */ -}; - -struct registrar_cfg -{ - pj_bool_t respond; /* should it respond at all */ - unsigned status_code; /* final response status code */ - pj_bool_t authenticate; /* should we authenticate? */ - enum contact_op contact_op; /* What should we do with Contact */ - unsigned expires_param; /* non-zero to put in expires param */ - unsigned expires; /* non-zero to put in Expires header*/ - - pj_str_t more_contacts; /* Additional Contact headers to put*/ -}; - -static struct registrar -{ - pjsip_module mod; - struct registrar_cfg cfg; - unsigned response_cnt; -} registrar = -{ - { - NULL, NULL, /* prev, next. */ - { "registrar", 9 }, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - ®s_rx_request, /* on_rx_request() */ - NULL, /* on_rx_response() */ - NULL, /* on_tx_request. */ - NULL, /* on_tx_response() */ - NULL, /* on_tsx_state() */ - } -}; - -static pj_bool_t regs_rx_request(pjsip_rx_data *rdata) -{ - pjsip_msg *msg = rdata->msg_info.msg; - pjsip_hdr hdr_list; - int code; - pj_status_t status; - - if (msg->line.req.method.id != PJSIP_REGISTER_METHOD) - return PJ_FALSE; - - if (!registrar.cfg.respond) - return PJ_TRUE; - - pj_list_init(&hdr_list); - - if (registrar.cfg.authenticate && - pjsip_msg_find_hdr(msg, PJSIP_H_AUTHORIZATION, NULL)==NULL) - { - pjsip_generic_string_hdr *hwww; - const pj_str_t hname = pj_str("WWW-Authenticate"); - const pj_str_t hvalue = pj_str("Digest realm=\"test\""); - - hwww = pjsip_generic_string_hdr_create(rdata->tp_info.pool, &hname, - &hvalue); - pj_list_push_back(&hdr_list, hwww); - - code = 401; - - } else { - if (registrar.cfg.contact_op == EXACT || - registrar.cfg.contact_op == MODIFIED) - { - pjsip_hdr *hsrc; - - for (hsrc=msg->hdr.next; hsrc!=&msg->hdr; hsrc=hsrc->next) { - pjsip_contact_hdr *hdst; - - if (hsrc->type != PJSIP_H_CONTACT) - continue; - - hdst = (pjsip_contact_hdr*) - pjsip_hdr_clone(rdata->tp_info.pool, hsrc); - - if (hdst->expires==0) - continue; - - if (registrar.cfg.contact_op == MODIFIED) { - if (PJSIP_URI_SCHEME_IS_SIP(hdst->uri) || - PJSIP_URI_SCHEME_IS_SIPS(hdst->uri)) - { - pjsip_sip_uri *sip_uri = (pjsip_sip_uri*) - pjsip_uri_get_uri(hdst->uri); - sip_uri->host = pj_str("x-modified-host"); - sip_uri->port = 1; - } - } - - if (registrar.cfg.expires_param) - hdst->expires = registrar.cfg.expires_param; - - pj_list_push_back(&hdr_list, hdst); - } - } - - if (registrar.cfg.more_contacts.slen) { - pjsip_generic_string_hdr *hcontact; - const pj_str_t hname = pj_str("Contact"); - - hcontact = pjsip_generic_string_hdr_create(rdata->tp_info.pool, &hname, - ®istrar.cfg.more_contacts); - pj_list_push_back(&hdr_list, hcontact); - } - - if (registrar.cfg.expires) { - pjsip_expires_hdr *hexp; - - hexp = pjsip_expires_hdr_create(rdata->tp_info.pool, - registrar.cfg.expires); - pj_list_push_back(&hdr_list, hexp); - } - - registrar.response_cnt++; - - code = registrar.cfg.status_code; - } - - status = pjsip_endpt_respond(endpt, NULL, rdata, code, NULL, - &hdr_list, NULL, NULL); - pj_assert(status == PJ_SUCCESS); - - return PJ_TRUE; -} - - -/************************************************************************/ -/* Client registration test session */ -struct client -{ - /* Result/expected result */ - int error; - int code; - pj_bool_t have_reg; - int expiration; - unsigned contact_cnt; - pj_bool_t auth; - - /* Commands */ - pj_bool_t destroy_on_cb; - - /* Status */ - pj_bool_t done; - - /* Additional results */ - int interval; - int next_reg; -}; - -/* regc callback */ -static void client_cb(struct pjsip_regc_cbparam *param) -{ - struct client *client = (struct client*) param->token; - pjsip_regc_info info; - pj_status_t status; - - client->done = PJ_TRUE; - - status = pjsip_regc_get_info(param->regc, &info); - pj_assert(status == PJ_SUCCESS); - - client->error = (param->status != PJ_SUCCESS); - client->code = param->code; - - if (client->error) - return; - - client->have_reg = info.auto_reg && info.interval>0 && - param->expiration>0; - client->expiration = param->expiration; - client->contact_cnt = param->contact_cnt; - client->interval = info.interval; - client->next_reg = info.next_reg; - - if (client->destroy_on_cb) - pjsip_regc_destroy(param->regc); -} - - -/* Generic client test session */ -static struct client client_result; -static int do_test(const char *title, - const struct registrar_cfg *srv_cfg, - const struct client *client_cfg, - const pj_str_t *registrar_uri, - unsigned contact_cnt, - const pj_str_t contacts[], - unsigned expires, - pj_bool_t leave_session, - pjsip_regc **p_regc) -{ - pjsip_regc *regc; - unsigned i; - const pj_str_t aor = pj_str(""); - pjsip_tx_data *tdata; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, " %s", title)); - - /* Modify registrar settings */ - pj_memcpy(®istrar.cfg, srv_cfg, sizeof(*srv_cfg)); - - pj_bzero(&client_result, sizeof(client_result)); - client_result.destroy_on_cb = client_cfg->destroy_on_cb; - - status = pjsip_regc_create(endpt, &client_result, &client_cb, ®c); - if (status != PJ_SUCCESS) - return -100; - - status = pjsip_regc_init(regc, registrar_uri, &aor, &aor, contact_cnt, - contacts, expires ? expires : 60); - if (status != PJ_SUCCESS) { - pjsip_regc_destroy(regc); - return -110; - } - - if (client_cfg->auth) { - pjsip_cred_info cred; - - pj_bzero(&cred, sizeof(cred)); - cred.realm = pj_str("*"); - cred.scheme = pj_str("digest"); - cred.username = pj_str("user"); - cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; - cred.data = pj_str("password"); - - status = pjsip_regc_set_credentials(regc, 1, &cred); - if (status != PJ_SUCCESS) { - pjsip_regc_destroy(regc); - return -115; - } - } - - /* Register */ - status = pjsip_regc_register(regc, PJ_TRUE, &tdata); - if (status != PJ_SUCCESS) { - pjsip_regc_destroy(regc); - return -120; - } - status = pjsip_regc_send(regc, tdata); - - /* That's it, wait until the callback is sent */ - for (i=0; i<600 && !client_result.done; ++i) { - flush_events(100); - } - - if (!client_result.done) { - PJ_LOG(3,(THIS_FILE, " error: test has timed out")); - pjsip_regc_destroy(regc); - return -200; - } - - /* Destroy the regc, we're done with the test, unless we're - * instructed to leave the session open. - */ - if (!leave_session && !client_cfg->destroy_on_cb) - pjsip_regc_destroy(regc); - - /* Compare results with expected results */ - - if (client_result.error != client_cfg->error) { - PJ_LOG(3,(THIS_FILE, " error: expecting err=%d, got err=%d", - client_cfg->error, client_result.error)); - return -210; - } - if (client_result.code != client_cfg->code) { - PJ_LOG(3,(THIS_FILE, " error: expecting code=%d, got code=%d", - client_cfg->code, client_result.code)); - return -220; - } - if (client_result.expiration != client_cfg->expiration) { - PJ_LOG(3,(THIS_FILE, " error: expecting expiration=%d, got expiration=%d", - client_cfg->expiration, client_result.expiration)); - return -240; - } - if (client_result.contact_cnt != client_cfg->contact_cnt) { - PJ_LOG(3,(THIS_FILE, " error: expecting contact_cnt=%d, got contact_cnt=%d", - client_cfg->contact_cnt, client_result.contact_cnt)); - return -250; - } - if (client_result.have_reg != client_cfg->have_reg) { - PJ_LOG(3,(THIS_FILE, " error: expecting have_reg=%d, got have_reg=%d", - client_cfg->have_reg, client_result.have_reg)); - return -260; - } - if (client_result.interval != client_result.expiration) { - PJ_LOG(3,(THIS_FILE, " error: interval (%d) is different than expiration (%d)", - client_result.interval, client_result.expiration)); - return -270; - } - if (client_result.expiration > 0 && client_result.next_reg < 1) { - PJ_LOG(3,(THIS_FILE, " error: next_reg=%d, expecting positive number because expiration is %d", - client_result.next_reg, client_result.expiration)); - return -280; - } - - /* Looks like everything is okay. */ - if (leave_session) { - *p_regc = regc; - } - - return 0; -} - - -/************************************************************************/ -/* Customized tests */ - -/* Check that client is sending register refresh */ -static int keep_alive_test(const pj_str_t *registrar_uri) -{ - enum { TIMEOUT = 40 }; - struct registrar_cfg server_cfg = - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_FALSE, EXACT, TIMEOUT, 0, {NULL, 0}}; - struct client client_cfg = - /* error code have_reg expiration contact_cnt auth? destroy*/ - { PJ_FALSE, 200, PJ_TRUE, TIMEOUT, 1, PJ_FALSE,PJ_FALSE}; - pj_str_t contact = pj_str(""); - - - pjsip_regc *regc; - unsigned i; - int ret; - - ret = do_test("register refresh (takes ~40 secs)", &server_cfg, &client_cfg, registrar_uri, - 1, &contact, TIMEOUT, PJ_TRUE, ®c); - if (ret != 0) - return ret; - - /* Reset server response_cnt */ - registrar.response_cnt = 0; - - /* Wait until keep-alive/refresh is done */ - for (i=0; i<(TIMEOUT-1)*10 && registrar.response_cnt==0; ++i) { - flush_events(100); - } - - if (registrar.response_cnt==0) { - PJ_LOG(3,(THIS_FILE, " error: no refresh is received")); - return -400; - } - - if (client_result.error) { - PJ_LOG(3,(THIS_FILE, " error: got error")); - return -410; - } - if (client_result.code != 200) { - PJ_LOG(3,(THIS_FILE, " error: expecting code=%d, got code=%d", - 200, client_result.code)); - return -420; - } - if (client_result.expiration != TIMEOUT) { - PJ_LOG(3,(THIS_FILE, " error: expecting expiration=%d, got expiration=%d", - TIMEOUT, client_result.expiration)); - return -440; - } - if (client_result.contact_cnt != 1) { - PJ_LOG(3,(THIS_FILE, " error: expecting contact_cnt=%d, got contact_cnt=%d", - TIMEOUT, client_result.contact_cnt)); - return -450; - } - if (client_result.have_reg == 0) { - PJ_LOG(3,(THIS_FILE, " error: expecting have_reg=%d, got have_reg=%d", - 1, client_result.have_reg)); - return -460; - } - if (client_result.interval != TIMEOUT) { - PJ_LOG(3,(THIS_FILE, " error: interval (%d) is different than expiration (%d)", - client_result.interval, TIMEOUT)); - return -470; - } - if (client_result.expiration > 0 && client_result.next_reg < 1) { - PJ_LOG(3,(THIS_FILE, " error: next_reg=%d, expecting positive number because expiration is %d", - client_result.next_reg, client_result.expiration)); - return -480; - } - - /* Success */ - pjsip_regc_destroy(regc); - return 0; -} - - -/* Send error on refresh */ -static int refresh_error(const pj_str_t *registrar_uri, - pj_bool_t destroy_on_cb) -{ - enum { TIMEOUT = 40 }; - struct registrar_cfg server_cfg = - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_FALSE, EXACT, TIMEOUT, 0, {NULL, 0}}; - struct client client_cfg = - /* error code have_reg expiration contact_cnt auth? destroy*/ - { PJ_FALSE, 200, PJ_TRUE, TIMEOUT, 1, PJ_FALSE,PJ_FALSE}; - pj_str_t contact = pj_str(""); - - pjsip_regc *regc; - unsigned i; - int ret; - - ret = do_test("refresh error (takes ~40 secs)", &server_cfg, &client_cfg, registrar_uri, - 1, &contact, TIMEOUT, PJ_TRUE, ®c); - if (ret != 0) - return ret; - - /* Reset server response_cnt */ - registrar.response_cnt = 0; - - /* inject error for transmission */ - send_mod.count = 0; - send_mod.count_before_reject = 0; - - /* reconfigure client */ - client_result.done = PJ_FALSE; - client_result.destroy_on_cb = destroy_on_cb; - - /* Wait until keep-alive/refresh is done */ - for (i=0; i", 7 }, - { "", 7 }, - { "", 7 } - }; - - pjsip_regc *regc; - pjsip_contact_hdr *h1, *h2; - pjsip_sip_uri *u1, *u2; - unsigned i; - pj_status_t status; - pjsip_tx_data *tdata = NULL; - int ret = 0; - - /* initially only has 1 contact */ - ret = do_test("update test", &server_cfg, &client_cfg, registrar_uri, - 1, &contacts[0], TIMEOUT, PJ_TRUE, ®c); - if (ret != 0) { - return -600; - } - - /***** - * replace the contact with new one - */ - PJ_LOG(3,(THIS_FILE, " replacing contact")); - status = pjsip_regc_update_contact(regc, 1, &contacts[1]); - if (status != PJ_SUCCESS) { - ret = -610; - goto on_return; - } - - status = pjsip_regc_register(regc, PJ_TRUE, &tdata); - if (status != PJ_SUCCESS) { - ret = -620; - goto on_return; - } - - /* Check that the REGISTER contains two Contacts: - * - ;expires=0, - * - - */ - h1 = (pjsip_contact_hdr*) - pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL); - if (!h1) { - ret = -630; - goto on_return; - } - if ((void*)h1->next == (void*)&tdata->msg->hdr) - h2 = NULL; - else - h2 = (pjsip_contact_hdr*) - pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h1->next); - if (!h2) { - ret = -640; - goto on_return; - } - /* must not have other Contact header */ - if ((void*)h2->next != (void*)&tdata->msg->hdr && - pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h2->next) != NULL) - { - ret = -645; - goto on_return; - } - - u1 = (pjsip_sip_uri*) pjsip_uri_get_uri(h1->uri); - u2 = (pjsip_sip_uri*) pjsip_uri_get_uri(h2->uri); - - if (*u1->host.ptr == 'a') { - if (h1->expires != 0) { - ret = -650; - goto on_return; - } - if (h2->expires == 0) { - ret = -660; - goto on_return; - } - - } else { - pj_assert(*u1->host.ptr == 'b'); - if (h1->expires == 0) { - ret = -670; - goto on_return; - } - if (h2->expires != 0) { - ret = -680; - goto on_return; - } - } - - /* Destroy tdata */ - pjsip_tx_data_dec_ref(tdata); - tdata = NULL; - - - - /** - * First loop, it will update with more contacts. Second loop - * should do nothing. - */ - for (i=0; i<2; ++i) { - if (i==0) - PJ_LOG(3,(THIS_FILE, " replacing with more contacts")); - else - PJ_LOG(3,(THIS_FILE, " updating contacts with same contacts")); - - status = pjsip_regc_update_contact(regc, 2, &contacts[1]); - if (status != PJ_SUCCESS) { - ret = -710; - goto on_return; - } - - status = pjsip_regc_register(regc, PJ_TRUE, &tdata); - if (status != PJ_SUCCESS) { - ret = -720; - goto on_return; - } - - /* Check that the REGISTER contains two Contacts: - * - - * - - */ - h1 = (pjsip_contact_hdr*) - pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL); - if (!h1) { - ret = -730; - goto on_return; - } - if ((void*)h1->next == (void*)&tdata->msg->hdr) - h2 = NULL; - else - h2 = (pjsip_contact_hdr*) - pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h1->next); - if (!h2) { - ret = -740; - goto on_return; - } - /* must not have other Contact header */ - if ((void*)h2->next != (void*)&tdata->msg->hdr && - pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h2->next) != NULL) - { - ret = -745; - goto on_return; - } - - /* both contacts must not have expires=0 parameter */ - if (h1->expires == 0) { - ret = -750; - goto on_return; - } - if (h2->expires == 0) { - ret = -760; - goto on_return; - } - - /* Destroy tdata */ - pjsip_tx_data_dec_ref(tdata); - tdata = NULL; - } - -on_return: - if (tdata) pjsip_tx_data_dec_ref(tdata); - pjsip_regc_destroy(regc); - return ret; -}; - - -/* send error on authentication */ -static int auth_send_error(const pj_str_t *registrar_uri, - pj_bool_t destroy_on_cb) -{ - enum { TIMEOUT = 40 }; - struct registrar_cfg server_cfg = - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_TRUE, EXACT, 75, 0, {NULL, 0}}; - struct client client_cfg = - /* error code have_reg expiration contact_cnt auth? destroy*/ - { PJ_TRUE, 401, PJ_FALSE, -1, 0, PJ_TRUE, PJ_TRUE}; - pj_str_t contact = pj_str(""); - - pjsip_regc *regc; - int ret; - - client_cfg.destroy_on_cb = destroy_on_cb; - - /* inject error for second request retry */ - send_mod.count = 0; - send_mod.count_before_reject = 1; - - ret = do_test("auth send error", &server_cfg, &client_cfg, registrar_uri, - 1, &contact, TIMEOUT, PJ_TRUE, ®c); - - send_mod.count_before_reject = 0xFFFF; - - return ret; -}; - - - - -/************************************************************************/ -enum -{ - OFF = 1, - ON = 2, - ON_OFF = 3, -}; - -int regc_test(void) -{ - struct test_rec { - unsigned check_contact; - unsigned add_xuid_param; - - const char *title; - char *alt_registrar; - unsigned contact_cnt; - char *contacts[4]; - unsigned expires; - struct registrar_cfg server_cfg; - struct client client_cfg; - } test_rec[] = - { - /* immediate error */ - { - OFF, /* check_contact */ - OFF, /* add_xuid_param */ - "immediate error", /* title */ - "sip:unresolved-host-xyy", /* alt_registrar */ - 1, /* contact cnt */ - { "sip:user@127.0.0.1:5060" }, /* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_FALSE, 200, PJ_FALSE, NONE, 0, 0, {NULL, 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth?*/ - { PJ_FALSE, 503, PJ_FALSE, -1, 0, PJ_FALSE} - }, - - /* timeout test */ - { - OFF, /* check_contact */ - OFF, /* add_xuid_param */ - "timeout test (takes ~32 secs)",/* title */ - NULL, /* alt_registrar */ - 1, /* contact cnt */ - { "sip:user@127.0.0.1:5060" }, /* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_FALSE, 200, PJ_FALSE, NONE, 0, 0, {NULL, 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth? */ - { PJ_FALSE, 408, PJ_FALSE, -1, 0, PJ_FALSE} - }, - - /* Basic successful registration scenario: - * a good registrar returns the Contact header as is and - * add expires parameter. In this test no additional bindings - * are returned. - */ - { - ON_OFF, /* check_contact */ - ON_OFF, /* add_xuid_param */ - "basic", /* title */ - NULL, /* alt_registrar */ - 1, /* contact cnt */ - { "" }, /* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_FALSE, EXACT, 75, 65, {NULL, 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth?*/ - { PJ_FALSE, 200, PJ_TRUE, 75, 1, PJ_FALSE} - }, - - /* Basic successful registration scenario with authentication - */ - { - ON_OFF, /* check_contact */ - ON_OFF, /* add_xuid_param */ - "authentication", /* title */ - NULL, /* alt_registrar */ - 1, /* contact cnt */ - { "" }, /* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_TRUE, EXACT, 75, 65, {NULL, 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth?*/ - { PJ_FALSE, 200, PJ_TRUE, 75, 1, PJ_TRUE} - }, - - /* a good registrar returns the Contact header as is and - * add expires parameter. Also it adds bindings from other - * clients in this test. - */ - { - ON_OFF, /* check_contact */ - ON, /* add_xuid_param */ - "more bindings in response", /* title */ - NULL, /* alt_registrar */ - 1, /* contact cnt */ - { "" }, /* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_FALSE, EXACT, 75, 65, {";expires=70", 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth?*/ - { PJ_FALSE, 200, PJ_TRUE, 75, 2, PJ_FALSE} - }, - - - /* a bad registrar returns modified Contact header, but it - * still returns all parameters intact. In this case - * the expiration is taken from the expires param because - * of matching xuid param or because the number of - * Contact header matches. - */ - { - ON_OFF, /* check_contact */ - ON_OFF, /* add_xuid_param */ - "registrar modifies Contact header", /* title */ - NULL, /* alt_registrar */ - 1, /* contact cnt */ - { "" }, /* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_FALSE, MODIFIED, 75, 65, {NULL, 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth?*/ - { PJ_FALSE, 200, PJ_TRUE, 75, 1, PJ_FALSE} - }, - - - /* a bad registrar returns modified Contact header, but it - * still returns all parameters intact. In addition it returns - * bindings from other clients. - * - * In this case the expiration is taken from the expires param - * because add_xuid_param is enabled. - */ - { - ON_OFF, /* check_contact */ - ON, /* add_xuid_param */ - "registrar modifies Contact header and add bindings", /* title */ - NULL, /* alt_registrar */ - 1, /* contact cnt */ - { "" }, /* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_FALSE, MODIFIED, 75, 65, {";expires=70", 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth?*/ - { PJ_FALSE, 200, PJ_TRUE, 75, 2, PJ_FALSE} - }, - - - /* a bad registrar returns completely different Contact and - * all parameters are gone. In this case the expiration is - * also taken from the expires param since the number of - * header matches. - */ - { - ON_OFF, /* check_contact */ - ON_OFF, /* add_xuid_param */ - "registrar replaces Contact header", /* title */ - NULL, /* alt_registrar */ - 1, /* contact cnt */ - { "" }, /* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 202, PJ_FALSE, NONE, 0, 65, {";expires=75", 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth?*/ - { PJ_FALSE, 202, PJ_TRUE, 75, 1, PJ_FALSE} - }, - - - /* a bad registrar returns completely different Contact (and - * all parameters are gone) and it also includes bindings from - * other clients. - * In this case the expiration is taken from the Expires header. - */ - { - ON_OFF, /* check_contact */ - ON_OFF, /* add_xuid_param */ - " as above with additional bindings", /* title */ - NULL, /* alt_registrar */ - 1, /* contact cnt */ - { "" }, /* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_FALSE, NONE, 0, 65, {";expires=75, ", 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth?*/ - { PJ_FALSE, 200, PJ_TRUE, 65, 2, PJ_FALSE} - }, - - /* the registrar doesn't return any bindings, but for some - * reason it includes an Expires header. - * In this case the expiration is taken from the Expires header. - */ - { - ON_OFF, /* check_contact */ - ON_OFF, /* add_xuid_param */ - "no Contact but with Expires", /* title */ - NULL, /* alt_registrar */ - 1, /* contact cnt */ - { "" }, /* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_FALSE, NONE, 0, 65, {NULL, 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth?*/ - { PJ_FALSE, 200, PJ_TRUE, 65, 0, PJ_FALSE} - }, - - /* Neither Contact header nor Expires header are present. - * In this case the expiration is taken from the request. - */ - { - ON_OFF, /* check_contact */ - ON_OFF, /* add_xuid_param */ - "no Contact and no Expires", /* title */ - NULL, /* alt_registrar */ - 1, /* contact cnt */ - { "" },/* contacts[] */ - 600, /* expires */ - - /* registrar config: */ - /* respond code auth contact exp_prm expires more_contacts */ - { PJ_TRUE, 200, PJ_FALSE, NONE, 0, 0, {NULL, 0}}, - - /* client expected results: */ - /* error code have_reg expiration contact_cnt auth?*/ - { PJ_FALSE, 200, PJ_TRUE, 600, 0, PJ_FALSE} - }, - }; - - unsigned i; - pj_sockaddr_in addr; - pjsip_transport *udp = NULL; - pj_uint16_t port; - char registrar_uri_buf[80]; - pj_str_t registrar_uri; - int rc = 0; - - pj_sockaddr_in_init(&addr, 0, 0); - - /* Acquire existing transport, if any */ - rc = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, &addr, sizeof(addr), NULL, &udp); - if (rc == PJ_SUCCESS) { - port = pj_sockaddr_get_port(&udp->local_addr); - pjsip_transport_dec_ref(udp); - udp = NULL; - } else { - rc = pjsip_udp_transport_start(endpt, NULL, NULL, 1, &udp); - if (rc != PJ_SUCCESS) { - app_perror(" error creating UDP transport", rc); - rc = -2; - goto on_return; - } - - port = pj_sockaddr_get_port(&udp->local_addr); - } - - /* Register registrar module */ - rc = pjsip_endpt_register_module(endpt, ®istrar.mod); - if (rc != PJ_SUCCESS) { - app_perror(" error registering module", rc); - rc = -3; - goto on_return; - } - - /* Register send module */ - rc = pjsip_endpt_register_module(endpt, &send_mod.mod); - if (rc != PJ_SUCCESS) { - app_perror(" error registering module", rc); - rc = -3; - goto on_return; - } - - pj_ansi_snprintf(registrar_uri_buf, sizeof(registrar_uri_buf), - "sip:127.0.0.1:%d", (int)port); - registrar_uri = pj_str(registrar_uri_buf); - - for (i=0; ialt_registrar == NULL) { - reg_uri = registrar_uri; - } else { - reg_uri = pj_str(t->alt_registrar); - } - - /* Build contact pj_str_t's */ - for (j=0; jcontact_cnt; ++j) { - contacts[j] = pj_str(t->contacts[j]); - } - - /* Normalize more_contacts field */ - if (t->server_cfg.more_contacts.ptr) - t->server_cfg.more_contacts.slen = strlen(t->server_cfg.more_contacts.ptr); - - /* Do tests with three combinations: - * - check_contact on/off - * - add_xuid_param on/off - * - destroy_on_callback on/off - */ - for (x=1; x<=2; ++x) { - unsigned y; - - if ((t->check_contact & x) == 0) - continue; - - pjsip_cfg()->regc.check_contact = (x-1); - - for (y=1; y<=2; ++y) { - unsigned z; - - if ((t->add_xuid_param & y) == 0) - continue; - - pjsip_cfg()->regc.add_xuid_param = (y-1); - - for (z=0; z<=1; ++z) { - char new_title[200]; - - t->client_cfg.destroy_on_cb = z; - - sprintf(new_title, "%s [check=%d, xuid=%d, destroy=%d]", - t->title, pjsip_cfg()->regc.check_contact, - pjsip_cfg()->regc.add_xuid_param, z); - rc = do_test(new_title, &t->server_cfg, &t->client_cfg, - ®_uri, t->contact_cnt, contacts, - t->expires, PJ_FALSE, NULL); - if (rc != 0) - goto on_return; - } - - } - } - - /* Sleep between test groups to avoid using up too many - * active transactions. - */ - pj_thread_sleep(1000); - } - - /* keep-alive test */ - rc = keep_alive_test(®istrar_uri); - if (rc != 0) - goto on_return; - - /* Send error on refresh without destroy on callback */ - rc = refresh_error(®istrar_uri, PJ_FALSE); - if (rc != 0) - goto on_return; - - /* Send error on refresh, destroy on callback */ - rc = refresh_error(®istrar_uri, PJ_TRUE); - if (rc != 0) - goto on_return; - - /* Updating contact */ - rc = update_test(®istrar_uri); - if (rc != 0) - goto on_return; - - /* Send error during auth, don't destroy on callback */ - rc = auth_send_error(®istrar_uri, PJ_FALSE); - if (rc != 0) - goto on_return; - - /* Send error during auth, destroy on callback */ - rc = auth_send_error(®istrar_uri, PJ_FALSE); - if (rc != 0) - goto on_return; - -on_return: - if (registrar.mod.id != -1) { - pjsip_endpt_unregister_module(endpt, ®istrar.mod); - } - if (send_mod.mod.id != -1) { - pjsip_endpt_unregister_module(endpt, &send_mod.mod); - } - if (udp) { - pjsip_transport_dec_ref(udp); - } - return rc; -} - - diff --git a/pjsip/src/test-pjsip/test.c b/pjsip/src/test-pjsip/test.c deleted file mode 100644 index 5ce2b71a..00000000 --- a/pjsip/src/test-pjsip/test.c +++ /dev/null @@ -1,392 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - - -#include "test.h" -#include -#include -#include - -#define THIS_FILE "test.c" - -#define DO_TEST(test) do { \ - PJ_LOG(3, (THIS_FILE, "Running %s...", #test)); \ - rc = test; \ - PJ_LOG(3, (THIS_FILE, \ - "%s(%d)", \ - (rc ? "..ERROR" : "..success"), rc)); \ - if (rc!=0) goto on_return; \ - } while (0) - -#define DO_TSX_TEST(test, param) \ - do { \ - PJ_LOG(3, (THIS_FILE, "Running %s(%s)...", #test, (param)->tp_type)); \ - rc = test(param); \ - PJ_LOG(3, (THIS_FILE, \ - "%s(%d)", \ - (rc ? "..ERROR" : "..success"), rc)); \ - if (rc!=0) goto on_return; \ - } while (0) - - -pjsip_endpoint *endpt; -int log_level = 3; -int param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | - PJ_LOG_HAS_MICRO_SEC; - -static pj_oshandle_t fd_report; -const char *system_name = "Unknown"; -static char buf[1024]; - -void app_perror(const char *msg, pj_status_t rc) -{ - char errbuf[256]; - - PJ_CHECK_STACK(); - - pj_strerror(rc, errbuf, sizeof(errbuf)); - PJ_LOG(3,(THIS_FILE, "%s: [pj_status_t=%d] %s", msg, rc, errbuf)); - -} - -void flush_events(unsigned duration) -{ - pj_time_val stop_time; - - pj_gettimeofday(&stop_time); - stop_time.msec += duration; - pj_time_val_normalize(&stop_time); - - /* Process all events for the specified duration. */ - for (;;) { - pj_time_val timeout = {0, 1}, now; - - pjsip_endpt_handle_events(endpt, &timeout); - - pj_gettimeofday(&now); - if (PJ_TIME_VAL_GTE(now, stop_time)) - break; - } -} - -pj_status_t register_static_modules(pj_size_t *count, pjsip_module **modules) -{ - *count = 0; - return PJ_SUCCESS; -} - -static pj_status_t init_report(void) -{ - char tmp[80]; - pj_time_val timestamp; - pj_parsed_time date_time; - pj_ssize_t len; - pj_status_t status; - - pj_ansi_sprintf(tmp, "pjsip-static-bench-%s-%s.htm", PJ_OS_NAME, PJ_CC_NAME); - - status = pj_file_open(NULL, tmp, PJ_O_WRONLY, &fd_report); - if (status != PJ_SUCCESS) - return status; - - /* Title */ - len = pj_ansi_sprintf(buf, "\n" - " \n" - " PJSIP %s (%s) - Static Benchmark\n" - " \n" - "\n" - "\n", - PJ_VERSION, - (PJ_DEBUG ? "Debug" : "Release")); - pj_file_write(fd_report, buf, &len); - - - /* Title */ - len = pj_ansi_sprintf(buf, "

PJSIP %s (%s) - Static Benchmark

\n", - PJ_VERSION, - (PJ_DEBUG ? "Debug" : "Release")); - pj_file_write(fd_report, buf, &len); - - len = pj_ansi_sprintf(buf, "

Below is the benchmark result generated " - "by test-pjsip program. The program " - "is single-threaded only.

\n"); - pj_file_write(fd_report, buf, &len); - - - /* Write table heading */ - len = pj_ansi_sprintf(buf, "\n" - " \n" - " \n" - " \n" - " \n"); - pj_file_write(fd_report, buf, &len); - - - /* Write version */ - report_sval("version", PJ_VERSION, "", "PJLIB/PJSIP version"); - - - /* Debug or release */ - report_sval("build-type", (PJ_DEBUG ? "Debug" : "Release"), "", "Build type"); - - - /* Write timestamp */ - pj_gettimeofday(×tamp); - report_ival("timestamp", timestamp.sec, "", "System timestamp of the test"); - - - /* Write time of day */ - pj_time_decode(×tamp, &date_time); - len = pj_ansi_sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d", - date_time.year, date_time.mon+1, date_time.day, - date_time.hour, date_time.min, date_time.sec); - report_sval("date-time", tmp, "", "Date/time of the test"); - - - /* Write System */ - report_sval("system", system_name, "", "System description"); - - - /* Write OS type */ - report_sval("os-family", PJ_OS_NAME, "", "Operating system family"); - - - /* Write CC name */ - len = pj_ansi_sprintf(tmp, "%s-%d.%d.%d", PJ_CC_NAME, - PJ_CC_VER_1, PJ_CC_VER_2, PJ_CC_VER_2); - report_sval("cc-name", tmp, "", "Compiler name and version"); - - - return PJ_SUCCESS; -} - -void report_sval(const char *name, const char* value, const char *valname, - const char *desc) -{ - pj_ssize_t len; - - len = pj_ansi_sprintf(buf, " \n" - " \n" - " \n" - " \n", - name, value, valname, desc); - pj_file_write(fd_report, buf, &len); -} - - -void report_ival(const char *name, int value, const char *valname, - const char *desc) -{ - pj_ssize_t len; - - len = pj_ansi_sprintf(buf, " \n" - " \n" - " \n" - " \n", - name, value, valname, desc); - pj_file_write(fd_report, buf, &len); - -} - -static void close_report(void) -{ - pj_ssize_t len; - - if (fd_report) { - len = pj_ansi_sprintf(buf, "
VariableValueDescription
%s%s %s%s
%s%d %s%s
\n\n\n"); - pj_file_write(fd_report, buf, &len); - - pj_file_close(fd_report); - } -} - - -int test_main(void) -{ - pj_status_t rc; - pj_caching_pool caching_pool; - const char *filename; - unsigned tsx_test_cnt=0; - struct tsx_test_param tsx_test[10]; - pj_status_t status; -#if INCLUDE_TSX_TEST - unsigned i; - pjsip_transport *tp; -#if PJ_HAS_TCP - pjsip_tpfactory *tpfactory; -#endif /* PJ_HAS_TCP */ -#endif /* INCLUDE_TSX_TEST */ - int line; - - pj_log_set_level(log_level); - pj_log_set_decor(param_log_decor); - - if ((rc=pj_init()) != PJ_SUCCESS) { - app_perror("pj_init", rc); - return rc; - } - - if ((rc=pjlib_util_init()) != PJ_SUCCESS) { - app_perror("pj_init", rc); - return rc; - } - - status = init_report(); - if (status != PJ_SUCCESS) - return status; - - pj_dump_config(); - - pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, - PJSIP_TEST_MEM_SIZE ); - - rc = pjsip_endpt_create(&caching_pool.factory, "endpt", &endpt); - if (rc != PJ_SUCCESS) { - app_perror("pjsip_endpt_create", rc); - pj_caching_pool_destroy(&caching_pool); - return rc; - } - - PJ_LOG(3,(THIS_FILE,"")); - - /* Init logger module. */ - init_msg_logger(); - msg_logger_set_enabled(1); - - /* Start transaction layer module. */ - rc = pjsip_tsx_layer_init_module(endpt); - if (rc != PJ_SUCCESS) { - app_perror(" Error initializing transaction module", rc); - goto on_return; - } - - /* Create loop transport. */ - rc = pjsip_loop_start(endpt, NULL); - if (rc != PJ_SUCCESS) { - app_perror(" error: unable to create datagram loop transport", - rc); - goto on_return; - } - tsx_test[tsx_test_cnt].port = 5060; - tsx_test[tsx_test_cnt].tp_type = "loop-dgram"; - tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_LOOP_DGRAM; - ++tsx_test_cnt; - - -#if INCLUDE_URI_TEST - DO_TEST(uri_test()); -#endif - -#if INCLUDE_MSG_TEST - DO_TEST(msg_test()); - DO_TEST(msg_err_test()); -#endif - -#if INCLUDE_TXDATA_TEST - DO_TEST(txdata_test()); -#endif - -#if INCLUDE_TSX_BENCH - DO_TEST(tsx_bench()); -#endif - -#if INCLUDE_UDP_TEST - DO_TEST(transport_udp_test()); -#endif - -#if INCLUDE_LOOP_TEST - DO_TEST(transport_loop_test()); -#endif - -#if INCLUDE_TCP_TEST - DO_TEST(transport_tcp_test()); -#endif - -#if INCLUDE_RESOLVE_TEST - DO_TEST(resolve_test()); -#endif - - -#if INCLUDE_TSX_TEST - status = pjsip_udp_transport_start(endpt, NULL, NULL, 1, &tp); - if (status == PJ_SUCCESS) { - tsx_test[tsx_test_cnt].port = tp->local_name.port; - tsx_test[tsx_test_cnt].tp_type = "udp"; - tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_UDP; - ++tsx_test_cnt; - } - -#if PJ_HAS_TCP - status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); - if (status == PJ_SUCCESS) { - tsx_test[tsx_test_cnt].port = tpfactory->addr_name.port; - tsx_test[tsx_test_cnt].tp_type = "tcp"; - tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_TCP; - ++tsx_test_cnt; - } else { - app_perror("Unable to create TCP", status); - rc = -4; - goto on_return; - } -#endif - - - for (i=0; i - * - * 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 - */ -#ifndef __TEST_H__ -#define __TEST_H__ - -#include - -extern pjsip_endpoint *endpt; - -#define TEST_UDP_PORT 15060 -#define TEST_UDP_PORT_STR "15060" - -/** - * Memory size to use in caching pool. - * Default: 2MB - */ -#ifndef PJSIP_TEST_MEM_SIZE -# define PJSIP_TEST_MEM_SIZE (2*1024*1024) -#endif - - - -#define INCLUDE_MESSAGING_GROUP 1 -#define INCLUDE_TRANSPORT_GROUP 1 -#define INCLUDE_TSX_GROUP 1 -#define INCLUDE_INV_GROUP 1 -#define INCLUDE_REGC_GROUP 1 - -#define INCLUDE_BENCHMARKS 1 - -/* - * Include tests that normally would fail under certain gcc - * optimization levels. - */ -#ifndef INCLUDE_GCC_TEST -# define INCLUDE_GCC_TEST 0 -#endif - - -#define INCLUDE_URI_TEST INCLUDE_MESSAGING_GROUP -#define INCLUDE_MSG_TEST INCLUDE_MESSAGING_GROUP -#define INCLUDE_TXDATA_TEST INCLUDE_MESSAGING_GROUP -#define INCLUDE_TSX_BENCH INCLUDE_MESSAGING_GROUP -#define INCLUDE_UDP_TEST INCLUDE_TRANSPORT_GROUP -#define INCLUDE_LOOP_TEST INCLUDE_TRANSPORT_GROUP -#define INCLUDE_TCP_TEST INCLUDE_TRANSPORT_GROUP -#define INCLUDE_RESOLVE_TEST INCLUDE_TRANSPORT_GROUP -#define INCLUDE_TSX_TEST INCLUDE_TSX_GROUP -#define INCLUDE_INV_OA_TEST INCLUDE_INV_GROUP -#define INCLUDE_REGC_TEST INCLUDE_REGC_GROUP - - -/* The tests */ -int uri_test(void); -int msg_test(void); -int msg_err_test(void); -int txdata_test(void); -int tsx_bench(void); -int transport_udp_test(void); -int transport_loop_test(void); -int transport_tcp_test(void); -int resolve_test(void); -int regc_test(void); - -struct tsx_test_param -{ - int type; - int port; - char *tp_type; -}; - -int tsx_basic_test(struct tsx_test_param *param); -int tsx_uac_test(struct tsx_test_param *param); -int tsx_uas_test(struct tsx_test_param *param); - -/* Transport test helpers (transport_test.c). */ -int generic_transport_test(pjsip_transport *tp); -int transport_send_recv_test( pjsip_transport_type_e tp_type, - pjsip_transport *ref_tp, - char *target_url, - int *p_usec_rtt); -int transport_rt_test( pjsip_transport_type_e tp_type, - pjsip_transport *ref_tp, - char *target_url, - int *pkt_lost); -int transport_load_test(char *target_url); - -/* Invite session */ -int inv_offer_answer_test(void); - -/* Test main entry */ -int test_main(void); - -/* Test utilities. */ -void app_perror(const char *msg, pj_status_t status); -int init_msg_logger(void); -int msg_logger_set_enabled(pj_bool_t enabled); -void flush_events(unsigned duration); - - -void report_ival(const char *name, int value, const char *valname, const char *desc); -void report_sval(const char *name, const char* value, const char *valname, const char *desc); - - -/* Settings. */ -extern int log_level; - -#endif /* __TEST_H__ */ diff --git a/pjsip/src/test-pjsip/transport_loop_test.c b/pjsip/src/test-pjsip/transport_loop_test.c deleted file mode 100644 index a28b7b07..00000000 --- a/pjsip/src/test-pjsip/transport_loop_test.c +++ /dev/null @@ -1,127 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - -#include "test.h" -#include -#include - -#define THIS_FILE "transport_loop_test.c" - -static int datagram_loop_test() -{ - enum { LOOP = 8 }; - pjsip_transport *loop; - int i, pkt_lost; - pj_sockaddr_in addr; - pj_status_t status; - long ref_cnt; - int rtt[LOOP], min_rtt; - - PJ_LOG(3,(THIS_FILE, "testing datagram loop transport")); - - /* Test acquire transport. */ - status = pjsip_endpt_acquire_transport( endpt, PJSIP_TRANSPORT_LOOP_DGRAM, - &addr, sizeof(addr), NULL, &loop); - if (status != PJ_SUCCESS) { - app_perror(" error: loop transport is not configured", status); - return -20; - } - - /* Get initial reference counter */ - ref_cnt = pj_atomic_get(loop->ref_cnt); - - /* Test basic transport attributes */ - status = generic_transport_test(loop); - if (status != PJ_SUCCESS) - return status; - - /* Basic transport's send/receive loopback test. */ - for (i=0; iref_cnt) != ref_cnt) { - PJ_LOG(3,(THIS_FILE, " error: ref counter is not %d (%d)", - ref_cnt, pj_atomic_get(loop->ref_cnt))); - return -51; - } - - /* Decrement reference. */ - pjsip_transport_dec_ref(loop); - - return 0; -} - -int transport_loop_test(void) -{ - int status; - - status = datagram_loop_test(); - if (status != 0) - return status; - - return 0; -} diff --git a/pjsip/src/test-pjsip/transport_tcp_test.c b/pjsip/src/test-pjsip/transport_tcp_test.c deleted file mode 100644 index d012fb0e..00000000 --- a/pjsip/src/test-pjsip/transport_tcp_test.c +++ /dev/null @@ -1,155 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - -#include "test.h" -#include -#include - -#define THIS_FILE "transport_tcp_test.c" - - -/* - * TCP transport test. - */ -#if PJ_HAS_TCP -int transport_tcp_test(void) -{ - enum { SEND_RECV_LOOP = 8 }; - pjsip_tpfactory *tpfactory; - pjsip_transport *tcp; - pj_sockaddr_in rem_addr; - pj_status_t status; - char url[PJSIP_MAX_URL_SIZE]; - int rtt[SEND_RECV_LOOP], min_rtt; - int i, pkt_lost; - - /* Start TCP listener on arbitrary port. */ - status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to start TCP transport", status); - return -10; - } - - - /* Get the listener address */ - status = pj_sockaddr_in_init(&rem_addr, &tpfactory->addr_name.host, - (pj_uint16_t)tpfactory->addr_name.port); - if (status != PJ_SUCCESS) { - app_perror(" Error: possibly invalid TCP address name", status); - return -14; - } - - pj_ansi_sprintf(url, "sip:alice@%s:%d;transport=tcp", - pj_inet_ntoa(rem_addr.sin_addr), - pj_ntohs(rem_addr.sin_port)); - - - /* Acquire one TCP transport. */ - status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP, - &rem_addr, sizeof(rem_addr), - NULL, &tcp); - if (status != PJ_SUCCESS || tcp == NULL) { - app_perror(" Error: unable to acquire TCP transport", status); - return -17; - } - - /* After pjsip_endpt_acquire_transport, TCP transport must have - * reference counter 1. - */ - if (pj_atomic_get(tcp->ref_cnt) != 1) - return -20; - - /* Test basic transport attributes */ - status = generic_transport_test(tcp); - if (status != PJ_SUCCESS) - return status; - - - /* Check again that reference counter is 1. */ - if (pj_atomic_get(tcp->ref_cnt) != 1) - return -40; - - /* Load test */ - if (transport_load_test(url) != 0) - return -60; - - /* Basic transport's send/receive loopback test. */ - for (i=0; iref_cnt) != 1) - return -80; - - /* Destroy this transport. */ - pjsip_transport_dec_ref(tcp); - - /* Force destroy this transport. */ - status = pjsip_transport_destroy(tcp); - if (status != PJ_SUCCESS) - return -90; - - /* Unregister factory */ - status = pjsip_tpmgr_unregister_tpfactory(pjsip_endpt_get_tpmgr(endpt), - tpfactory); - if (status != PJ_SUCCESS) - return -95; - - /* Flush events. */ - PJ_LOG(3,(THIS_FILE, " Flushing events, 1 second...")); - flush_events(1000); - - /* Done */ - return 0; -} -#else /* PJ_HAS_TCP */ -int transport_tcp_test(void) -{ - return 0; -} -#endif /* PJ_HAS_TCP */ diff --git a/pjsip/src/test-pjsip/transport_test.c b/pjsip/src/test-pjsip/transport_test.c deleted file mode 100644 index 9f19b68f..00000000 --- a/pjsip/src/test-pjsip/transport_test.c +++ /dev/null @@ -1,760 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - -#include "test.h" -#include -#include - -#define THIS_FILE "transport_test.c" - -/////////////////////////////////////////////////////////////////////////////// -/* - * Generic testing for transport, to make sure that basic - * attributes have been initialized properly. - */ -int generic_transport_test(pjsip_transport *tp) -{ - PJ_LOG(3,(THIS_FILE, " structure test...")); - - /* Check that local address name is valid. */ - { - struct pj_in_addr addr; - - /* Note: inet_aton() returns non-zero if addr is valid! */ - if (pj_inet_aton(&tp->local_name.host, &addr) != 0) { - if (addr.s_addr==PJ_INADDR_ANY || addr.s_addr==PJ_INADDR_NONE) { - PJ_LOG(3,(THIS_FILE, " Error: invalid address name")); - return -420; - } - } else { - /* It's okay. local_name.host may be a hostname instead of - * IP address. - */ - } - } - - /* Check that port is valid. */ - if (tp->local_name.port <= 0) { - return -430; - } - - /* Check length of address (for now we only check against sockaddr_in). */ - if (tp->addr_len != sizeof(pj_sockaddr_in)) - return -440; - - /* Check type. */ - if (tp->key.type == PJSIP_TRANSPORT_UNSPECIFIED) - return -450; - - /* That's it. */ - return PJ_SUCCESS; -} - -/////////////////////////////////////////////////////////////////////////////// -/* - * Send/receive test. - * - * This test sends a request to loopback address; as soon as request is - * received, response will be sent, and time is recorded. - * - * The main purpose is to test that the basic transport functionalities works, - * before we continue with more complicated tests. - */ -#define FROM_HDR "Bob " -#define CONTACT_HDR "Bob " -#define CALL_ID_HDR "SendRecv-Test" -#define CSEQ_VALUE 100 -#define BODY "Hello World!" - -static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata); -static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata); - -/* Flag to indicate message has been received - * (or failed to send) - */ -#define NO_STATUS -2 -static int send_status = NO_STATUS; -static int recv_status = NO_STATUS; -static pj_timestamp my_send_time, my_recv_time; - -/* Module to receive messages for this test. */ -static pjsip_module my_module = -{ - NULL, NULL, /* prev and next */ - { "Transport-Test", 14}, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &my_on_rx_request, /* on_rx_request() */ - &my_on_rx_response, /* on_rx_response() */ - NULL, /* on_tsx_state() */ -}; - - -static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata) -{ - /* Check that this is our request. */ - if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) { - /* It is! */ - /* Send response. */ - pjsip_tx_data *tdata; - pjsip_response_addr res_addr; - pj_status_t status; - - status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata); - if (status != PJ_SUCCESS) { - recv_status = status; - return PJ_TRUE; - } - status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr); - if (status != PJ_SUCCESS) { - recv_status = status; - pjsip_tx_data_dec_ref(tdata); - return PJ_TRUE; - } - status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL); - if (status != PJ_SUCCESS) { - recv_status = status; - pjsip_tx_data_dec_ref(tdata); - return PJ_TRUE; - } - return PJ_TRUE; - } - - /* Not ours. */ - return PJ_FALSE; -} - -static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata) -{ - if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) { - pj_get_timestamp(&my_recv_time); - recv_status = PJ_SUCCESS; - return PJ_TRUE; - } - return PJ_FALSE; -} - -/* Transport callback. */ -static void send_msg_callback(pjsip_send_state *stateless_data, - pj_ssize_t sent, pj_bool_t *cont) -{ - if (sent < 1) { - /* Obtain the error code. */ - send_status = -sent; - } else { - send_status = PJ_SUCCESS; - } - - /* Don't want to continue. */ - *cont = PJ_FALSE; -} - - -/* Test that we receive loopback message. */ -int transport_send_recv_test( pjsip_transport_type_e tp_type, - pjsip_transport *ref_tp, - char *target_url, - int *p_usec_rtt) -{ - pj_bool_t msg_log_enabled; - pj_status_t status; - pj_str_t target, from, to, contact, call_id, body; - pjsip_method method; - pjsip_tx_data *tdata; - pj_time_val timeout; - - PJ_LOG(3,(THIS_FILE, " single message round-trip test...")); - - /* Register out test module to receive the message (if necessary). */ - if (my_module.id == -1) { - status = pjsip_endpt_register_module( endpt, &my_module ); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to register module", status); - return -500; - } - } - - /* Disable message logging. */ - msg_log_enabled = msg_logger_set_enabled(0); - - /* Create a request message. */ - target = pj_str(target_url); - from = pj_str(FROM_HDR); - to = pj_str(target_url); - contact = pj_str(CONTACT_HDR); - call_id = pj_str(CALL_ID_HDR); - body = pj_str(BODY); - - pjsip_method_set(&method, PJSIP_OPTIONS_METHOD); - status = pjsip_endpt_create_request( endpt, &method, &target, &from, &to, - &contact, &call_id, CSEQ_VALUE, - &body, &tdata ); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create request", status); - return -510; - } - - /* Reset statuses */ - send_status = recv_status = NO_STATUS; - - /* Start time. */ - pj_get_timestamp(&my_send_time); - - /* Send the message (statelessly). */ - PJ_LOG(5,(THIS_FILE, "Sending request to %.*s", - (int)target.slen, target.ptr)); - status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, - &send_msg_callback); - if (status != PJ_SUCCESS) { - /* Immediate error! */ - pjsip_tx_data_dec_ref(tdata); - send_status = status; - } - - /* Set the timeout (2 seconds from now) */ - pj_gettimeofday(&timeout); - timeout.sec += 2; - - /* Loop handling events until we get status */ - do { - pj_time_val now; - pj_time_val poll_interval = { 0, 10 }; - - pj_gettimeofday(&now); - if (PJ_TIME_VAL_GTE(now, timeout)) { - PJ_LOG(3,(THIS_FILE, " error: timeout in send/recv test")); - status = -540; - goto on_return; - } - - if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) { - app_perror(" error sending message", send_status); - status = -550; - goto on_return; - } - - if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) { - app_perror(" error receiving message", recv_status); - status = -560; - goto on_return; - } - - if (send_status!=NO_STATUS && recv_status!=NO_STATUS) { - /* Success! */ - break; - } - - pjsip_endpt_handle_events(endpt, &poll_interval); - - } while (1); - - if (status == PJ_SUCCESS) { - unsigned usec_rt; - usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time); - - PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt)); - - *p_usec_rtt = usec_rt; - } - - /* Restore message logging. */ - msg_logger_set_enabled(msg_log_enabled); - - status = PJ_SUCCESS; - -on_return: - return status; -} - - -/////////////////////////////////////////////////////////////////////////////// -/* - * Multithreaded round-trip test - * - * This test will spawn multiple threads, each of them send a request. As soon - * as request is received, response will be sent, and time is recorded. - * - * The main purpose of this test is to ensure there's no crash when multiple - * threads are sending/receiving messages. - * - */ -static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata); -static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata); - -static pjsip_module rt_module = -{ - NULL, NULL, /* prev and next */ - { "Transport-RT-Test", 17}, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &rt_on_rx_request, /* on_rx_request() */ - &rt_on_rx_response, /* on_rx_response() */ - NULL, /* tsx_handler() */ -}; - -static struct -{ - pj_thread_t *thread; - pj_timestamp send_time; - pj_timestamp total_rt_time; - int sent_request_count, recv_response_count; - pj_str_t call_id; - pj_timer_entry timeout_timer; - pj_timer_entry tx_timer; - pj_mutex_t *mutex; -} rt_test_data[16]; - -static char rt_target_uri[64]; -static pj_bool_t rt_stop; -static pj_str_t rt_call_id; - -static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata) -{ - if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) { - pjsip_tx_data *tdata; - pjsip_response_addr res_addr; - pj_status_t status; - - status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata); - if (status != PJ_SUCCESS) { - app_perror(" error creating response", status); - return PJ_TRUE; - } - status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr); - if (status != PJ_SUCCESS) { - app_perror(" error in get response address", status); - pjsip_tx_data_dec_ref(tdata); - return PJ_TRUE; - } - status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL); - if (status != PJ_SUCCESS) { - app_perror(" error sending response", status); - pjsip_tx_data_dec_ref(tdata); - return PJ_TRUE; - } - return PJ_TRUE; - - } - return PJ_FALSE; -} - -static pj_status_t rt_send_request(int thread_id) -{ - pj_status_t status; - pj_str_t target, from, to, contact, call_id; - pjsip_tx_data *tdata; - pj_time_val timeout_delay; - - pj_mutex_lock(rt_test_data[thread_id].mutex); - - /* Create a request message. */ - target = pj_str(rt_target_uri); - from = pj_str(FROM_HDR); - to = pj_str(rt_target_uri); - contact = pj_str(CONTACT_HDR); - call_id = rt_test_data[thread_id].call_id; - - status = pjsip_endpt_create_request( endpt, &pjsip_options_method, - &target, &from, &to, - &contact, &call_id, -1, - NULL, &tdata ); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create request", status); - pj_mutex_unlock(rt_test_data[thread_id].mutex); - return -610; - } - - /* Start time. */ - pj_get_timestamp(&rt_test_data[thread_id].send_time); - - /* Send the message (statelessly). */ - status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, NULL); - if (status != PJ_SUCCESS) { - /* Immediate error! */ - app_perror(" error: send request", status); - pjsip_tx_data_dec_ref(tdata); - pj_mutex_unlock(rt_test_data[thread_id].mutex); - return -620; - } - - /* Update counter. */ - rt_test_data[thread_id].sent_request_count++; - - /* Set timeout timer. */ - if (rt_test_data[thread_id].timeout_timer.user_data != NULL) { - pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer); - } - timeout_delay.sec = 100; timeout_delay.msec = 0; - rt_test_data[thread_id].timeout_timer.user_data = (void*)1; - pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].timeout_timer, - &timeout_delay); - - pj_mutex_unlock(rt_test_data[thread_id].mutex); - return PJ_SUCCESS; -} - -static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata) -{ - if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) { - char *pos = pj_strchr(&rdata->msg_info.cid->id, '/')+1; - int thread_id = (*pos - '0'); - pj_timestamp recv_time; - - pj_mutex_lock(rt_test_data[thread_id].mutex); - - /* Stop timer. */ - pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer); - - /* Update counter and end-time. */ - rt_test_data[thread_id].recv_response_count++; - pj_get_timestamp(&recv_time); - - pj_sub_timestamp(&recv_time, &rt_test_data[thread_id].send_time); - pj_add_timestamp(&rt_test_data[thread_id].total_rt_time, &recv_time); - - if (!rt_stop) { - pj_time_val tx_delay = { 0, 0 }; - pj_assert(rt_test_data[thread_id].tx_timer.user_data == NULL); - rt_test_data[thread_id].tx_timer.user_data = (void*)1; - pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].tx_timer, - &tx_delay); - } - - pj_mutex_unlock(rt_test_data[thread_id].mutex); - - return PJ_TRUE; - } - return PJ_FALSE; -} - -static void rt_timeout_timer( pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry ) -{ - pj_mutex_lock(rt_test_data[entry->id].mutex); - - PJ_UNUSED_ARG(timer_heap); - PJ_LOG(3,(THIS_FILE, " timeout waiting for response")); - rt_test_data[entry->id].timeout_timer.user_data = NULL; - - if (rt_test_data[entry->id].tx_timer.user_data == NULL) { - pj_time_val delay = { 0, 0 }; - rt_test_data[entry->id].tx_timer.user_data = (void*)1; - pjsip_endpt_schedule_timer(endpt, &rt_test_data[entry->id].tx_timer, - &delay); - } - - pj_mutex_unlock(rt_test_data[entry->id].mutex); -} - -static void rt_tx_timer( pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry ) -{ - pj_mutex_lock(rt_test_data[entry->id].mutex); - - PJ_UNUSED_ARG(timer_heap); - pj_assert(rt_test_data[entry->id].tx_timer.user_data != NULL); - rt_test_data[entry->id].tx_timer.user_data = NULL; - rt_send_request(entry->id); - - pj_mutex_unlock(rt_test_data[entry->id].mutex); -} - - -static int rt_worker_thread(void *arg) -{ - int i; - pj_time_val poll_delay = { 0, 10 }; - - /* Sleep to allow main threads to run. */ - pj_thread_sleep(10); - - while (!rt_stop) { - pjsip_endpt_handle_events(endpt, &poll_delay); - } - - /* Exhaust responses. */ - for (i=0; i<100; ++i) - pjsip_endpt_handle_events(endpt, &poll_delay); - - return 0; -} - -int transport_rt_test( pjsip_transport_type_e tp_type, - pjsip_transport *ref_tp, - char *target_url, - int *lost) -{ - enum { THREADS = 4, INTERVAL = 10 }; - int i; - pj_status_t status; - pj_pool_t *pool; - pj_bool_t logger_enabled; - - pj_timestamp zero_time, total_time; - unsigned usec_rt; - unsigned total_sent; - unsigned total_recv; - - PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...", - THREADS)); - PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..", - INTERVAL)); - - /* Make sure msg logger is disabled. */ - logger_enabled = msg_logger_set_enabled(0); - - /* Register module (if not yet registered) */ - if (rt_module.id == -1) { - status = pjsip_endpt_register_module( endpt, &rt_module ); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to register module", status); - return -600; - } - } - - /* Create pool for this test. */ - pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000); - if (!pool) - return -610; - - /* Initialize static test data. */ - pj_ansi_strcpy(rt_target_uri, target_url); - rt_call_id = pj_str("RT-Call-Id/"); - rt_stop = PJ_FALSE; - - /* Initialize thread data. */ - for (i=0; imsg_info.cseq->cseq != mod_load.next_seq) { - PJ_LOG(1,("THIS_FILE", " err: expecting cseq %u, got %u", - mod_load.next_seq, rdata->msg_info.cseq->cseq)); - mod_load.err = PJ_TRUE; - mod_load.next_seq = rdata->msg_info.cseq->cseq + 1; - } else - mod_load.next_seq++; - return PJ_TRUE; -} - -int transport_load_test(char *target_url) -{ - enum { COUNT = 2000 }; - unsigned i; - pj_status_t status = PJ_SUCCESS; - - /* exhaust packets */ - do { - pj_time_val delay = {1, 0}; - i = 0; - pjsip_endpt_handle_events2(endpt, &delay, &i); - } while (i != 0); - - PJ_LOG(3,(THIS_FILE, " transport load test...")); - - if (mod_load.mod.id == -1) { - status = pjsip_endpt_register_module( endpt, &mod_load.mod); - if (status != PJ_SUCCESS) { - app_perror("error registering module", status); - return -1; - } - } - mod_load.err = PJ_FALSE; - mod_load.next_seq = 0; - - for (i=0; i"); - call_id = pj_str("thecallid"); - status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, - &target, &from, - &target, &from, &call_id, - i, NULL, &tdata ); - if (status != PJ_SUCCESS) { - app_perror("error creating request", status); - goto on_return; - } - - status = pjsip_endpt_send_request_stateless(endpt, tdata, NULL, NULL); - if (status != PJ_SUCCESS) { - app_perror("error sending request", status); - goto on_return; - } - } - - do { - pj_time_val delay = {1, 0}; - i = 0; - pjsip_endpt_handle_events2(endpt, &delay, &i); - } while (i != 0); - - if (mod_load.next_seq != COUNT) { - PJ_LOG(1,("THIS_FILE", " err: expecting %u msg, got only %u", - COUNT, mod_load.next_seq)); - status = -2; - goto on_return; - } - -on_return: - if (mod_load.mod.id != -1) { - pjsip_endpt_unregister_module( endpt, &mod_load.mod); - mod_load.mod.id = -1; - } - if (status != PJ_SUCCESS || mod_load.err) { - return -2; - } - PJ_LOG(3,(THIS_FILE, " success")); - return 0; -} - - diff --git a/pjsip/src/test-pjsip/transport_udp_test.c b/pjsip/src/test-pjsip/transport_udp_test.c deleted file mode 100644 index 81e8d69c..00000000 --- a/pjsip/src/test-pjsip/transport_udp_test.c +++ /dev/null @@ -1,128 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - -#include "test.h" -#include -#include - -#define THIS_FILE "transport_udp_test.c" - - -/* - * UDP transport test. - */ -int transport_udp_test(void) -{ - enum { SEND_RECV_LOOP = 8 }; - pjsip_transport *udp_tp, *tp; - pj_sockaddr_in addr, rem_addr; - pj_str_t s; - pj_status_t status; - int rtt[SEND_RECV_LOOP], min_rtt; - int i, pkt_lost; - - pj_sockaddr_in_init(&addr, NULL, TEST_UDP_PORT); - - /* Start UDP transport. */ - status = pjsip_udp_transport_start( endpt, &addr, NULL, 1, &udp_tp); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to start UDP transport", status); - return -10; - } - - /* UDP transport must have initial reference counter set to 1. */ - if (pj_atomic_get(udp_tp->ref_cnt) != 1) - return -20; - - /* Test basic transport attributes */ - status = generic_transport_test(udp_tp); - if (status != PJ_SUCCESS) - return status; - - /* Test that transport manager is returning the correct - * transport. - */ - pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80); - status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, - &rem_addr, sizeof(rem_addr), - NULL, &tp); - if (status != PJ_SUCCESS) - return -50; - if (tp != udp_tp) - return -60; - - /* pjsip_endpt_acquire_transport() adds reference, so we need - * to decrement it. - */ - pjsip_transport_dec_ref(tp); - - /* Check again that reference counter is 1. */ - if (pj_atomic_get(udp_tp->ref_cnt) != 1) - return -70; - - /* Basic transport's send/receive loopback test. */ - pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "127.0.0.1"), TEST_UDP_PORT); - for (i=0; iref_cnt) != 1) - return -80; - - /* Destroy this transport. */ - pjsip_transport_dec_ref(udp_tp); - - /* Force destroy this transport. */ - status = pjsip_transport_destroy(udp_tp); - if (status != PJ_SUCCESS) - return -90; - - /* Flush events. */ - PJ_LOG(3,(THIS_FILE, " Flushing events, 1 second...")); - flush_events(1000); - - /* Done */ - return 0; -} diff --git a/pjsip/src/test-pjsip/tsx_basic_test.c b/pjsip/src/test-pjsip/tsx_basic_test.c deleted file mode 100644 index f030ea06..00000000 --- a/pjsip/src/test-pjsip/tsx_basic_test.c +++ /dev/null @@ -1,157 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - -#include "test.h" -#include -#include - -#define THIS_FILE "tsx_basic_test.c" - -static char TARGET_URI[PJSIP_MAX_URL_SIZE]; -static char FROM_URI[PJSIP_MAX_URL_SIZE]; - - -/* Test transaction layer. */ -static int tsx_layer_test(void) -{ - pj_str_t target, from, tsx_key; - pjsip_tx_data *tdata; - pjsip_transaction *tsx, *found; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, " transaction layer test")); - - target = pj_str(TARGET_URI); - from = pj_str(FROM_URI); - - status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, - &from, &target, NULL, NULL, -1, NULL, - &tdata); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create request", status); - return -110; - } - - status = pjsip_tsx_create_uac(NULL, tdata, &tsx); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create transaction", status); - return -120; - } - - pj_strdup(tdata->pool, &tsx_key, &tsx->transaction_key); - - found = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE); - if (found != tsx) { - return -130; - } - - pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); - flush_events(500); - - if (pjsip_tx_data_dec_ref(tdata) != PJSIP_EBUFDESTROYED) { - return -140; - } - - return 0; -} - -/* Double terminate test. */ -static int double_terminate(void) -{ - pj_str_t target, from, tsx_key; - pjsip_tx_data *tdata; - pjsip_transaction *tsx; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, " double terminate test")); - - target = pj_str(TARGET_URI); - from = pj_str(FROM_URI); - - /* Create request. */ - status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, - &from, &target, NULL, NULL, -1, NULL, - &tdata); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create request", status); - return -10; - } - - /* Create transaction. */ - status = pjsip_tsx_create_uac(NULL, tdata, &tsx); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create transaction", status); - return -20; - } - - /* Save transaction key for later. */ - pj_strdup_with_null(tdata->pool, &tsx_key, &tsx->transaction_key); - - /* Add reference to transmit buffer (tsx_send_msg() will dec txdata). */ - pjsip_tx_data_add_ref(tdata); - - /* Send message to start timeout timer. */ - status = pjsip_tsx_send_msg(tsx, NULL); - - /* Terminate transaction. */ - status = pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to terminate transaction", status); - return -30; - } - - tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); - if (tsx) { - /* Terminate transaction again. */ - pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to terminate transaction", status); - return -40; - } - pj_mutex_unlock(tsx->mutex); - } - - flush_events(500); - if (pjsip_tx_data_dec_ref(tdata) != PJSIP_EBUFDESTROYED) { - return -50; - } - - return PJ_SUCCESS; -} - -int tsx_basic_test(struct tsx_test_param *param) -{ - int status; - - pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", - param->port, param->tp_type); - pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", - param->port, param->tp_type); - - status = tsx_layer_test(); - if (status != 0) - return status; - - status = double_terminate(); - if (status != 0) - return status; - - return 0; -} diff --git a/pjsip/src/test-pjsip/tsx_bench.c b/pjsip/src/test-pjsip/tsx_bench.c deleted file mode 100644 index 6f217a2b..00000000 --- a/pjsip/src/test-pjsip/tsx_bench.c +++ /dev/null @@ -1,280 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ -#include "test.h" -#include -#include - -#define THIS_FILE "tsx_uas_test.c" - - -static pjsip_module mod_tsx_user; - -static int uac_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) -{ - unsigned i; - pjsip_tx_data *request; - pjsip_transaction **tsx; - pj_timestamp t1, t2, elapsed; - pjsip_via_hdr *via; - pj_status_t status; - - /* Create the request first. */ - pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); - pj_str_t str_from = pj_str("\"Local User\" "); - pj_str_t str_to = pj_str("\"Remote User\" "); - pj_str_t str_contact = str_from; - - status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, - &str_target, &str_from, &str_to, - &str_contact, NULL, -1, NULL, - &request); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create request", status); - return status; - } - - via = (pjsip_via_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_VIA, - NULL); - - /* Create transaction array */ - tsx = (pjsip_transaction**) pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*)); - - pj_bzero(&mod_tsx_user, sizeof(mod_tsx_user)); - mod_tsx_user.id = -1; - - /* Benchmark */ - elapsed.u64 = 0; - pj_get_timestamp(&t1); - for (i=0; ibranch_param.slen = 0; - } - pj_get_timestamp(&t2); - pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&elapsed, &t2); - - p_elapsed->u64 = elapsed.u64; - status = PJ_SUCCESS; - -on_error: - for (i=0; i"); - pj_str_t str_to = pj_str("\"Remote User\" "); - pj_str_t str_contact = str_from; - - status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, - &str_target, &str_from, &str_to, - &str_contact, NULL, -1, NULL, - &request); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create request", status); - return status; - } - - /* Create Via */ - via = pjsip_via_hdr_create(request->pool); - via->sent_by.host = pj_str("192.168.0.7"); - via->sent_by.port = 5061; - via->transport = pj_str("udp"); - via->rport_param = 1; - via->recvd_param = pj_str("192.168.0.7"); - pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); - - - /* Create "dummy" rdata from the tdata */ - pj_bzero(&rdata, sizeof(pjsip_rx_data)); - rdata.tp_info.pool = request->pool; - rdata.msg_info.msg = request->msg; - rdata.msg_info.from = (pjsip_from_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); - rdata.msg_info.to = (pjsip_to_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); - rdata.msg_info.cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); - rdata.msg_info.cid = (pjsip_cid_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); - rdata.msg_info.via = via; - - pj_sockaddr_in_init(&remote, 0, 0); - status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, - &remote, sizeof(pj_sockaddr_in), - NULL, &rdata.tp_info.transport); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to get loop transport", status); - return status; - } - - - /* Create transaction array */ - tsx = (pjsip_transaction**) pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*)); - - pj_bzero(&mod_tsx_user, sizeof(mod_tsx_user)); - mod_tsx_user.id = -1; - - - /* Benchmark */ - elapsed.u64 = 0; - pj_get_timestamp(&t1); - for (i=0; ibranch_param.ptr = branch_buf; - via->branch_param.slen = PJSIP_RFC3261_BRANCH_LEN + - pj_ansi_sprintf(branch_buf+PJSIP_RFC3261_BRANCH_LEN, - "-%d", i); - status = pjsip_tsx_create_uas(&mod_tsx_user, &rdata, &tsx[i]); - if (status != PJ_SUCCESS) - goto on_error; - - } - pj_get_timestamp(&t2); - pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&elapsed, &t2); - - p_elapsed->u64 = elapsed.u64; - status = PJ_SUCCESS; - -on_error: - for (i=0; ipjsip_tsx_create_uac(), based on the time " - "to create %d simultaneous transactions above.", - WORKING_SET); - - report_ival("create-uac-tsx-per-sec", - speed, "tsx/sec", desc); - - - - /* - * Benchmark UAS - */ - PJ_LOG(3,(THIS_FILE, " benchmarking UAS transaction creation:")); - for (i=0; ipjsip_tsx_create_uas(), based on the time " - "to create %d simultaneous transactions above.", - WORKING_SET); - - report_ival("create-uas-tsx-per-sec", - speed, "tsx/sec", desc); - - return PJ_SUCCESS; -} - diff --git a/pjsip/src/test-pjsip/tsx_uac_test.c b/pjsip/src/test-pjsip/tsx_uac_test.c deleted file mode 100644 index f725114a..00000000 --- a/pjsip/src/test-pjsip/tsx_uac_test.c +++ /dev/null @@ -1,1450 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - -#include "test.h" -#include -#include - -#define THIS_FILE "tsx_uac_test.c" - - -/***************************************************************************** - ** - ** UAC tests. - ** - ** This file performs various tests for UAC transactions. Each test will have - ** a different Via branch param so that message receiver module and - ** transaction user module can identify which test is being carried out. - ** - ** TEST1_BRANCH_ID - ** Perform basic retransmission and timeout test. Message receiver will - ** verify that retransmission is received at correct time. - ** This test verifies the following requirements: - ** - retransmit timer doubles for INVITE - ** - retransmit timer doubles and caps off for non-INVITE - ** - retransmit timer timer is precise - ** - correct timeout and retransmission count - ** Requirements not tested: - ** - retransmit timer only starts after resolving has completed. - ** - ** TEST2_BRANCH_ID - ** Test scenario where resolver is unable to resolve destination host. - ** - ** TEST3_BRANCH_ID - ** Test scenario where transaction is terminated while resolver is still - ** running. - ** - ** TEST4_BRANCH_ID - ** Test scenario where transport failed after several retransmissions. - ** - ** TEST5_BRANCH_ID - ** Test scenario where transaction is terminated by user after several - ** retransmissions. - ** - ** TEST6_BRANCH_ID - ** Test successfull non-INVITE transaction. - ** It tests the following requirements: - ** - transaction correctly moves to COMPLETED state. - ** - retransmission must cease. - ** - tx_data must be maintained until state is terminated. - ** - ** TEST7_BRANCH_ID - ** Test successfull non-INVITE transaction, with provisional response. - ** - ** TEST8_BRANCH_ID - ** Test failed INVITE transaction (e.g. ACK must be received) - ** - ** TEST9_BRANCH_ID - ** Test failed INVITE transaction with provisional response. - ** - ** - ***************************************************************************** - */ - -static char *TEST1_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test1"; -static char *TEST2_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test2"; -static char *TEST3_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test3"; -static char *TEST4_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test4"; -static char *TEST5_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test5"; -static char *TEST6_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test6"; -static char *TEST7_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test7"; -static char *TEST8_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test8"; -static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test9"; - -#define TEST1_ALLOWED_DIFF (150) -#define TEST4_RETRANSMIT_CNT 3 -#define TEST5_RETRANSMIT_CNT 3 - -static char TARGET_URI[128]; -static char FROM_URI[128]; -static unsigned tp_flag; -static struct tsx_test_param *test_param; - -static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e); -static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata); - -/* UAC transaction user module. */ -static pjsip_module tsx_user = -{ - NULL, NULL, /* prev and next */ - { "Tsx-UAC-User", 12}, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - NULL, /* on_rx_request() */ - NULL, /* on_rx_response() */ - NULL, /* on_tx_request() */ - NULL, /* on_tx_response() */ - &tsx_user_on_tsx_state, /* on_tsx_state() */ -}; - -/* Module to receive the loop-backed request. */ -static pjsip_module msg_receiver = -{ - NULL, NULL, /* prev and next */ - { "Msg-Receiver", 12}, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &msg_receiver_on_rx_request, /* on_rx_request() */ - NULL, /* on_rx_response() */ - NULL, /* on_tx_request() */ - NULL, /* on_tx_response() */ - NULL, /* on_tsx_state() */ -}; - -/* Static vars, which will be reset on each test. */ -static int recv_count; -static pj_time_val recv_last; -static pj_bool_t test_complete; - -/* Loop transport instance. */ -static pjsip_transport *loop; - -/* General timer entry to be used by tests. */ -static struct my_timer -{ - pj_timer_entry entry; - char key_buf[1024]; - pj_str_t tsx_key; -} timer; - -/* - * This is the handler to receive state changed notification from the - * transaction. It is used to verify that the transaction behaves according - * to the test scenario. - */ -static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) -{ - if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) { - /* - * Transaction with TEST1_BRANCH_ID should terminate with transaction - * timeout status. - */ - if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - if (test_complete == 0) - test_complete = 1; - - /* Test the status code. */ - if (tsx->status_code != PJSIP_SC_TSX_TIMEOUT) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, PJSIP_SC_TSX_TIMEOUT)); - test_complete = -710; - } - - - /* If transport is reliable, then there must not be any - * retransmissions. - */ - if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { - if (recv_count != 1) { - PJ_LOG(3,(THIS_FILE, - " error: there were %d (re)transmissions", - recv_count)); - test_complete = -715; - } - } else { - /* Check the number of transmissions, which must be - * 6 for INVITE and 10 for non-INVITE - */ - if (tsx->method.id==PJSIP_INVITE_METHOD && recv_count != 7) { - PJ_LOG(3,(THIS_FILE, - " error: there were %d (re)transmissions", - recv_count)); - test_complete = -716; - } else - if (tsx->method.id==PJSIP_OPTIONS_METHOD && recv_count != 11) { - PJ_LOG(3,(THIS_FILE, - " error: there were %d (re)transmissions", - recv_count)); - test_complete = -717; - } else - if (tsx->method.id!=PJSIP_INVITE_METHOD && - tsx->method.id!=PJSIP_OPTIONS_METHOD) - { - PJ_LOG(3,(THIS_FILE, " error: unexpected method")); - test_complete = -718; - } - } - } - - } else if (pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) { - /* - * Transaction with TEST2_BRANCH_ID should terminate with transport error. - */ - if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - /* Test the status code. */ - if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR)); - test_complete = -720; - } - - if (test_complete == 0) - test_complete = 1; - } - - } else if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) { - /* - * This test terminates the transaction while resolver is still - * running. - */ - if (tsx->state == PJSIP_TSX_STATE_CALLING) { - - /* Terminate the transaction. */ - pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); - - } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - /* Check if status code is correct. */ - if (tsx->status_code != PJSIP_SC_REQUEST_TERMINATED) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, PJSIP_SC_REQUEST_TERMINATED)); - test_complete = -730; - } - - if (test_complete == 0) - test_complete = 1; - - } - - } else if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) { - /* - * This test simulates transport failure after several - * retransmissions. - */ - if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - /* Status code must be transport error. */ - if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR)); - test_complete = -730; - } - - /* Must have correct retransmission count. */ - if (tsx->retransmit_count != TEST4_RETRANSMIT_CNT) { - PJ_LOG(3,(THIS_FILE, - " error: retransmit cnt is %d instead of %d", - tsx->retransmit_count, TEST4_RETRANSMIT_CNT)); - test_complete = -731; - } - - if (test_complete == 0) - test_complete = 1; - } - - - } else if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) { - /* - * This test simulates transport failure after several - * retransmissions. - */ - if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - /* Status code must be PJSIP_SC_REQUEST_TERMINATED. */ - if (tsx->status_code != PJSIP_SC_REQUEST_TERMINATED) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, PJSIP_SC_REQUEST_TERMINATED)); - test_complete = -733; - } - - /* Must have correct retransmission count. */ - if (tsx->retransmit_count != TEST5_RETRANSMIT_CNT) { - PJ_LOG(3,(THIS_FILE, - " error: retransmit cnt is %d instead of %d", - tsx->retransmit_count, TEST5_RETRANSMIT_CNT)); - test_complete = -734; - } - - if (test_complete == 0) - test_complete = 1; - } - - - } else if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) { - /* - * Successfull non-INVITE transaction. - */ - if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { - - /* Status code must be 202. */ - if (tsx->status_code != 202) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, 202)); - test_complete = -736; - } - - /* Must have correct retransmission count. */ - if (tsx->retransmit_count != 0) { - PJ_LOG(3,(THIS_FILE, - " error: retransmit cnt is %d instead of %d", - tsx->retransmit_count, 0)); - test_complete = -737; - } - - /* Must still keep last_tx */ - if (tsx->last_tx == NULL) { - PJ_LOG(3,(THIS_FILE, - " error: transaction lost last_tx")); - test_complete = -738; - } - - if (test_complete == 0) { - test_complete = 1; - pjsip_tsx_terminate(tsx, 202); - } - - } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - /* Previous state must be COMPLETED. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - test_complete = -7381; - } - - } - - } else if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0) { - /* - * Successfull non-INVITE transaction. - */ - if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { - - /* Check prev state. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) { - PJ_LOG(3,(THIS_FILE, - " error: prev state is %s instead of %s", - pjsip_tsx_state_str((pjsip_tsx_state_e)e->body.tsx_state.prev_state), - pjsip_tsx_state_str(PJSIP_TSX_STATE_PROCEEDING))); - test_complete = -739; - } - - /* Status code must be 202. */ - if (tsx->status_code != 202) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, 202)); - test_complete = -740; - } - - /* Must have correct retransmission count. */ - if (tsx->retransmit_count != 0) { - PJ_LOG(3,(THIS_FILE, - " error: retransmit cnt is %d instead of %d", - tsx->retransmit_count, 0)); - test_complete = -741; - } - - /* Must still keep last_tx */ - if (tsx->last_tx == NULL) { - PJ_LOG(3,(THIS_FILE, - " error: transaction lost last_tx")); - test_complete = -741; - } - - if (test_complete == 0) { - test_complete = 1; - pjsip_tsx_terminate(tsx, 202); - } - - } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - /* Previous state must be COMPLETED. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - test_complete = -742; - } - - } - - - } else if (pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0) { - /* - * Failed INVITE transaction. - */ - if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { - - /* Status code must be 301. */ - if (tsx->status_code != 301) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, 301)); - test_complete = -745; - } - - /* Must have correct retransmission count. */ - if (tsx->retransmit_count != 0) { - PJ_LOG(3,(THIS_FILE, - " error: retransmit cnt is %d instead of %d", - tsx->retransmit_count, 0)); - test_complete = -746; - } - - /* Must still keep last_tx */ - if (tsx->last_tx == NULL) { - PJ_LOG(3,(THIS_FILE, - " error: transaction lost last_tx")); - test_complete = -747; - } - - /* last_tx MUST be the INVITE request - * (authorization depends on this behavior) - */ - if (tsx->last_tx && tsx->last_tx->msg->line.req.method.id != - PJSIP_INVITE_METHOD) - { - PJ_LOG(3,(THIS_FILE, - " error: last_tx is not INVITE")); - test_complete = -748; - } - } - else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - test_complete = 1; - - /* Previous state must be COMPLETED. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - test_complete = -750; - } - - /* Status code must be 301. */ - if (tsx->status_code != 301) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, 301)); - test_complete = -751; - } - - } - - - } else if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) { - /* - * Failed INVITE transaction with provisional response. - */ - if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { - - /* Previous state must be PJSIP_TSX_STATE_PROCEEDING. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) { - test_complete = -760; - } - - /* Status code must be 302. */ - if (tsx->status_code != 302) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, 302)); - test_complete = -761; - } - - /* Must have correct retransmission count. */ - if (tsx->retransmit_count != 0) { - PJ_LOG(3,(THIS_FILE, - " error: retransmit cnt is %d instead of %d", - tsx->retransmit_count, 0)); - test_complete = -762; - } - - /* Must still keep last_tx */ - if (tsx->last_tx == NULL) { - PJ_LOG(3,(THIS_FILE, - " error: transaction lost last_tx")); - test_complete = -763; - } - - /* last_tx MUST be INVITE. - * (authorization depends on this behavior) - */ - if (tsx->last_tx && tsx->last_tx->msg->line.req.method.id != - PJSIP_INVITE_METHOD) - { - PJ_LOG(3,(THIS_FILE, - " error: last_tx is not INVITE")); - test_complete = -764; - } - - } - else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - test_complete = 1; - - /* Previous state must be COMPLETED. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - test_complete = -767; - } - - /* Status code must be 302. */ - if (tsx->status_code != 302) { - PJ_LOG(3,(THIS_FILE, - " error: status code is %d instead of %d", - tsx->status_code, 302)); - test_complete = -768; - } - - } - - } -} - -/* - * This timer callback is called to send delayed response. - */ -struct response -{ - pjsip_response_addr res_addr; - pjsip_tx_data *tdata; -}; - -static void send_response_callback( pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry) -{ - struct response *r = (struct response*) entry->user_data; - pjsip_transport *tp = r->res_addr.transport; - - pjsip_endpt_send_response(endpt, &r->res_addr, r->tdata, NULL, NULL); - if (tp) - pjsip_transport_dec_ref(tp); -} - -/* Timer callback to terminate a transaction. */ -static void terminate_tsx_callback( pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry) -{ - struct my_timer *m = (struct my_timer *)entry; - pjsip_transaction *tsx = pjsip_tsx_layer_find_tsx(&m->tsx_key, PJ_FALSE); - int status_code = entry->id; - - if (tsx) { - pjsip_tsx_terminate(tsx, status_code); - } -} - - -#define DIFF(a,b) ((amsg_info.via->branch_param, TEST1_BRANCH_ID) == 0) { - /* - * The TEST1_BRANCH_ID test performs the verifications for transaction - * retransmission mechanism. It will not answer the incoming request - * with any response. - */ - pjsip_msg *msg = rdata->msg_info.msg; - - PJ_LOG(4,(THIS_FILE, " received request")); - - /* Only wants to take INVITE or OPTIONS method. */ - if (msg->line.req.method.id != PJSIP_INVITE_METHOD && - msg->line.req.method.id != PJSIP_OPTIONS_METHOD) - { - PJ_LOG(3,(THIS_FILE, " error: received unexpected method %.*s", - msg->line.req.method.name.slen, - msg->line.req.method.name.ptr)); - test_complete = -600; - return PJ_TRUE; - } - - if (recv_count == 0) { - recv_count++; - //pj_gettimeofday(&recv_last); - recv_last = rdata->pkt_info.timestamp; - } else { - pj_time_val now; - unsigned msec_expected, msec_elapsed; - int max_received; - - //pj_gettimeofday(&now); - now = rdata->pkt_info.timestamp; - PJ_TIME_VAL_SUB(now, recv_last); - msec_elapsed = now.sec*1000 + now.msec; - - ++recv_count; - msec_expected = (1<<(recv_count-2))*pjsip_cfg()->tsx.t1; - - if (msg->line.req.method.id != PJSIP_INVITE_METHOD) { - if (msec_expected > pjsip_cfg()->tsx.t2) - msec_expected = pjsip_cfg()->tsx.t2; - max_received = 11; - } else { - max_received = 7; - } - - if (DIFF(msec_expected, msec_elapsed) > TEST1_ALLOWED_DIFF) { - PJ_LOG(3,(THIS_FILE, - " error: expecting retransmission no. %d in %d " - "ms, received in %d ms", - recv_count-1, msec_expected, msec_elapsed)); - test_complete = -610; - } - - - if (recv_count > max_received) { - PJ_LOG(3,(THIS_FILE, - " error: too many messages (%d) received", - recv_count)); - test_complete = -620; - } - - //pj_gettimeofday(&recv_last); - recv_last = rdata->pkt_info.timestamp; - } - return PJ_TRUE; - - } else - if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID) == 0) { - /* - * The TEST4_BRANCH_ID test simulates transport failure after several - * retransmissions. - */ - recv_count++; - - if (recv_count == TEST4_RETRANSMIT_CNT) { - /* Simulate transport failure. */ - pjsip_loop_set_failure(loop, 2, NULL); - - } else if (recv_count > TEST4_RETRANSMIT_CNT) { - PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -631; - } - - return PJ_TRUE; - - - } else - if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID) == 0) { - /* - * The TEST5_BRANCH_ID test simulates user terminating the transaction - * after several retransmissions. - */ - recv_count++; - - if (recv_count == TEST5_RETRANSMIT_CNT+1) { - pj_str_t key; - pjsip_transaction *tsx; - - pjsip_tsx_create_key( rdata->tp_info.pool, &key, PJSIP_ROLE_UAC, - &rdata->msg_info.msg->line.req.method, rdata); - tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE); - if (tsx) { - pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); - pj_mutex_unlock(tsx->mutex); - } else { - PJ_LOG(3,(THIS_FILE, " error: uac transaction not found!")); - test_complete = -633; - } - - } else if (recv_count > TEST5_RETRANSMIT_CNT+1) { - PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -634; - } - - return PJ_TRUE; - - } else - if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID) == 0) { - /* - * The TEST6_BRANCH_ID test successfull non-INVITE transaction. - */ - pj_status_t status; - - recv_count++; - - if (recv_count > 1) { - PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -635; - } - - status = pjsip_endpt_respond_stateless(endpt, rdata, 202, NULL, - NULL, NULL); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to send response", status); - test_complete = -636; - } - - return PJ_TRUE; - - - } else - if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST7_BRANCH_ID) == 0) { - /* - * The TEST7_BRANCH_ID test successfull non-INVITE transaction - * with provisional response. - */ - pj_status_t status; - pjsip_response_addr res_addr; - struct response *r; - pjsip_tx_data *tdata; - pj_time_val delay = { 2, 0 }; - - recv_count++; - - if (recv_count > 1) { - PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -640; - return PJ_TRUE; - } - - /* Respond with provisional response */ - status = pjsip_endpt_create_response(endpt, rdata, 100, NULL, &tdata); - pj_assert(status == PJ_SUCCESS); - - status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr); - pj_assert(status == PJ_SUCCESS); - - status = pjsip_endpt_send_response(endpt, &res_addr, tdata, - NULL, NULL); - pj_assert(status == PJ_SUCCESS); - - /* Create the final response. */ - status = pjsip_endpt_create_response(endpt, rdata, 202, NULL, &tdata); - pj_assert(status == PJ_SUCCESS); - - /* Schedule sending final response in couple of of secs. */ - r = PJ_POOL_ALLOC_T(tdata->pool, struct response); - r->res_addr = res_addr; - r->tdata = tdata; - if (r->res_addr.transport) - pjsip_transport_add_ref(r->res_addr.transport); - - timer.entry.cb = &send_response_callback; - timer.entry.user_data = r; - pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); - - return PJ_TRUE; - - - } else - if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST8_BRANCH_ID) == 0) { - /* - * The TEST8_BRANCH_ID test failed INVITE transaction. - */ - pjsip_method *method; - pj_status_t status; - - method = &rdata->msg_info.msg->line.req.method; - - recv_count++; - - if (method->id == PJSIP_INVITE_METHOD) { - - if (recv_count > 1) { - PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -635; - } - - status = pjsip_endpt_respond_stateless(endpt, rdata, 301, NULL, - NULL, NULL); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to send response", status); - test_complete = -636; - } - - } else if (method->id == PJSIP_ACK_METHOD) { - - if (recv_count == 2) { - pj_str_t key; - pj_time_val delay = { 5, 0 }; - - /* Schedule timer to destroy transaction after 5 seconds. - * This is to make sure that transaction does not - * retransmit ACK. - */ - pjsip_tsx_create_key(rdata->tp_info.pool, &key, - PJSIP_ROLE_UAC, &pjsip_invite_method, - rdata); - - pj_strcpy(&timer.tsx_key, &key); - timer.entry.id = 301; - timer.entry.cb = &terminate_tsx_callback; - - pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); - } - - if (recv_count > 2) { - PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -638; - } - - - } else { - PJ_LOG(3,(THIS_FILE," error: not expecting %s", - pjsip_rx_data_get_info(rdata))); - test_complete = -639; - - } - - - } else - if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST9_BRANCH_ID) == 0) { - /* - * The TEST9_BRANCH_ID test failed INVITE transaction with - * provisional response. - */ - pjsip_method *method; - pj_status_t status; - - method = &rdata->msg_info.msg->line.req.method; - - recv_count++; - - if (method->id == PJSIP_INVITE_METHOD) { - - pjsip_response_addr res_addr; - struct response *r; - pjsip_tx_data *tdata; - pj_time_val delay = { 2, 0 }; - - if (recv_count > 1) { - PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -650; - return PJ_TRUE; - } - - /* Respond with provisional response */ - status = pjsip_endpt_create_response(endpt, rdata, 100, NULL, - &tdata); - pj_assert(status == PJ_SUCCESS); - - status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr); - pj_assert(status == PJ_SUCCESS); - - status = pjsip_endpt_send_response(endpt, &res_addr, tdata, - NULL, NULL); - pj_assert(status == PJ_SUCCESS); - - /* Create the final response. */ - status = pjsip_endpt_create_response(endpt, rdata, 302, NULL, - &tdata); - pj_assert(status == PJ_SUCCESS); - - /* Schedule sending final response in couple of of secs. */ - r = PJ_POOL_ALLOC_T(tdata->pool, struct response); - r->res_addr = res_addr; - r->tdata = tdata; - if (r->res_addr.transport) - pjsip_transport_add_ref(r->res_addr.transport); - - timer.entry.cb = &send_response_callback; - timer.entry.user_data = r; - pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); - - } else if (method->id == PJSIP_ACK_METHOD) { - - if (recv_count == 2) { - pj_str_t key; - pj_time_val delay = { 5, 0 }; - - /* Schedule timer to destroy transaction after 5 seconds. - * This is to make sure that transaction does not - * retransmit ACK. - */ - pjsip_tsx_create_key(rdata->tp_info.pool, &key, - PJSIP_ROLE_UAC, &pjsip_invite_method, - rdata); - - pj_strcpy(&timer.tsx_key, &key); - timer.entry.id = 302; - timer.entry.cb = &terminate_tsx_callback; - - pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); - } - - if (recv_count > 2) { - PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -638; - } - - - } else { - PJ_LOG(3,(THIS_FILE," error: not expecting %s", - pjsip_rx_data_get_info(rdata))); - test_complete = -639; - - } - - return PJ_TRUE; - - } - - return PJ_FALSE; -} - -/* - * The generic test framework, used by most of the tests. - */ -static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, - char *branch_param, int test_time, - const pjsip_method *method) -{ - pjsip_tx_data *tdata; - pjsip_transaction *tsx; - pj_str_t target, from, tsx_key; - pjsip_via_hdr *via; - pj_time_val timeout; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, - " please standby, this will take at most %d seconds..", - test_time)); - - /* Reset test. */ - recv_count = 0; - test_complete = 0; - - /* Init headers. */ - target = pj_str(target_uri); - from = pj_str(from_uri); - - /* Create request. */ - status = pjsip_endpt_create_request( endpt, method, &target, - &from, &target, NULL, NULL, -1, - NULL, &tdata); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to create request", status); - return -100; - } - - /* Set the branch param for test 1. */ - via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); - via->branch_param = pj_str(branch_param); - - /* Add additional reference to tdata to prevent transaction from - * deleting it. - */ - pjsip_tx_data_add_ref(tdata); - - /* Create transaction. */ - status = pjsip_tsx_create_uac( &tsx_user, tdata, &tsx); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to create UAC transaction", status); - pjsip_tx_data_dec_ref(tdata); - return -110; - } - - /* Get transaction key. */ - pj_strdup(tdata->pool, &tsx_key, &tsx->transaction_key); - - /* Send the message. */ - status = pjsip_tsx_send_msg(tsx, NULL); - // Ignore send result. Some tests do deliberately triggers error - // when sending message. - if (status != PJ_SUCCESS) { - // app_perror(" Error: unable to send request", status); - pjsip_tx_data_dec_ref(tdata); - // return -120; - } - - - /* Set test completion time. */ - pj_gettimeofday(&timeout); - timeout.sec += test_time; - - /* Wait until test complete. */ - while (!test_complete) { - pj_time_val now, poll_delay = {0, 10}; - - pjsip_endpt_handle_events(endpt, &poll_delay); - - pj_gettimeofday(&now); - if (now.sec > timeout.sec) { - PJ_LOG(3,(THIS_FILE, " Error: test has timed out")); - pjsip_tx_data_dec_ref(tdata); - return -130; - } - } - - if (test_complete < 0) { - tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); - if (tsx) { - pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); - pj_mutex_unlock(tsx->mutex); - flush_events(1000); - } - pjsip_tx_data_dec_ref(tdata); - return test_complete; - - } else { - pj_time_val now; - - /* Allow transaction to destroy itself */ - flush_events(500); - - /* Wait until test completes */ - pj_gettimeofday(&now); - - if (PJ_TIME_VAL_LT(now, timeout)) { - pj_time_val interval; - interval = timeout; - PJ_TIME_VAL_SUB(interval, now); - flush_events(PJ_TIME_VAL_MSEC(interval)); - } - } - - /* Make sure transaction has been destroyed. */ - if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) { - PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed")); - pjsip_tx_data_dec_ref(tdata); - return -140; - } - - /* Check tdata reference counter. */ - if (pj_atomic_get(tdata->ref_cnt) != 1) { - PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %d", - pj_atomic_get(tdata->ref_cnt))); - pjsip_tx_data_dec_ref(tdata); - return -150; - } - - /* Destroy txdata */ - pjsip_tx_data_dec_ref(tdata); - - return PJ_SUCCESS; -} - -/***************************************************************************** - ** - ** TEST1_BRANCH_ID: UAC basic retransmission and timeout test. - ** - ** This will test the retransmission of the UAC transaction. Remote will not - ** answer the transaction, so the transaction should fail. The Via branch prm - ** TEST1_BRANCH_ID will be used for this test. - ** - ***************************************************************************** - */ -static int tsx_uac_retransmit_test(void) -{ - int status, enabled; - int i; - struct { - const pjsip_method *method; - unsigned delay; - } sub_test[] = - { - { &pjsip_invite_method, 0}, - { &pjsip_invite_method, TEST1_ALLOWED_DIFF*2}, - { &pjsip_options_method, 0}, - { &pjsip_options_method, TEST1_ALLOWED_DIFF*2} - }; - - PJ_LOG(3,(THIS_FILE, " test1: basic uac retransmit and timeout test")); - - - /* For this test. message printing shound be disabled because it makes - * incorrect timing. - */ - enabled = msg_logger_set_enabled(0); - - for (i=0; i<(int)PJ_ARRAY_SIZE(sub_test); ++i) { - - PJ_LOG(3,(THIS_FILE, - " variant %c: %s with %d ms network delay", - ('a' + i), - sub_test[i].method->name.ptr, - sub_test[i].delay)); - - /* Configure transport */ - pjsip_loop_set_failure(loop, 0, NULL); - pjsip_loop_set_recv_delay(loop, sub_test[i].delay, NULL); - - /* Do the test. */ - status = perform_tsx_test(-500, TARGET_URI, FROM_URI, - TEST1_BRANCH_ID, - 35, sub_test[i].method); - if (status != 0) - break; - } - - /* Restore transport. */ - pjsip_loop_set_recv_delay(loop, 0, NULL); - - /* Restore msg logger. */ - msg_logger_set_enabled(enabled); - - /* Done. */ - return status; -} - -/***************************************************************************** - ** - ** TEST2_BRANCH_ID: UAC resolve error test. - ** - ** Test the scenario where destination host is unresolvable. There are - ** two variants: - ** (a) resolver returns immediate error - ** (b) resolver returns error via the callback. - ** - ***************************************************************************** - */ -static int tsx_resolve_error_test(void) -{ - int status; - - PJ_LOG(3,(THIS_FILE, " test2: resolve error test")); - - /* - * Variant (a): immediate resolve error. - */ - PJ_LOG(3,(THIS_FILE, " variant a: immediate resolving error")); - - status = perform_tsx_test(-800, - "sip:bob@unresolved-host", - FROM_URI, TEST2_BRANCH_ID, 20, - &pjsip_options_method); - if (status != 0) - return status; - - /* - * Variant (b): error via callback. - */ - PJ_LOG(3,(THIS_FILE, " variant b: error via callback")); - - /* This only applies to "loop-dgram" transport */ - if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { - /* Set loop transport to return delayed error. */ - pjsip_loop_set_failure(loop, 2, NULL); - pjsip_loop_set_send_callback_delay(loop, 10, NULL); - - status = perform_tsx_test(-800, TARGET_URI, FROM_URI, - TEST2_BRANCH_ID, 2, - &pjsip_options_method); - if (status != 0) - return status; - - /* Restore loop transport settings. */ - pjsip_loop_set_failure(loop, 0, NULL); - pjsip_loop_set_send_callback_delay(loop, 0, NULL); - } - - return status; -} - - -/***************************************************************************** - ** - ** TEST3_BRANCH_ID: UAC terminate while resolving test. - ** - ** Terminate the transaction while resolver is still running. - ** - ***************************************************************************** - */ -static int tsx_terminate_resolving_test(void) -{ - unsigned prev_delay; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, " test3: terminate while resolving test")); - - /* Configure transport delay. */ - pjsip_loop_set_send_callback_delay(loop, 100, &prev_delay); - - /* Start the test. */ - status = perform_tsx_test(-900, TARGET_URI, FROM_URI, - TEST3_BRANCH_ID, 2, &pjsip_options_method); - - /* Restore delay. */ - pjsip_loop_set_send_callback_delay(loop, prev_delay, NULL); - - return status; -} - - -/***************************************************************************** - ** - ** TEST4_BRANCH_ID: Transport failed after several retransmissions - ** - ** There are two variants of this test: (a) failure occurs immediately when - ** transaction calls pjsip_transport_send() or (b) failure is reported via - ** transport callback. - ** - ***************************************************************************** - */ -static int tsx_retransmit_fail_test(void) -{ - int i; - unsigned delay[] = {0, 10}; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, - " test4: transport fails after several retransmissions test")); - - - for (i=0; i<(int)PJ_ARRAY_SIZE(delay); ++i) { - - PJ_LOG(3,(THIS_FILE, - " variant %c: transport delay %d ms", ('a'+i), delay[i])); - - /* Configure transport delay. */ - pjsip_loop_set_send_callback_delay(loop, delay[i], NULL); - - /* Restore transport failure mode. */ - pjsip_loop_set_failure(loop, 0, 0); - - /* Start the test. */ - status = perform_tsx_test(-1000, TARGET_URI, FROM_URI, - TEST4_BRANCH_ID, 6, &pjsip_options_method); - - if (status != 0) - break; - - } - - /* Restore delay. */ - pjsip_loop_set_send_callback_delay(loop, 0, NULL); - - /* Restore transport failure mode. */ - pjsip_loop_set_failure(loop, 0, 0); - - return status; -} - - -/***************************************************************************** - ** - ** TEST5_BRANCH_ID: Terminate transaction after several retransmissions - ** - ***************************************************************************** - */ -static int tsx_terminate_after_retransmit_test(void) -{ - int status; - - PJ_LOG(3,(THIS_FILE, " test5: terminate after retransmissions")); - - /* Do the test. */ - status = perform_tsx_test(-1100, TARGET_URI, FROM_URI, - TEST5_BRANCH_ID, - 6, &pjsip_options_method); - - /* Done. */ - return status; -} - - -/***************************************************************************** - ** - ** TEST6_BRANCH_ID: Successfull non-invite transaction - ** TEST7_BRANCH_ID: Successfull non-invite transaction with provisional - ** TEST8_BRANCH_ID: Failed invite transaction - ** TEST9_BRANCH_ID: Failed invite transaction with provisional - ** - ***************************************************************************** - */ -static int perform_generic_test( const char *title, - char *branch_id, - const pjsip_method *method) -{ - int i, status; - unsigned delay[] = { 1, 200 }; - - PJ_LOG(3,(THIS_FILE, " %s", title)); - - /* Do the test. */ - for (i=0; i<(int)PJ_ARRAY_SIZE(delay); ++i) { - - if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { - PJ_LOG(3,(THIS_FILE, " variant %c: with %d ms transport delay", - ('a'+i), delay[i])); - - pjsip_loop_set_delay(loop, delay[i]); - } - - status = perform_tsx_test(-1200, TARGET_URI, FROM_URI, - branch_id, 10, method); - if (status != 0) - return status; - - if (test_param->type != PJSIP_TRANSPORT_LOOP_DGRAM) - break; - } - - pjsip_loop_set_delay(loop, 0); - - /* Done. */ - return status; -} - - -/***************************************************************************** - ** - ** UAC Transaction Test. - ** - ***************************************************************************** - */ -int tsx_uac_test(struct tsx_test_param *param) -{ - pj_sockaddr_in addr; - pj_status_t status; - - timer.tsx_key.ptr = timer.key_buf; - - test_param = param; - - /* Get transport flag */ - tp_flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)test_param->type); - - pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", - param->port, param->tp_type); - pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", - param->port, param->tp_type); - - /* Check if loop transport is configured. */ - status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, - &addr, sizeof(addr), NULL, &loop); - if (status != PJ_SUCCESS) { - PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!")); - return -10; - } - - /* Register modules. */ - status = pjsip_endpt_register_module(endpt, &tsx_user); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to register module", status); - return -30; - } - status = pjsip_endpt_register_module(endpt, &msg_receiver); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to register module", status); - return -40; - } - - /* TEST1_BRANCH_ID: Basic retransmit and timeout test. */ - status = tsx_uac_retransmit_test(); - if (status != 0) - return status; - - /* TEST2_BRANCH_ID: Resolve error test. */ - status = tsx_resolve_error_test(); - if (status != 0) - return status; - - /* TEST3_BRANCH_ID: UAC terminate while resolving test. */ - status = tsx_terminate_resolving_test(); - if (status != 0) - return status; - - /* TEST4_BRANCH_ID: Transport failed after several retransmissions. - * Only applies to loop transport. - */ - if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { - status = tsx_retransmit_fail_test(); - if (status != 0) - return status; - } - - /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions - * Only applicable to non-reliable transports. - */ - if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { - status = tsx_terminate_after_retransmit_test(); - if (status != 0) - return status; - } - - /* TEST6_BRANCH_ID: Successfull non-invite transaction */ - status = perform_generic_test("test6: successfull non-invite transaction", - TEST6_BRANCH_ID, &pjsip_options_method); - if (status != 0) - return status; - - /* TEST7_BRANCH_ID: Successfull non-invite transaction */ - status = perform_generic_test("test7: successfull non-invite transaction " - "with provisional response", - TEST7_BRANCH_ID, &pjsip_options_method); - if (status != 0) - return status; - - /* TEST8_BRANCH_ID: Failed invite transaction */ - status = perform_generic_test("test8: failed invite transaction", - TEST8_BRANCH_ID, &pjsip_invite_method); - if (status != 0) - return status; - - /* TEST9_BRANCH_ID: Failed invite transaction with provisional response */ - status = perform_generic_test("test9: failed invite transaction with " - "provisional response", - TEST9_BRANCH_ID, &pjsip_invite_method); - if (status != 0) - return status; - - pjsip_transport_dec_ref(loop); - flush_events(500); - - /* Unregister modules. */ - status = pjsip_endpt_unregister_module(endpt, &tsx_user); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to unregister module", status); - return -31; - } - status = pjsip_endpt_unregister_module(endpt, &msg_receiver); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to unregister module", status); - return -41; - } - - return 0; -} - diff --git a/pjsip/src/test-pjsip/tsx_uas_test.c b/pjsip/src/test-pjsip/tsx_uas_test.c deleted file mode 100644 index 813e4e50..00000000 --- a/pjsip/src/test-pjsip/tsx_uas_test.c +++ /dev/null @@ -1,1656 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - -#include "test.h" -#include -#include - -#define THIS_FILE "tsx_uas_test.c" - - -/***************************************************************************** - ** - ** UAS tests. - ** - ** This file performs various tests for UAC transactions. Each test will have - ** a different Via branch param so that message receiver module and - ** transaction user module can identify which test is being carried out. - ** - ** TEST1_BRANCH_ID - ** Test that non-INVITE transaction returns 2xx response to the correct - ** transport and correctly terminates the transaction. - ** This also checks that transaction is destroyed immediately after - ** it sends final response when reliable transport is used. - ** - ** TEST2_BRANCH_ID - ** As above, for non-2xx final response. - ** - ** TEST3_BRANCH_ID - ** Transaction correctly progressing to PROCEEDING state when provisional - ** response is sent. - ** - ** TEST4_BRANCH_ID - ** Transaction retransmits last response (if any) without notifying - ** transaction user upon receiving request retransmissions on TRYING - ** state - ** - ** TEST5_BRANCH_ID - ** As above, in PROCEEDING state. - ** - ** TEST6_BRANCH_ID - ** As above, in COMPLETED state, with first sending provisional response. - ** (Only applicable for non-reliable transports). - ** - ** TEST7_BRANCH_ID - ** INVITE transaction MUST retransmit non-2xx final response. - ** - ** TEST8_BRANCH_ID - ** As above, for INVITE's 2xx final response (this is PJSIP specific). - ** - ** TEST9_BRANCH_ID - ** INVITE transaction MUST cease retransmission of final response when - ** ACK is received. (Note: PJSIP also retransmit 2xx final response - ** until it's terminated by user). - ** Transaction also MUST terminate in T4 seconds. - ** (Only applicable for non-reliable transports). - ** - ** TEST11_BRANCH_ID - ** Test scenario where transport fails before response is sent (i.e. - ** in TRYING state). - ** - ** TEST12_BRANCH_ID - ** As above, after provisional response is sent but before final - ** response is sent (i.e. in PROCEEDING state). - ** - ** TEST13_BRANCH_ID - ** As above, for INVITE, after final response has been sent but before - ** ACK is received (i.e. in CONNECTED state). - ** - ** TEST14_BRANCH_ID - ** When UAS failed to deliver the response with the selected transport, - ** it should try contacting the client with other transport or begin - ** RFC 3263 server resolution procedure. - ** This should be tested on: - ** a. TRYING state (when delivering first response). - ** b. PROCEEDING state (when failed to retransmit last response - ** upon receiving request retransmission). - ** c. COMPLETED state. - ** - **/ - -static char *TEST1_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test1"; -static char *TEST2_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test2"; -static char *TEST3_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test3"; -static char *TEST4_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test4"; -static char *TEST5_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test5"; -static char *TEST6_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test6"; -static char *TEST7_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test7"; -static char *TEST8_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test8"; -static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test9"; -static char *TEST10_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test10"; -static char *TEST11_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test11"; -static char *TEST12_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test12"; -//static char *TEST13_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test13"; - -#define TEST1_STATUS_CODE 200 -#define TEST2_STATUS_CODE 301 -#define TEST3_PROVISIONAL_CODE PJSIP_SC_QUEUED -#define TEST3_STATUS_CODE 202 -#define TEST4_STATUS_CODE 200 -#define TEST4_REQUEST_COUNT 2 -#define TEST5_PROVISIONAL_CODE 100 -#define TEST5_STATUS_CODE 200 -#define TEST5_REQUEST_COUNT 2 -#define TEST5_RESPONSE_COUNT 2 -#define TEST6_PROVISIONAL_CODE 100 -#define TEST6_STATUS_CODE 200 /* Must be final */ -#define TEST6_REQUEST_COUNT 2 -#define TEST6_RESPONSE_COUNT 3 -#define TEST7_STATUS_CODE 301 -#define TEST8_STATUS_CODE 302 -#define TEST9_STATUS_CODE 301 - - -#define TEST4_TITLE "test4: absorbing request retransmission" -#define TEST5_TITLE "test5: retransmit last response in PROCEEDING state" -#define TEST6_TITLE "test6: retransmit last response in COMPLETED state" - - -static char TARGET_URI[128]; -static char FROM_URI[128]; -static struct tsx_test_param *test_param; -static unsigned tp_flag; - - -#define TEST_TIMEOUT_ERROR -30 -#define MAX_ALLOWED_DIFF 150 - -static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e); -static pj_bool_t on_rx_message(pjsip_rx_data *rdata); - -/* UAC transaction user module. */ -static pjsip_module tsx_user = -{ - NULL, NULL, /* prev and next */ - { "Tsx-UAS-User", 12}, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - NULL, /* on_rx_request() */ - NULL, /* on_rx_response() */ - NULL, /* on_tx_request() */ - NULL, /* on_tx_response() */ - &tsx_user_on_tsx_state, /* on_tsx_state() */ -}; - -/* Module to send request. */ -static pjsip_module msg_sender = -{ - NULL, NULL, /* prev and next */ - { "Msg-Sender", 10}, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &on_rx_message, /* on_rx_request() */ - &on_rx_message, /* on_rx_response() */ - NULL, /* on_tx_request() */ - NULL, /* on_tx_response() */ - NULL, /* on_tsx_state() */ -}; - -/* Static vars, which will be reset on each test. */ -static int recv_count; -static pj_time_val recv_last; -static pj_bool_t test_complete; - -/* Loop transport instance. */ -static pjsip_transport *loop; - -/* UAS transaction key. */ -static char key_buf[64]; -static pj_str_t tsx_key = { key_buf, 0 }; - - -/* General timer entry to be used by tests. */ -//static pj_timer_entry timer; - -/* Timer to send response via transaction. */ -struct response -{ - pj_str_t tsx_key; - pjsip_tx_data *tdata; -}; - -/* Timer callback to send response. */ -static void send_response_timer( pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry) -{ - pjsip_transaction *tsx; - struct response *r = (struct response*) entry->user_data; - pj_status_t status; - - tsx = pjsip_tsx_layer_find_tsx(&r->tsx_key, PJ_TRUE); - if (!tsx) { - PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction")); - pjsip_tx_data_dec_ref(r->tdata); - return; - } - - status = pjsip_tsx_send_msg(tsx, r->tdata); - if (status != PJ_SUCCESS) { - // Some tests do expect failure! - //PJ_LOG(3,(THIS_FILE," error: timer unable to send response")); - pj_mutex_unlock(tsx->mutex); - pjsip_tx_data_dec_ref(r->tdata); - return; - } - - pj_mutex_unlock(tsx->mutex); -} - -/* Utility to send response. */ -static void send_response( pjsip_rx_data *rdata, - pjsip_transaction *tsx, - int status_code ) -{ - pj_status_t status; - pjsip_tx_data *tdata; - - status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL, - &tdata); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create response", status); - test_complete = -196; - return; - } - - status = pjsip_tsx_send_msg(tsx, tdata); - if (status != PJ_SUCCESS) { - pjsip_tx_data_dec_ref(tdata); - // Some tests do expect failure! - //app_perror(" error: unable to send response", status); - //test_complete = -197; - return; - } -} - -/* Schedule timer to send response for the specified UAS transaction */ -static void schedule_send_response( pjsip_rx_data *rdata, - const pj_str_t *tsx_key, - int status_code, - int msec_delay ) -{ - pj_status_t status; - pjsip_tx_data *tdata; - pj_timer_entry *t; - struct response *r; - pj_time_val delay; - - status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL, - &tdata); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create response", status); - test_complete = -198; - return; - } - - r = PJ_POOL_ALLOC_T(tdata->pool, struct response); - pj_strdup(tdata->pool, &r->tsx_key, tsx_key); - r->tdata = tdata; - - delay.sec = 0; - delay.msec = msec_delay; - pj_time_val_normalize(&delay); - - t = PJ_POOL_ZALLOC_T(tdata->pool, pj_timer_entry); - t->user_data = r; - t->cb = &send_response_timer; - - status = pjsip_endpt_schedule_timer(endpt, t, &delay); - if (status != PJ_SUCCESS) { - pjsip_tx_data_dec_ref(tdata); - app_perror(" error: unable to schedule timer", status); - test_complete = -199; - return; - } -} - - -/* Find and terminate tsx with the specified key. */ -static void terminate_our_tsx(int status_code) -{ - pjsip_transaction *tsx; - - tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); - if (!tsx) { - PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction")); - return; - } - - pjsip_tsx_terminate(tsx, status_code); - pj_mutex_unlock(tsx->mutex); -} - -#if 0 /* Unused for now */ -/* Timer callback to terminate transaction. */ -static void terminate_tsx_timer( pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry) -{ - terminate_our_tsx(entry->id); -} - - -/* Schedule timer to terminate transaction. */ -static void schedule_terminate_tsx( pjsip_transaction *tsx, - int status_code, - int msec_delay ) -{ - pj_time_val delay; - - delay.sec = 0; - delay.msec = msec_delay; - pj_time_val_normalize(&delay); - - pj_assert(pj_strcmp(&tsx->transaction_key, &tsx_key)==0); - timer.user_data = NULL; - timer.id = status_code; - timer.cb = &terminate_tsx_timer; - pjsip_endpt_schedule_timer(endpt, &timer, &delay); -} -#endif - - -/* - * This is the handler to receive state changed notification from the - * transaction. It is used to verify that the transaction behaves according - * to the test scenario. - */ -static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) -{ - if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0 || - pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) - { - /* - * TEST1_BRANCH_ID tests that non-INVITE transaction transmits final - * response using correct transport and terminates transaction after - * T4 (PJSIP_T4_TIMEOUT, 5 seconds). - * - * TEST2_BRANCH_ID does similar test for non-2xx final response. - */ - int status_code = (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) ? - TEST1_STATUS_CODE : TEST2_STATUS_CODE; - - if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - test_complete = 1; - - /* Check that status code is status_code. */ - if (tsx->status_code != status_code) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -100; - } - - /* Previous state must be completed. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -101; - } - - } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { - - /* Previous state must be TRYING. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -102; - } - } - - } - else - if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) { - /* - * TEST3_BRANCH_ID tests sending provisional response. - */ - if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - test_complete = 1; - - /* Check that status code is status_code. */ - if (tsx->status_code != TEST3_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -110; - } - - /* Previous state must be completed. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -111; - } - - } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) { - - /* Previous state must be TRYING. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -112; - } - - /* Check that status code is status_code. */ - if (tsx->status_code != TEST3_PROVISIONAL_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -113; - } - - /* Check that event must be TX_MSG */ - if (e->body.tsx_state.type != PJSIP_EVENT_TX_MSG) { - PJ_LOG(3,(THIS_FILE, " error: incorrect event")); - test_complete = -114; - } - - } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { - - /* Previous state must be PROCEEDING. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -115; - } - - /* Check that status code is status_code. */ - if (tsx->status_code != TEST3_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -116; - } - - /* Check that event must be TX_MSG */ - if (e->body.tsx_state.type != PJSIP_EVENT_TX_MSG) { - PJ_LOG(3,(THIS_FILE, " error: incorrect event")); - test_complete = -117; - } - - } - - } else - if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) { - /* - * TEST4_BRANCH_ID tests receiving retransmissions in TRYING state. - */ - if (tsx->state == PJSIP_TSX_STATE_TRYING) { - /* Request is received. */ - } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - /* Check that status code is status_code. */ - if (tsx->status_code != TEST4_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, - " error: incorrect status code %d " - "(expecting %d)", tsx->status_code, - TEST4_STATUS_CODE)); - test_complete = -120; - } - - /* Previous state. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -121; - } - - } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) - { - PJ_LOG(3,(THIS_FILE, " error: unexpected state %s (122)", - pjsip_tsx_state_str(tsx->state))); - test_complete = -122; - - } - - - } else - if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) { - /* - * TEST5_BRANCH_ID tests receiving retransmissions in PROCEEDING state - */ - if (tsx->state == PJSIP_TSX_STATE_TRYING) { - /* Request is received. */ - - } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - /* Check that status code is status_code. */ - if (tsx->status_code != TEST5_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -130; - } - - /* Previous state. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -131; - } - - } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) { - - /* Check status code. */ - if (tsx->status_code != TEST5_PROVISIONAL_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -132; - } - - } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) { - PJ_LOG(3,(THIS_FILE, " error: unexpected state %s (133)", - pjsip_tsx_state_str(tsx->state))); - test_complete = -133; - - } - - } else - if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) { - /* - * TEST6_BRANCH_ID tests receiving retransmissions in COMPLETED state - */ - if (tsx->state == PJSIP_TSX_STATE_TRYING) { - /* Request is received. */ - - } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - /* Check that status code is status_code. */ - if (tsx->status_code != TEST6_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code %d " - "(expecting %d)", tsx->status_code, - TEST6_STATUS_CODE)); - test_complete = -140; - } - - /* Previous state. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -141; - } - - } else if (tsx->state != PJSIP_TSX_STATE_PROCEEDING && - tsx->state != PJSIP_TSX_STATE_COMPLETED && - tsx->state != PJSIP_TSX_STATE_DESTROYED) - { - PJ_LOG(3,(THIS_FILE, " error: unexpected state %s (142)", - pjsip_tsx_state_str(tsx->state))); - test_complete = -142; - - } - - - } else - if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0 || - pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0) - { - /* - * TEST7_BRANCH_ID and TEST8_BRANCH_ID test retransmission of - * INVITE final response - */ - int code; - - if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID) == 0) - code = TEST7_STATUS_CODE; - else - code = TEST8_STATUS_CODE; - - if (tsx->state == PJSIP_TSX_STATE_TRYING) { - /* Request is received. */ - - } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - if (test_complete == 0) - test_complete = 1; - - /* Check status code. */ - if (tsx->status_code != PJSIP_SC_TSX_TIMEOUT) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -150; - } - - /* Previous state. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -151; - } - - /* Check the number of retransmissions */ - if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { - - if (tsx->retransmit_count != 0) { - PJ_LOG(3,(THIS_FILE, " error: should not retransmit")); - test_complete = -1510; - } - - } else { - - if (tsx->retransmit_count != 10) { - PJ_LOG(3,(THIS_FILE, - " error: incorrect retransmit count %d " - "(expecting 10)", - tsx->retransmit_count)); - test_complete = -1510; - } - - } - - } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { - - /* Check that status code is status_code. */ - if (tsx->status_code != code) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -152; - } - - /* Previous state. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -153; - } - - } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) { - - PJ_LOG(3,(THIS_FILE, " error: unexpected state (154)")); - test_complete = -154; - - } - - - } else - if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) { - /* - * TEST9_BRANCH_ID tests that retransmission of INVITE final response - * must cease when ACK is received. - */ - - if (tsx->state == PJSIP_TSX_STATE_TRYING) { - /* Request is received. */ - - } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - if (test_complete == 0) - test_complete = 1; - - /* Check status code. */ - if (tsx->status_code != TEST9_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -160; - } - - /* Previous state. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_CONFIRMED) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -161; - } - - } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { - - /* Check that status code is status_code. */ - if (tsx->status_code != TEST9_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -162; - } - - /* Previous state. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -163; - } - - - } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) { - - /* Check that status code is status_code. */ - if (tsx->status_code != TEST9_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -164; - } - - /* Previous state. */ - if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); - test_complete = -165; - } - - } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) { - - PJ_LOG(3,(THIS_FILE, " error: unexpected state (166)")); - test_complete = -166; - - } - - - } else - if (pj_strcmp2(&tsx->branch, TEST10_BRANCH_ID)==0 || - pj_strcmp2(&tsx->branch, TEST11_BRANCH_ID)==0 || - pj_strcmp2(&tsx->branch, TEST12_BRANCH_ID)==0) - { - if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - - if (!test_complete) - test_complete = 1; - - if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) { - PJ_LOG(3,(THIS_FILE," error: incorrect status code")); - test_complete = -170; - } - } - } - -} - -/* Save transaction key to global variables. */ -static void save_key(pjsip_transaction *tsx) -{ - pj_str_t key; - - pj_strdup(tsx->pool, &key, &tsx->transaction_key); - pj_strcpy(&tsx_key, &key); -} - -#define DIFF(a,b) ((amsg_info.msg; - pj_str_t branch_param = rdata->msg_info.via->branch_param; - pj_status_t status; - - if (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0 || - pj_strcmp2(&branch_param, TEST2_BRANCH_ID) == 0) - { - /* - * TEST1_BRANCH_ID tests that non-INVITE transaction transmits 2xx - * final response using correct transport and terminates transaction - * after 32 seconds. - * - * TEST2_BRANCH_ID performs similar test for non-2xx final response. - */ - int status_code = (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0) ? - TEST1_STATUS_CODE : TEST2_STATUS_CODE; - - if (msg->type == PJSIP_REQUEST_MSG) { - /* On received request, create UAS and respond with final - * response. - */ - pjsip_transaction *tsx; - - status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create transaction", status); - test_complete = -110; - return PJ_TRUE; - } - pjsip_tsx_recv_msg(tsx, rdata); - - save_key(tsx); - send_response(rdata, tsx, status_code); - - } else { - /* Verify the response received. */ - - ++recv_count; - - /* Verify status code. */ - if (msg->line.status.code != status_code) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -113; - } - - /* Verify that no retransmissions is received. */ - if (recv_count > 1) { - PJ_LOG(3,(THIS_FILE, " error: retransmission received")); - test_complete = -114; - } - - } - return PJ_TRUE; - - } else if (pj_strcmp2(&branch_param, TEST3_BRANCH_ID) == 0) { - - /* TEST3_BRANCH_ID tests provisional response. */ - - if (msg->type == PJSIP_REQUEST_MSG) { - /* On received request, create UAS and respond with provisional - * response, then schedule timer to send final response. - */ - pjsip_transaction *tsx; - - status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create transaction", status); - test_complete = -116; - return PJ_TRUE; - } - pjsip_tsx_recv_msg(tsx, rdata); - - save_key(tsx); - - send_response(rdata, tsx, TEST3_PROVISIONAL_CODE); - schedule_send_response(rdata, &tsx->transaction_key, - TEST3_STATUS_CODE, 2000); - - } else { - /* Verify the response received. */ - - ++recv_count; - - if (recv_count == 1) { - /* Verify status code. */ - if (msg->line.status.code != TEST3_PROVISIONAL_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -123; - } - } else if (recv_count == 2) { - /* Verify status code. */ - if (msg->line.status.code != TEST3_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -124; - } - } else { - PJ_LOG(3,(THIS_FILE, " error: retransmission received")); - test_complete = -125; - } - - } - return PJ_TRUE; - - } else if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0 || - pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0 || - pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) - { - - /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state. */ - /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state. */ - /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state. */ - - if (msg->type == PJSIP_REQUEST_MSG) { - /* On received request, create UAS. */ - pjsip_transaction *tsx; - - PJ_LOG(4,(THIS_FILE, " received request (probably retransmission)")); - - status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create transaction", status); - test_complete = -130; - return PJ_TRUE; - } - - pjsip_tsx_recv_msg(tsx, rdata); - save_key(tsx); - - if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) { - - } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) { - send_response(rdata, tsx, TEST5_PROVISIONAL_CODE); - - } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) { - PJ_LOG(4,(THIS_FILE, " sending provisional response")); - send_response(rdata, tsx, TEST6_PROVISIONAL_CODE); - PJ_LOG(4,(THIS_FILE, " sending final response")); - send_response(rdata, tsx, TEST6_STATUS_CODE); - } - - } else { - /* Verify the response received. */ - - PJ_LOG(4,(THIS_FILE, " received response number %d", recv_count)); - - ++recv_count; - - if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) { - PJ_LOG(3,(THIS_FILE, " error: not expecting response!")); - test_complete = -132; - - } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) { - - if (rdata->msg_info.msg->line.status.code!=TEST5_PROVISIONAL_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code!")); - test_complete = -133; - - } - if (recv_count > TEST5_RESPONSE_COUNT) { - PJ_LOG(3,(THIS_FILE, " error: not expecting response!")); - test_complete = -134; - } - - } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) { - - int code = rdata->msg_info.msg->line.status.code; - - switch (recv_count) { - case 1: - if (code != TEST6_PROVISIONAL_CODE) { - PJ_LOG(3,(THIS_FILE, " error: invalid code!")); - test_complete = -135; - } - break; - case 2: - case 3: - if (code != TEST6_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: invalid code %d " - "(expecting %d)", code, TEST6_STATUS_CODE)); - test_complete = -136; - } - break; - default: - PJ_LOG(3,(THIS_FILE, " error: not expecting response")); - test_complete = -137; - break; - } - } - } - return PJ_TRUE; - - - } else if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0 || - pj_strcmp2(&branch_param, TEST8_BRANCH_ID) == 0) - { - - /* - * TEST7_BRANCH_ID and TEST8_BRANCH_ID test the retransmission - * of INVITE final response - */ - if (msg->type == PJSIP_REQUEST_MSG) { - - /* On received request, create UAS. */ - pjsip_transaction *tsx; - - status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create transaction", status); - test_complete = -140; - return PJ_TRUE; - } - - pjsip_tsx_recv_msg(tsx, rdata); - save_key(tsx); - - if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0) { - - send_response(rdata, tsx, TEST7_STATUS_CODE); - - } else { - - send_response(rdata, tsx, TEST8_STATUS_CODE); - - } - - } else { - int code; - - ++recv_count; - - if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0) - code = TEST7_STATUS_CODE; - else - code = TEST8_STATUS_CODE; - - if (recv_count==1) { - - if (rdata->msg_info.msg->line.status.code != code) { - PJ_LOG(3,(THIS_FILE," error: invalid status code")); - test_complete = -141; - } - - recv_last = rdata->pkt_info.timestamp; - - } else { - - pj_time_val now; - unsigned msec, msec_expected; - - now = rdata->pkt_info.timestamp; - - PJ_TIME_VAL_SUB(now, recv_last); - - msec = now.sec*1000 + now.msec; - msec_expected = (1 << (recv_count-2)) * pjsip_cfg()->tsx.t1; - if (msec_expected > pjsip_cfg()->tsx.t2) - msec_expected = pjsip_cfg()->tsx.t2; - - if (DIFF(msec, msec_expected) > MAX_ALLOWED_DIFF) { - PJ_LOG(3,(THIS_FILE, - " error: incorrect retransmission " - "time (%d ms expected, %d ms received", - msec_expected, msec)); - test_complete = -142; - } - - if (recv_count > 11) { - PJ_LOG(3,(THIS_FILE," error: too many responses (%d)", - recv_count)); - test_complete = -143; - } - - recv_last = rdata->pkt_info.timestamp; - } - - } - return PJ_TRUE; - - } else if (pj_strcmp2(&branch_param, TEST9_BRANCH_ID) == 0) { - - /* - * TEST9_BRANCH_ID tests that the retransmission of INVITE final - * response should cease when ACK is received. Transaction also MUST - * terminate in T4 seconds. - */ - if (msg->type == PJSIP_REQUEST_MSG) { - - /* On received request, create UAS. */ - pjsip_transaction *tsx; - - status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create transaction", status); - test_complete = -150; - return PJ_TRUE; - } - - pjsip_tsx_recv_msg(tsx, rdata); - save_key(tsx); - send_response(rdata, tsx, TEST9_STATUS_CODE); - - - } else { - - ++recv_count; - - if (rdata->msg_info.msg->line.status.code != TEST9_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE," error: invalid status code")); - test_complete = -151; - } - - if (recv_count==1) { - - recv_last = rdata->pkt_info.timestamp; - - } else if (recv_count < 5) { - - /* Let UAS retransmit some messages before we send ACK. */ - pj_time_val now; - unsigned msec, msec_expected; - - now = rdata->pkt_info.timestamp; - - PJ_TIME_VAL_SUB(now, recv_last); - - msec = now.sec*1000 + now.msec; - msec_expected = (1 << (recv_count-2)) * pjsip_cfg()->tsx.t1; - if (msec_expected > pjsip_cfg()->tsx.t2) - msec_expected = pjsip_cfg()->tsx.t2; - - if (DIFF(msec, msec_expected) > MAX_ALLOWED_DIFF) { - PJ_LOG(3,(THIS_FILE, - " error: incorrect retransmission " - "time (%d ms expected, %d ms received", - msec_expected, msec)); - test_complete = -152; - } - - recv_last = rdata->pkt_info.timestamp; - - } else if (recv_count == 5) { - pjsip_tx_data *tdata; - pjsip_sip_uri *uri; - pjsip_via_hdr *via; - - status = pjsip_endpt_create_request_from_hdr( - endpt, &pjsip_ack_method, - rdata->msg_info.to->uri, - rdata->msg_info.from, - rdata->msg_info.to, - NULL, - rdata->msg_info.cid, - rdata->msg_info.cseq->cseq, - NULL, - &tdata); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create ACK", status); - test_complete = -153; - return PJ_TRUE; - } - - uri=(pjsip_sip_uri*)pjsip_uri_get_uri(tdata->msg->line.req.uri); - uri->transport_param = pj_str("loop-dgram"); - - via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); - via->branch_param = pj_str(TEST9_BRANCH_ID); - - status = pjsip_endpt_send_request_stateless(endpt, tdata, - NULL, NULL); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to send ACK", status); - test_complete = -154; - } - - } else { - PJ_LOG(3,(THIS_FILE," error: too many responses (%d)", - recv_count)); - test_complete = -155; - } - - } - return PJ_TRUE; - - } else if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0 || - pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0 || - pj_strcmp2(&branch_param, TEST12_BRANCH_ID) == 0) - { - int test_num, code1, code2; - - if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0) - test_num=10, code1 = 100, code2 = 0; - else if (pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0) - test_num=11, code1 = 100, code2 = 200; - else - test_num=12, code1 = 200, code2 = 0; - - if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) { - - /* On received response, create UAS. */ - pjsip_transaction *tsx; - - status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create transaction", status); - test_complete = -150; - return PJ_TRUE; - } - - pjsip_tsx_recv_msg(tsx, rdata); - save_key(tsx); - - schedule_send_response(rdata, &tsx_key, code1, 1000); - - if (code2) - schedule_send_response(rdata, &tsx_key, code2, 2000); - - } else { - - } - - return PJ_TRUE; - } - - return PJ_FALSE; -} - -/* - * The generic test framework, used by most of the tests. - */ -static int perform_test( char *target_uri, char *from_uri, - char *branch_param, int test_time, - const pjsip_method *method, - int request_cnt, int request_interval_msec, - int expecting_timeout) -{ - pjsip_tx_data *tdata; - pj_str_t target, from; - pjsip_via_hdr *via; - pj_time_val timeout, next_send; - int sent_cnt; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, - " please standby, this will take at most %d seconds..", - test_time)); - - /* Reset test. */ - recv_count = 0; - test_complete = 0; - tsx_key.slen = 0; - - /* Init headers. */ - target = pj_str(target_uri); - from = pj_str(from_uri); - - /* Create request. */ - status = pjsip_endpt_create_request( endpt, method, &target, - &from, &target, NULL, NULL, -1, - NULL, &tdata); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to create request", status); - return -10; - } - - /* Set the branch param for test 1. */ - via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); - via->branch_param = pj_str(branch_param); - - /* Schedule first send. */ - sent_cnt = 0; - pj_gettimeofday(&next_send); - pj_time_val_normalize(&next_send); - - /* Set test completion time. */ - pj_gettimeofday(&timeout); - timeout.sec += test_time; - - /* Wait until test complete. */ - while (!test_complete) { - pj_time_val now, poll_delay = {0, 10}; - - pjsip_endpt_handle_events(endpt, &poll_delay); - - pj_gettimeofday(&now); - - if (sent_cnt < request_cnt && PJ_TIME_VAL_GTE(now, next_send)) { - /* Add additional reference to tdata to prevent transaction from - * deleting it. - */ - pjsip_tx_data_add_ref(tdata); - - /* (Re)Send the request. */ - PJ_LOG(4,(THIS_FILE, " (re)sending request %d", sent_cnt)); - - status = pjsip_endpt_send_request_stateless(endpt, tdata, 0, 0); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to send request", status); - pjsip_tx_data_dec_ref(tdata); - return -20; - } - - /* Schedule next send, if any. */ - sent_cnt++; - if (sent_cnt < request_cnt) { - pj_gettimeofday(&next_send); - next_send.msec += request_interval_msec; - pj_time_val_normalize(&next_send); - } - } - - if (now.sec > timeout.sec) { - if (!expecting_timeout) - PJ_LOG(3,(THIS_FILE, " Error: test has timed out")); - pjsip_tx_data_dec_ref(tdata); - return TEST_TIMEOUT_ERROR; - } - } - - if (test_complete < 0) { - pjsip_transaction *tsx; - - tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); - if (tsx) { - pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); - pj_mutex_unlock(tsx->mutex); - flush_events(1000); - } - pjsip_tx_data_dec_ref(tdata); - return test_complete; - } - - /* Allow transaction to destroy itself */ - flush_events(500); - - /* Make sure transaction has been destroyed. */ - if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) { - PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed")); - pjsip_tx_data_dec_ref(tdata); - return -40; - } - - /* Check tdata reference counter. */ - if (pj_atomic_get(tdata->ref_cnt) != 1) { - PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %d", - pj_atomic_get(tdata->ref_cnt))); - pjsip_tx_data_dec_ref(tdata); - return -50; - } - - /* Destroy txdata */ - pjsip_tx_data_dec_ref(tdata); - - return PJ_SUCCESS; - -} - - -/***************************************************************************** - ** - ** TEST1_BRANCH_ID: Basic 2xx final response - ** TEST2_BRANCH_ID: Basic non-2xx final response - ** - ***************************************************************************** - */ -static int tsx_basic_final_response_test(void) -{ - unsigned duration; - int status; - - PJ_LOG(3,(THIS_FILE," test1: basic sending 2xx final response")); - - /* Test duration must be greater than 32 secs if unreliable transport - * is used. - */ - duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; - - status = perform_test(TARGET_URI, FROM_URI, TEST1_BRANCH_ID, - duration, &pjsip_options_method, 1, 0, 0); - if (status != 0) - return status; - - PJ_LOG(3,(THIS_FILE," test2: basic sending non-2xx final response")); - - status = perform_test(TARGET_URI, FROM_URI, TEST2_BRANCH_ID, - duration, &pjsip_options_method, 1, 0, 0); - if (status != 0) - return status; - - return 0; -} - - -/***************************************************************************** - ** - ** TEST3_BRANCH_ID: Sending provisional response - ** - ***************************************************************************** - */ -static int tsx_basic_provisional_response_test(void) -{ - unsigned duration; - int status; - - PJ_LOG(3,(THIS_FILE," test3: basic sending 2xx final response")); - - duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; - duration += 2; - - status = perform_test(TARGET_URI, FROM_URI, TEST3_BRANCH_ID, duration, - &pjsip_options_method, 1, 0, 0); - - return status; -} - - -/***************************************************************************** - ** - ** TEST4_BRANCH_ID: Absorbs retransmissions in TRYING state - ** TEST5_BRANCH_ID: Absorbs retransmissions in PROCEEDING state - ** TEST6_BRANCH_ID: Absorbs retransmissions in COMPLETED state - ** - ***************************************************************************** - */ -static int tsx_retransmit_last_response_test(const char *title, - char *branch_id, - int request_cnt, - int status_code) -{ - int status; - - PJ_LOG(3,(THIS_FILE," %s", title)); - - status = perform_test(TARGET_URI, FROM_URI, branch_id, 5, - &pjsip_options_method, - request_cnt, 1000, 1); - if (status && status != TEST_TIMEOUT_ERROR) - return status; - if (!status) { - PJ_LOG(3,(THIS_FILE, " error: expecting timeout")); - return -31; - } - - terminate_our_tsx(status_code); - flush_events(100); - - if (test_complete != 1) - return test_complete; - - flush_events(100); - return 0; -} - -/***************************************************************************** - ** - ** TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test - ** TEST8_BRANCH_ID: INVITE 2xx final response retransmission test - ** - ***************************************************************************** - */ -static int tsx_final_response_retransmission_test(void) -{ - int status; - - PJ_LOG(3,(THIS_FILE, - " test7: INVITE non-2xx final response retransmission")); - - status = perform_test(TARGET_URI, FROM_URI, TEST7_BRANCH_ID, - 33, /* Test duration must be greater than 32 secs */ - &pjsip_invite_method, 1, 0, 0); - if (status != 0) - return status; - - PJ_LOG(3,(THIS_FILE, - " test8: INVITE 2xx final response retransmission")); - - status = perform_test(TARGET_URI, FROM_URI, TEST8_BRANCH_ID, - 33, /* Test duration must be greater than 32 secs */ - &pjsip_invite_method, 1, 0, 0); - if (status != 0) - return status; - - return 0; -} - - -/***************************************************************************** - ** - ** TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must - ** cease when ACK is received - ** - ***************************************************************************** - */ -static int tsx_ack_test(void) -{ - int status; - - PJ_LOG(3,(THIS_FILE, - " test9: receiving ACK for non-2xx final response")); - - status = perform_test(TARGET_URI, FROM_URI, TEST9_BRANCH_ID, - 20, /* allow 5 retransmissions */ - &pjsip_invite_method, 1, 0, 0); - if (status != 0) - return status; - - - return 0; -} - - - -/***************************************************************************** - ** - ** TEST10_BRANCH_ID: test transport failure in TRYING state. - ** TEST11_BRANCH_ID: test transport failure in PROCEEDING state. - ** TEST12_BRANCH_ID: test transport failure in CONNECTED state. - ** TEST13_BRANCH_ID: test transport failure in CONFIRMED state. - ** - ***************************************************************************** - */ -static int tsx_transport_failure_test(void) -{ - struct test_desc - { - int transport_delay; - int fail_delay; - char *branch_id; - char *title; - } tests[] = - { - { 0, 10, TEST10_BRANCH_ID, "test10: failed transport in TRYING state (no delay)" }, - { 50, 10, TEST10_BRANCH_ID, "test10: failed transport in TRYING state (50 ms delay)" }, - { 0, 1500, TEST11_BRANCH_ID, "test11: failed transport in PROCEEDING state (no delay)" }, - { 50, 1500, TEST11_BRANCH_ID, "test11: failed transport in PROCEEDING state (50 ms delay)" }, - { 0, 2500, TEST12_BRANCH_ID, "test12: failed transport in COMPLETED state (no delay)" }, - { 50, 2500, TEST12_BRANCH_ID, "test12: failed transport in COMPLETED state (50 ms delay)" }, - }; - int i, status; - - for (i=0; i<(int)PJ_ARRAY_SIZE(tests); ++i) { - pj_time_val fail_time, end_test, now; - - PJ_LOG(3,(THIS_FILE, " %s", tests[i].title)); - pjsip_loop_set_failure(loop, 0, NULL); - pjsip_loop_set_delay(loop, tests[i].transport_delay); - - status = perform_test(TARGET_URI, FROM_URI, tests[i].branch_id, - 0, &pjsip_invite_method, 1, 0, 1); - if (status && status != TEST_TIMEOUT_ERROR) - return status; - if (!status) { - PJ_LOG(3,(THIS_FILE, " error: expecting timeout")); - return -40; - } - - pj_gettimeofday(&fail_time); - fail_time.msec += tests[i].fail_delay; - pj_time_val_normalize(&fail_time); - - do { - pj_time_val interval = { 0, 1 }; - pj_gettimeofday(&now); - pjsip_endpt_handle_events(endpt, &interval); - } while (PJ_TIME_VAL_LT(now, fail_time)); - - pjsip_loop_set_failure(loop, 1, NULL); - - end_test = now; - end_test.sec += 5; - - do { - pj_time_val interval = { 0, 1 }; - pj_gettimeofday(&now); - pjsip_endpt_handle_events(endpt, &interval); - } while (!test_complete && PJ_TIME_VAL_LT(now, end_test)); - - if (test_complete == 0) { - PJ_LOG(3,(THIS_FILE, " error: test has timed out")); - return -41; - } - - if (test_complete != 1) - return test_complete; - } - - return 0; -} - -/***************************************************************************** - ** - ** UAS Transaction Test. - ** - ***************************************************************************** - */ -int tsx_uas_test(struct tsx_test_param *param) -{ - pj_sockaddr_in addr; - pj_status_t status; - - test_param = param; - tp_flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)param->type); - - pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", - param->port, param->tp_type); - pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", - param->port, param->tp_type); - - /* Check if loop transport is configured. */ - status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, - &addr, sizeof(addr), NULL, &loop); - if (status != PJ_SUCCESS) { - PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!")); - return -10; - } - /* Register modules. */ - status = pjsip_endpt_register_module(endpt, &tsx_user); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to register module", status); - return -3; - } - status = pjsip_endpt_register_module(endpt, &msg_sender); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to register module", status); - return -4; - } - - /* TEST1_BRANCH_ID: Basic 2xx final response. - * TEST2_BRANCH_ID: Basic non-2xx final response. - */ - status = tsx_basic_final_response_test(); - if (status != 0) - return status; - - /* TEST3_BRANCH_ID: with provisional response - */ - status = tsx_basic_provisional_response_test(); - if (status != 0) - return status; - - /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state - */ - status = tsx_retransmit_last_response_test(TEST4_TITLE, - TEST4_BRANCH_ID, - TEST4_REQUEST_COUNT, - TEST4_STATUS_CODE); - if (status != 0) - return status; - - /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state - */ - status = tsx_retransmit_last_response_test(TEST5_TITLE, - TEST5_BRANCH_ID, - TEST5_REQUEST_COUNT, - TEST5_STATUS_CODE); - if (status != 0) - return status; - - /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state - * This only applies to non-reliable transports, - * since UAS transaction is destroyed as soon - * as final response is sent for reliable transports. - */ - if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { - status = tsx_retransmit_last_response_test(TEST6_TITLE, - TEST6_BRANCH_ID, - TEST6_REQUEST_COUNT, - TEST6_STATUS_CODE); - if (status != 0) - return status; - } - - /* TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test - * TEST8_BRANCH_ID: INVITE 2xx final response retransmission test - */ - status = tsx_final_response_retransmission_test(); - if (status != 0) - return status; - - /* TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must - * cease when ACK is received - * Only applicable for non-reliable transports. - */ - if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { - status = tsx_ack_test(); - if (status != 0) - return status; - } - - - /* TEST10_BRANCH_ID: test transport failure in TRYING state. - * TEST11_BRANCH_ID: test transport failure in PROCEEDING state. - * TEST12_BRANCH_ID: test transport failure in CONNECTED state. - * TEST13_BRANCH_ID: test transport failure in CONFIRMED state. - */ - /* Only valid for loop-dgram */ - if (param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { - status = tsx_transport_failure_test(); - if (status != 0) - return status; - } - - - /* Register modules. */ - status = pjsip_endpt_unregister_module(endpt, &tsx_user); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to unregister module", status); - return -8; - } - status = pjsip_endpt_unregister_module(endpt, &msg_sender); - if (status != PJ_SUCCESS) { - app_perror(" Error: unable to unregister module", status); - return -9; - } - - - if (loop) - pjsip_transport_dec_ref(loop); - - return 0; -} - diff --git a/pjsip/src/test-pjsip/txdata_test.c b/pjsip/src/test-pjsip/txdata_test.c deleted file mode 100644 index 9ced25e3..00000000 --- a/pjsip/src/test-pjsip/txdata_test.c +++ /dev/null @@ -1,847 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ - -#include "test.h" -#include -#include - - -#define THIS_FILE "txdata_test.c" - - -#define HFIND(msg,h,H) ((pjsip_##h##_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_##H, NULL)) - -#if defined(PJ_DEBUG) && PJ_DEBUG!=0 -# define LOOP 10000 -#else -# define LOOP 100000 -#endif - - -/* - * This tests various core message creation functions. - */ -static int core_txdata_test(void) -{ - pj_status_t status; - pj_str_t target, from, to, contact, body; - pjsip_rx_data dummy_rdata; - pjsip_tx_data *invite, *invite2, *cancel, *response, *ack; - - PJ_LOG(3,(THIS_FILE, " core transmit data test")); - - /* Create INVITE request. */ - target = pj_str("tel:+1"); - from = pj_str("tel:+0"); - to = pj_str("tel:+1"); - contact = pj_str("Bob "); - body = pj_str("Hello world!"); - - status = pjsip_endpt_create_request( endpt, &pjsip_invite_method, &target, - &from, &to, &contact, NULL, 10, &body, - &invite); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create request", status); - return -10; - } - - /* Buffer must be invalid. */ - if (pjsip_tx_data_is_valid(invite) != 0) { - PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); - return -14; - } - /* Reference counter must be set to 1. */ - if (pj_atomic_get(invite->ref_cnt) != 1) { - PJ_LOG(3,(THIS_FILE, " error: invalid reference counter")); - return -15; - } - /* Check message type. */ - if (invite->msg->type != PJSIP_REQUEST_MSG) - return -16; - /* Check method. */ - if (invite->msg->line.req.method.id != PJSIP_INVITE_METHOD) - return -17; - - /* Check that mandatory headers are present. */ - if (HFIND(invite->msg, from, FROM) == 0) - return -20; - if (HFIND(invite->msg, to, TO) == 0) - return -21; - if (HFIND(invite->msg, contact, CONTACT) == 0) - return -22; - if (HFIND(invite->msg, cid, CALL_ID) == 0) - return -23; - if (HFIND(invite->msg, cseq, CSEQ) == 0) - return -24; - do { - pjsip_via_hdr *via = HFIND(invite->msg, via, VIA); - if (via == NULL) - return -25; - /* Branch param must be empty. */ - if (via->branch_param.slen != 0) - return -26; - } while (0); - if (invite->msg->body == NULL) - return -28; - - /* Create another INVITE request from first request. */ - status = pjsip_endpt_create_request_from_hdr( endpt, &pjsip_invite_method, - invite->msg->line.req.uri, - HFIND(invite->msg,from,FROM), - HFIND(invite->msg,to,TO), - HFIND(invite->msg,contact,CONTACT), - HFIND(invite->msg,cid,CALL_ID), - 10, &body, &invite2); - if (status != PJ_SUCCESS) { - app_perror(" error: create second request failed", status); - return -30; - } - - /* Buffer must be invalid. */ - if (pjsip_tx_data_is_valid(invite2) != 0) { - PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); - return -34; - } - /* Reference counter must be set to 1. */ - if (pj_atomic_get(invite2->ref_cnt) != 1) { - PJ_LOG(3,(THIS_FILE, " error: invalid reference counter")); - return -35; - } - /* Check message type. */ - if (invite2->msg->type != PJSIP_REQUEST_MSG) - return -36; - /* Check method. */ - if (invite2->msg->line.req.method.id != PJSIP_INVITE_METHOD) - return -37; - - /* Check that mandatory headers are again present. */ - if (HFIND(invite2->msg, from, FROM) == 0) - return -40; - if (HFIND(invite2->msg, to, TO) == 0) - return -41; - if (HFIND(invite2->msg, contact, CONTACT) == 0) - return -42; - if (HFIND(invite2->msg, cid, CALL_ID) == 0) - return -43; - if (HFIND(invite2->msg, cseq, CSEQ) == 0) - return -44; - if (HFIND(invite2->msg, via, VIA) == 0) - return -45; - /* - if (HFIND(invite2->msg, ctype, CONTENT_TYPE) == 0) - return -46; - if (HFIND(invite2->msg, clen, CONTENT_LENGTH) == 0) - return -47; - */ - if (invite2->msg->body == NULL) - return -48; - - /* Done checking invite2. We can delete this. */ - if (pjsip_tx_data_dec_ref(invite2) != PJSIP_EBUFDESTROYED) { - PJ_LOG(3,(THIS_FILE, " error: request buffer not destroyed!")); - return -49; - } - - /* Initialize dummy rdata (to simulate receiving a request) - * We should never do this in real application, as there are many - * many more fields need to be initialized!! - */ - dummy_rdata.msg_info.cid = HFIND(invite->msg, cid, CALL_ID); - dummy_rdata.msg_info.clen = NULL; - dummy_rdata.msg_info.cseq = HFIND(invite->msg, cseq, CSEQ); - dummy_rdata.msg_info.ctype = NULL; - dummy_rdata.msg_info.from = HFIND(invite->msg, from, FROM); - dummy_rdata.msg_info.max_fwd = NULL; - dummy_rdata.msg_info.msg = invite->msg; - dummy_rdata.msg_info.record_route = NULL; - dummy_rdata.msg_info.require = NULL; - dummy_rdata.msg_info.route = NULL; - dummy_rdata.msg_info.to = HFIND(invite->msg, to, TO); - dummy_rdata.msg_info.via = HFIND(invite->msg, via, VIA); - - /* Create a response message for the request. */ - status = pjsip_endpt_create_response( endpt, &dummy_rdata, 301, NULL, - &response); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create response", status); - return -50; - } - - /* Buffer must be invalid. */ - if (pjsip_tx_data_is_valid(response) != 0) { - PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); - return -54; - } - /* Check reference counter. */ - if (pj_atomic_get(response->ref_cnt) != 1) { - PJ_LOG(3,(THIS_FILE, " error: invalid ref count in response")); - return -55; - } - /* Check message type. */ - if (response->msg->type != PJSIP_RESPONSE_MSG) - return -56; - /* Check correct status is set. */ - if (response->msg->line.status.code != 301) - return -57; - - /* Check that mandatory headers are again present. */ - if (HFIND(response->msg, from, FROM) == 0) - return -60; - if (HFIND(response->msg, to, TO) == 0) - return -61; - /* - if (HFIND(response->msg, contact, CONTACT) == 0) - return -62; - */ - if (HFIND(response->msg, cid, CALL_ID) == 0) - return -63; - if (HFIND(response->msg, cseq, CSEQ) == 0) - return -64; - if (HFIND(response->msg, via, VIA) == 0) - return -65; - - /* This response message will be used later when creating ACK */ - - /* Create CANCEL request for the original request. */ - status = pjsip_endpt_create_cancel( endpt, invite, &cancel); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create CANCEL request", status); - return -80; - } - - /* Buffer must be invalid. */ - if (pjsip_tx_data_is_valid(cancel) != 0) { - PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); - return -84; - } - /* Check reference counter. */ - if (pj_atomic_get(cancel->ref_cnt) != 1) { - PJ_LOG(3,(THIS_FILE, " error: invalid ref count in CANCEL request")); - return -85; - } - /* Check message type. */ - if (cancel->msg->type != PJSIP_REQUEST_MSG) - return -86; - /* Check method. */ - if (cancel->msg->line.req.method.id != PJSIP_CANCEL_METHOD) - return -87; - - /* Check that mandatory headers are again present. */ - if (HFIND(cancel->msg, from, FROM) == 0) - return -90; - if (HFIND(cancel->msg, to, TO) == 0) - return -91; - /* - if (HFIND(cancel->msg, contact, CONTACT) == 0) - return -92; - */ - if (HFIND(cancel->msg, cid, CALL_ID) == 0) - return -93; - if (HFIND(cancel->msg, cseq, CSEQ) == 0) - return -94; - if (HFIND(cancel->msg, via, VIA) == 0) - return -95; - - /* Done checking CANCEL request. */ - if (pjsip_tx_data_dec_ref(cancel) != PJSIP_EBUFDESTROYED) { - PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); - return -99; - } - - /* Modify dummy_rdata to simulate receiving response. */ - pj_bzero(&dummy_rdata, sizeof(dummy_rdata)); - dummy_rdata.msg_info.msg = response->msg; - dummy_rdata.msg_info.to = HFIND(response->msg, to, TO); - - /* Create ACK request */ - status = pjsip_endpt_create_ack( endpt, invite, &dummy_rdata, &ack ); - if (status != PJ_SUCCESS) { - PJ_LOG(3,(THIS_FILE, " error: unable to create ACK")); - return -100; - } - /* Buffer must be invalid. */ - if (pjsip_tx_data_is_valid(ack) != 0) { - PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); - return -104; - } - /* Check reference counter. */ - if (pj_atomic_get(ack->ref_cnt) != 1) { - PJ_LOG(3,(THIS_FILE, " error: invalid ref count in ACK request")); - return -105; - } - /* Check message type. */ - if (ack->msg->type != PJSIP_REQUEST_MSG) - return -106; - /* Check method. */ - if (ack->msg->line.req.method.id != PJSIP_ACK_METHOD) - return -107; - /* Check Request-URI is present. */ - if (ack->msg->line.req.uri == NULL) - return -108; - - /* Check that mandatory headers are again present. */ - if (HFIND(ack->msg, from, FROM) == 0) - return -110; - if (HFIND(ack->msg, to, TO) == 0) - return -111; - if (HFIND(ack->msg, cid, CALL_ID) == 0) - return -112; - if (HFIND(ack->msg, cseq, CSEQ) == 0) - return -113; - if (HFIND(ack->msg, via, VIA) == 0) - return -114; - if (ack->msg->body != NULL) - return -115; - - /* Done checking invite message. */ - if (pjsip_tx_data_dec_ref(invite) != PJSIP_EBUFDESTROYED) { - PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); - return -120; - } - - /* Done checking response message. */ - if (pjsip_tx_data_dec_ref(response) != PJSIP_EBUFDESTROYED) { - PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); - return -130; - } - - /* Done checking ack message. */ - if (pjsip_tx_data_dec_ref(ack) != PJSIP_EBUFDESTROYED) { - PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); - return -140; - } - - /* Done. */ - return 0; -} - - - -/* - * This test demonstrate the bug as reported in: - * http://bugzilla.pjproject.net/show_bug.cgi?id=49 - */ -#if INCLUDE_GCC_TEST -static int gcc_test() -{ - char msgbuf[512]; - pj_str_t target = pj_str("sip:alice@wonderland:5061;x-param=param%201" - "?X-Hdr-1=Header%201" - "&X-Empty-Hdr="); - pjsip_tx_data *tdata; - pjsip_parser_err_report err_list; - pjsip_msg *msg; - int len; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, " header param in URI to create request")); - - /* Create request with header param in target URI. */ - status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, - &target, &target, &target, NULL, -1, - NULL, &tdata); - if (status != 0) { - app_perror(" error: Unable to create request", status); - return -200; - } - - /* Print and parse the request. - * We'll check that header params are not present in - */ - len = pjsip_msg_print(tdata->msg, msgbuf, sizeof(msgbuf)); - if (len < 1) { - PJ_LOG(3,(THIS_FILE, " error: printing message")); - pjsip_tx_data_dec_ref(tdata); - return -250; - } - msgbuf[len] = '\0'; - - PJ_LOG(5,(THIS_FILE, "%d bytes request created:--begin-msg--\n" - "%s\n" - "--end-msg--", len, msgbuf)); - - /* Now parse the message. */ - pj_list_init(&err_list); - msg = pjsip_parse_msg( tdata->pool, msgbuf, len, &err_list); - if (msg == NULL) { - pjsip_parser_err_report *e; - - PJ_LOG(3,(THIS_FILE, " error: parsing message message")); - - e = err_list.next; - while (e != &err_list) { - PJ_LOG(3,(THIS_FILE, " %s in line %d col %d hname=%.*s", - pj_exception_id_name(e->except_code), - e->line, e->col+1, - (int)e->hname.slen, - e->hname.ptr)); - e = e->next; - } - - pjsip_tx_data_dec_ref(tdata); - return -255; - } - - pjsip_tx_data_dec_ref(tdata); - return 0; -} -#endif - - -/* This tests the request creating functions against the following - * requirements: - * - header params in URI creates header in the request. - * - method and headers params are correctly shown or hidden in - * request URI, From, To, and Contact header. - */ -static int txdata_test_uri_params(void) -{ - char msgbuf[512]; - pj_str_t target = pj_str("sip:alice@wonderland:5061;x-param=param%201" - "?X-Hdr-1=Header%201" - "&X-Empty-Hdr="); - pj_str_t pname = pj_str("x-param"); - pj_str_t hname = pj_str("X-Hdr-1"); - pj_str_t hemptyname = pj_str("X-Empty-Hdr"); - pjsip_from_hdr *from_hdr; - pjsip_to_hdr *to_hdr; - pjsip_contact_hdr *contact_hdr; - pjsip_generic_string_hdr *hdr; - pjsip_tx_data *tdata; - pjsip_sip_uri *uri; - pjsip_param *param; - pjsip_via_hdr *via; - pjsip_parser_err_report err_list; - pjsip_msg *msg; - int len; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, " header param in URI to create request")); - - /* Create request with header param in target URI. */ - status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, - &target, &target, &target, NULL, -1, - NULL, &tdata); - if (status != 0) { - app_perror(" error: Unable to create request", status); - return -200; - } - - /* Fill up the Via header to prevent syntax error on parsing */ - via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); - via->transport = pj_str("TCP"); - via->sent_by.host = pj_str("127.0.0.1"); - - /* Print and parse the request. - * We'll check that header params are not present in - */ - len = pjsip_msg_print(tdata->msg, msgbuf, sizeof(msgbuf)); - if (len < 1) { - PJ_LOG(3,(THIS_FILE, " error: printing message")); - pjsip_tx_data_dec_ref(tdata); - return -250; - } - msgbuf[len] = '\0'; - - PJ_LOG(5,(THIS_FILE, "%d bytes request created:--begin-msg--\n" - "%s\n" - "--end-msg--", len, msgbuf)); - - /* Now parse the message. */ - pj_list_init(&err_list); - msg = pjsip_parse_msg( tdata->pool, msgbuf, len, &err_list); - if (msg == NULL) { - pjsip_parser_err_report *e; - - PJ_LOG(3,(THIS_FILE, " error: parsing message message")); - - e = err_list.next; - while (e != &err_list) { - PJ_LOG(3,(THIS_FILE, " %s in line %d col %d hname=%.*s", - pj_exception_id_name(e->except_code), - e->line, e->col+1, - (int)e->hname.slen, - e->hname.ptr)); - e = e->next; - } - - pjsip_tx_data_dec_ref(tdata); - return -256; - } - - /* Check the existence of port, other_param, and header param. - * Port is now allowed in To and From header. - */ - /* Port in request URI. */ - uri = (pjsip_sip_uri*) pjsip_uri_get_uri(msg->line.req.uri); - if (uri->port != 5061) { - PJ_LOG(3,(THIS_FILE, " error: port not present in request URI")); - pjsip_tx_data_dec_ref(tdata); - return -260; - } - /* other_param in request_uri */ - param = pjsip_param_find(&uri->other_param, &pname); - if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { - PJ_LOG(3,(THIS_FILE, " error: x-param not present in request URI")); - pjsip_tx_data_dec_ref(tdata); - return -261; - } - /* header param in request uri. */ - if (!pj_list_empty(&uri->header_param)) { - PJ_LOG(3,(THIS_FILE, " error: hparam in request URI")); - pjsip_tx_data_dec_ref(tdata); - return -262; - } - - /* Port in From header. */ - from_hdr = (pjsip_from_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL); - uri = (pjsip_sip_uri*) pjsip_uri_get_uri(from_hdr->uri); - if (uri->port != 0) { - PJ_LOG(3,(THIS_FILE, " error: port most not exist in From header")); - pjsip_tx_data_dec_ref(tdata); - return -270; - } - /* other_param in From header */ - param = pjsip_param_find(&uri->other_param, &pname); - if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { - PJ_LOG(3,(THIS_FILE, " error: x-param not present in From header")); - pjsip_tx_data_dec_ref(tdata); - return -271; - } - /* header param in From header. */ - if (!pj_list_empty(&uri->header_param)) { - PJ_LOG(3,(THIS_FILE, " error: hparam in From header")); - pjsip_tx_data_dec_ref(tdata); - return -272; - } - - - /* Port in To header. */ - to_hdr = (pjsip_to_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL); - uri = (pjsip_sip_uri*) pjsip_uri_get_uri(to_hdr->uri); - if (uri->port != 0) { - PJ_LOG(3,(THIS_FILE, " error: port most not exist in To header")); - pjsip_tx_data_dec_ref(tdata); - return -280; - } - /* other_param in To header */ - param = pjsip_param_find(&uri->other_param, &pname); - if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { - PJ_LOG(3,(THIS_FILE, " error: x-param not present in To header")); - pjsip_tx_data_dec_ref(tdata); - return -281; - } - /* header param in From header. */ - if (!pj_list_empty(&uri->header_param)) { - PJ_LOG(3,(THIS_FILE, " error: hparam in To header")); - pjsip_tx_data_dec_ref(tdata); - return -282; - } - - - - /* Port in Contact header. */ - contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL); - uri = (pjsip_sip_uri*) pjsip_uri_get_uri(contact_hdr->uri); - if (uri->port != 5061) { - PJ_LOG(3,(THIS_FILE, " error: port not present in Contact header")); - pjsip_tx_data_dec_ref(tdata); - return -290; - } - /* other_param in Contact header */ - param = pjsip_param_find(&uri->other_param, &pname); - if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { - PJ_LOG(3,(THIS_FILE, " error: x-param not present in Contact header")); - pjsip_tx_data_dec_ref(tdata); - return -291; - } - /* header param in Contact header. */ - if (pj_list_empty(&uri->header_param)) { - PJ_LOG(3,(THIS_FILE, " error: hparam is missing in Contact header")); - pjsip_tx_data_dec_ref(tdata); - return -292; - } - /* Check for X-Hdr-1 */ - param = pjsip_param_find(&uri->header_param, &hname); - if (param == NULL || pj_strcmp2(¶m->value, "Header 1")!=0) { - PJ_LOG(3,(THIS_FILE, " error: hparam is missing in Contact header")); - pjsip_tx_data_dec_ref(tdata); - return -293; - } - /* Check for X-Empty-Hdr */ - param = pjsip_param_find(&uri->header_param, &hemptyname); - if (param == NULL || pj_strcmp2(¶m->value, "")!=0) { - PJ_LOG(3,(THIS_FILE, " error: hparam is missing in Contact header")); - pjsip_tx_data_dec_ref(tdata); - return -294; - } - - - /* Check that headers are present in the request. */ - hdr = (pjsip_generic_string_hdr*) - pjsip_msg_find_hdr_by_name(msg, &hname, NULL); - if (hdr == NULL || pj_strcmp2(&hdr->hvalue, "Header 1")!=0) { - PJ_LOG(3,(THIS_FILE, " error: header X-Hdr-1 not created")); - pjsip_tx_data_dec_ref(tdata); - return -300; - } - - hdr = (pjsip_generic_string_hdr*) - pjsip_msg_find_hdr_by_name(msg, &hemptyname, NULL); - if (hdr == NULL || pj_strcmp2(¶m->value, "")!=0) { - PJ_LOG(3,(THIS_FILE, " error: header X-Empty-Hdr not created")); - pjsip_tx_data_dec_ref(tdata); - return -330; - } - - pjsip_tx_data_dec_ref(tdata); - return 0; -} - - -/* - * create request benchmark - */ -static int create_request_bench(pj_timestamp *p_elapsed) -{ - enum { COUNT = 100 }; - unsigned i, j; - pjsip_tx_data *tdata[COUNT]; - pj_timestamp t1, t2, elapsed; - pj_status_t status; - - pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); - pj_str_t str_from = pj_str("\"Local User\" "); - pj_str_t str_to = pj_str("\"Remote User\" "); - pj_str_t str_contact = str_from; - - elapsed.u64 = 0; - - for (i=0; iu64 = elapsed.u64; - return PJ_SUCCESS; - -on_error: - for (i=0; i"); - pj_str_t str_to = pj_str("\"Remote User\" "); - pj_str_t str_contact = str_from; - - status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, - &str_target, &str_from, &str_to, - &str_contact, NULL, -1, NULL, - &request); - if (status != PJ_SUCCESS) { - app_perror(" error: unable to create request", status); - return status; - } - - /* Create several Via headers */ - via = pjsip_via_hdr_create(request->pool); - via->sent_by.host = pj_str("192.168.0.7"); - via->sent_by.port = 5061; - via->transport = pj_str("udp"); - via->rport_param = 0; - via->branch_param = pj_str("012345678901234567890123456789"); - via->recvd_param = pj_str("192.168.0.7"); - pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*) pjsip_hdr_clone(request->pool, via)); - pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*) pjsip_hdr_clone(request->pool, via)); - pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); - - - /* Create "dummy" rdata from the tdata */ - pj_bzero(&rdata, sizeof(pjsip_rx_data)); - rdata.tp_info.pool = request->pool; - rdata.msg_info.msg = request->msg; - rdata.msg_info.from = (pjsip_from_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); - rdata.msg_info.to = (pjsip_to_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); - rdata.msg_info.cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); - rdata.msg_info.cid = (pjsip_cid_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); - rdata.msg_info.via = via; - - /* - * Now benchmark create_response - */ - elapsed.u64 = 0; - - for (i=0; iu64 = elapsed.u64; - pjsip_tx_data_dec_ref(request); - return PJ_SUCCESS; - -on_error: - for (i=0; ipjsip_endpt_create_request()"); - - - /* - * Benchmark create_response() - */ - PJ_LOG(3,(THIS_FILE, " benchmarking response creation:")); - for (i=0; ipjsip_endpt_create_response()"); - - - return 0; -} - diff --git a/pjsip/src/test-pjsip/uri_test.c b/pjsip/src/test-pjsip/uri_test.c deleted file mode 100644 index d51c6fe5..00000000 --- a/pjsip/src/test-pjsip/uri_test.c +++ /dev/null @@ -1,1091 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono - * - * 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 - */ -#include "test.h" -#include -#include - -#define THIS_FILE "uri_test.c" - - -#define ALPHANUM "abcdefghijklmnopqrstuvwxyz" \ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ - "0123456789" -#define MARK "-_.!~*'()" -#define USER_CHAR ALPHANUM MARK "&=+$,;?/" -#define PASS_CHAR ALPHANUM MARK "&=+$," -#define PARAM_CHAR ALPHANUM MARK "[]/:&+$" - -#define POOL_SIZE 8000 -#if defined(PJ_DEBUG) && PJ_DEBUG!=0 -# define LOOP_COUNT 10000 -#else -# define LOOP_COUNT 40000 -#endif -#define AVERAGE_URL_LEN 80 -#define THREAD_COUNT 4 - -static struct -{ - pj_highprec_t parse_len, print_len, cmp_len; - pj_timestamp parse_time, print_time, cmp_time; -} var; - - -/* URI creator functions. */ -static pjsip_uri *create_uri0( pj_pool_t *pool ); -static pjsip_uri *create_uri1( pj_pool_t *pool ); -static pjsip_uri *create_uri2( pj_pool_t *pool ); -static pjsip_uri *create_uri3( pj_pool_t *pool ); -static pjsip_uri *create_uri4( pj_pool_t *pool ); -static pjsip_uri *create_uri5( pj_pool_t *pool ); -static pjsip_uri *create_uri6( pj_pool_t *pool ); -static pjsip_uri *create_uri7( pj_pool_t *pool ); -static pjsip_uri *create_uri8( pj_pool_t *pool ); -static pjsip_uri *create_uri9( pj_pool_t *pool ); -static pjsip_uri *create_uri10( pj_pool_t *pool ); -static pjsip_uri *create_uri11( pj_pool_t *pool ); -static pjsip_uri *create_uri12( pj_pool_t *pool ); -static pjsip_uri *create_uri13( pj_pool_t *pool ); -static pjsip_uri *create_uri14( pj_pool_t *pool ); -static pjsip_uri *create_uri15( pj_pool_t *pool ); -static pjsip_uri *create_uri16( pj_pool_t *pool ); -static pjsip_uri *create_uri17( pj_pool_t *pool ); -static pjsip_uri *create_uri25( pj_pool_t *pool ); -static pjsip_uri *create_uri26( pj_pool_t *pool ); -static pjsip_uri *create_uri27( pj_pool_t *pool ); -static pjsip_uri *create_uri28( pj_pool_t *pool ); -static pjsip_uri *create_uri29( pj_pool_t *pool ); -static pjsip_uri *create_uri30( pj_pool_t *pool ); -static pjsip_uri *create_uri31( pj_pool_t *pool ); -static pjsip_uri *create_uri32( pj_pool_t *pool ); -static pjsip_uri *create_uri33( pj_pool_t *pool ); -static pjsip_uri *create_uri34( pj_pool_t *pool ); -static pjsip_uri *create_uri35( pj_pool_t *pool ); -static pjsip_uri *create_uri36( pj_pool_t *pool ); -static pjsip_uri *create_uri37( pj_pool_t *pool ); -static pjsip_uri *create_uri38( pj_pool_t *pool ); -static pjsip_uri *create_dummy( pj_pool_t *pool ); - -#define ERR_NOT_EQUAL -1001 -#define ERR_SYNTAX_ERR -1002 - -struct uri_test -{ - pj_status_t status; - char str[PJSIP_MAX_URL_SIZE]; - pjsip_uri *(*creator)(pj_pool_t *pool); - const char *printed; - pj_size_t len; -} uri_test_array[] = -{ - { - PJ_SUCCESS, - "sip:localhost", - &create_uri0 - }, - { - PJ_SUCCESS, - "sip:user@localhost", - &create_uri1 - }, - { - PJ_SUCCESS, - "sip:user:password@localhost:5060", - &create_uri2, }, - { - /* Port is specified should not match unspecified port. */ - ERR_NOT_EQUAL, - "sip:localhost:5060", - &create_uri3 - }, - { - /* All recognized parameters. */ - PJ_SUCCESS, - "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK", - &create_uri4 - }, - { - /* Params mixed with other params and header params. */ - PJ_SUCCESS, - "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry" - "?Subject=Hello%20There&Server=SIP%20Server", - &create_uri5 - }, - { - /* SIPS. */ - PJ_SUCCESS, - "sips:localhost", - &create_uri6, - }, - { - /* Name address */ - PJ_SUCCESS, - "", - &create_uri7 - }, - { - /* Name address with display name and SIPS scheme with some redundant - * whitespaced. - */ - PJ_SUCCESS, - " Power Administrator ", - &create_uri8 - }, - { - /* Name address. */ - PJ_SUCCESS, - " \"User\" ", - &create_uri9 - }, - { - /* Escaped sequence in display name (display=Strange User\"\\\"). */ - PJ_SUCCESS, - " \"Strange User\\\"\\\\\\\"\" ", - &create_uri10, - }, - { - /* Errorneous escaping in display name. */ - ERR_SYNTAX_ERR, - " \"Rogue User\\\" ", - &create_uri11, - }, - { - /* Dangling quote in display name, but that should be OK. */ - PJ_SUCCESS, - "Strange User\" ", - &create_uri12, - }, - { - /* Special characters in parameter value must be quoted. */ - PJ_SUCCESS, - "sip:localhost;pvalue=\"hello world\"", - &create_uri13, - }, - { - /* Excercise strange character sets allowed in display, user, password, - * host, and port. - */ - PJ_SUCCESS, - "This is -. !% *_+`'~ me ", - &create_uri14, - }, - { - /* Another excercise to the allowed character sets to the hostname. */ - PJ_SUCCESS, - "sip:" ALPHANUM "-_.com", - &create_uri15, - }, - { - /* Another excercise to the allowed character sets to the username - * and password. - */ - PJ_SUCCESS, - "sip:" USER_CHAR ":" PASS_CHAR "@host", - &create_uri16, - }, - { - /* Excercise to the pname and pvalue, and mixup of other-param - * between 'recognized' params. - */ - PJ_SUCCESS, - "sip:host;user=ip;" PARAM_CHAR "%21=" PARAM_CHAR "%21" - ";lr;other=1;transport=sctp;other2", - &create_uri17, - }, - { - /* 18: This should trigger syntax error. */ - ERR_SYNTAX_ERR, - "sip:", - &create_dummy, - }, - { - /* 19: Syntax error: whitespace after scheme. */ - ERR_SYNTAX_ERR, - "sip :host", - &create_dummy, - }, - { - /* 20: Syntax error: whitespace before hostname. */ - ERR_SYNTAX_ERR, - "sip: host", - &create_dummy, - }, - { - /* 21: Syntax error: invalid port. */ - ERR_SYNTAX_ERR, - "sip:user:password", - &create_dummy, - }, - { - /* 22: Syntax error: no host. */ - ERR_SYNTAX_ERR, - "sip:user@", - &create_dummy, - }, - { - /* 23: Syntax error: no user/host. */ - ERR_SYNTAX_ERR, - "sip:@", - &create_dummy, - }, - { - /* 24: Syntax error: empty string. */ - ERR_SYNTAX_ERR, - "", - &create_dummy, - }, - { - /* 25: Simple tel: URI with global context */ - PJ_SUCCESS, - "tel:+1-201-555-0123", - &create_uri25, - "tel:+1-201-555-0123" - }, - { - /* 26: Simple tel: URI with local context */ - PJ_SUCCESS, - "tel:7042;phone-context=example.com", - &create_uri26, - "tel:7042;phone-context=example.com" - }, - { - /* 27: Simple tel: URI with local context */ - PJ_SUCCESS, - "tel:863-1234;phone-context=+1-914-555", - &create_uri27, - "tel:863-1234;phone-context=+1-914-555" - }, - { - /* 28: Comparison between local and global number */ - ERR_NOT_EQUAL, - "tel:+1", - &create_uri28, - "tel:+1" - }, - { - /* 29: tel: with some visual chars and spaces */ - PJ_SUCCESS, - "tel:(44).1234-*#+Deaf", - &create_uri29, - "tel:(44).1234-*#+Deaf" - }, - { - /* 30: isub parameters */ - PJ_SUCCESS, - "tel:+1;isub=/:@&$,-_.!~*'()[]/:&$aA1%21+=", - &create_uri30, - "tel:+1;isub=/:@&$,-_.!~*'()[]/:&$aA1!+%3d" - }, - { - /* 31: extension number parsing and encoding */ - PJ_SUCCESS, - "tel:+1;ext=+123", - &create_uri31, - "tel:+1;ext=%2b123" - }, - { - /* 32: context parameter parsing and encoding */ - PJ_SUCCESS, - "tel:911;phone-context=+1-911", - &create_uri32, - "tel:911;phone-context=+1-911" - }, - { - /* 33: case-insensitive comparison */ - PJ_SUCCESS, - "tel:911;phone-context=emergency.example.com", - &create_uri33, - "tel:911;phone-context=emergency.example.com" - }, - { - /* 34: parameter only appears in one URL */ - ERR_NOT_EQUAL, - "tel:911;p1=p1;p2=p2", - &create_uri34, - "tel:911;p1=p1;p2=p2" - }, - { - /* 35: IPv6 in host and maddr parameter */ - PJ_SUCCESS, - "sip:user@[::1];maddr=[::01]", - &create_uri35, - "sip:user@[::1];maddr=[::01]" - }, - { - /* 36: IPv6 in host and maddr, without username */ - PJ_SUCCESS, - "sip:[::1];maddr=[::01]", - &create_uri36, - "sip:[::1];maddr=[::01]" - }, - { - /* 37: Non-ASCII UTF-8 in display name, with quote */ - PJ_SUCCESS, - "\"\xC0\x81\" ", - &create_uri37, - "\"\xC0\x81\" " - }, - { - /* 38: Non-ASCII UTF-8 in display name, without quote */ - PJ_SUCCESS, - "\xC0\x81 ", - &create_uri38, - "\"\xC0\x81\" " - } - -}; - -static pjsip_uri *create_uri0(pj_pool_t *pool) -{ - /* "sip:localhost" */ - pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); - - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri1(pj_pool_t *pool) -{ - /* "sip:user@localhost" */ - pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); - - pj_strdup2( pool, &url->user, "user"); - pj_strdup2( pool, &url->host, "localhost"); - - return (pjsip_uri*) url; -} - -static pjsip_uri *create_uri2(pj_pool_t *pool) -{ - /* "sip:user:password@localhost:5060" */ - pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); - - pj_strdup2( pool, &url->user, "user"); - pj_strdup2( pool, &url->passwd, "password"); - pj_strdup2( pool, &url->host, "localhost"); - url->port = 5060; - - return (pjsip_uri*) url; -} - -static pjsip_uri *create_uri3(pj_pool_t *pool) -{ - /* Like: "sip:localhost:5060", but without the port. */ - pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); - - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri4(pj_pool_t *pool) -{ - /* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */ - pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); - - pj_strdup2(pool, &url->host, "localhost"); - pj_strdup2(pool, &url->transport_param, "tcp"); - pj_strdup2(pool, &url->user_param, "ip"); - url->ttl_param = 255; - url->lr_param = 1; - pj_strdup2(pool, &url->maddr_param, "127.0.0.1"); - pj_strdup2(pool, &url->method_param, "ACK"); - - return (pjsip_uri*)url; -} - -#define param_add(list,pname,pvalue) \ - do { \ - pjsip_param *param; \ - param=PJ_POOL_ALLOC_T(pool, pjsip_param); \ - param->name = pj_str(pname); \ - param->value = pj_str(pvalue); \ - pj_list_insert_before(&list, param); \ - } while (0) - -static pjsip_uri *create_uri5(pj_pool_t *pool) -{ - /* "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry" - "?Subject=Hello%20There&Server=SIP%20Server" - */ - pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); - - pj_strdup2(pool, &url->host, "localhost"); - pj_strdup2(pool, &url->user_param, "phone"); - - //pj_strdup2(pool, &url->other_param, ";pickup=hurry;message=I%20am%20sorry"); - param_add(url->other_param, "pickup", "hurry"); - param_add(url->other_param, "message", "I am sorry"); - - //pj_strdup2(pool, &url->header_param, "?Subject=Hello%20There&Server=SIP%20Server"); - param_add(url->header_param, "Subject", "Hello There"); - param_add(url->header_param, "Server", "SIP Server"); - return (pjsip_uri*)url; - -} - -static pjsip_uri *create_uri6(pj_pool_t *pool) -{ - /* "sips:localhost" */ - pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 1); - - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri7(pj_pool_t *pool) -{ - /* "" */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_sip_uri *url; - - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri8(pj_pool_t *pool) -{ - /* " Power Administrator " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_sip_uri *url; - - url = pjsip_sip_uri_create(pool, 1); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "Power Administrator"); - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri9(pj_pool_t *pool) -{ - /* " \"User\" " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_sip_uri *url; - - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "User"); - pj_strdup2(pool, &url->user, "user"); - pj_strdup2(pool, &url->host, "localhost"); - url->port = 5071; - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri10(pj_pool_t *pool) -{ - /* " \"Strange User\\\"\\\\\\\"\" " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_sip_uri *url; - - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "Strange User\\\"\\\\\\\""); - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri11(pj_pool_t *pool) -{ - /* " \"Rogue User\\\" " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_sip_uri *url; - - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "Rogue User\\"); - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri12(pj_pool_t *pool) -{ - /* "Strange User\" " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_sip_uri *url; - - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "Strange User\""); - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri13(pj_pool_t *pool) -{ - /* "sip:localhost;pvalue=\"hello world\"" */ - pjsip_sip_uri *url; - url = pjsip_sip_uri_create(pool, 0); - pj_strdup2(pool, &url->host, "localhost"); - //pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\""); - param_add(url->other_param, "pvalue", "\"hello world\""); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri14(pj_pool_t *pool) -{ - /* "This is -. !% *_+`'~ me " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_sip_uri *url; - - url = pjsip_sip_uri_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "This is -. !% *_+`'~ me"); - pj_strdup2(pool, &url->user, "a19A&=+$,;?/,"); - pj_strdup2(pool, &url->passwd, "@a&Zz=+$,"); - pj_strdup2(pool, &url->host, "my_proxy09.MY-domain.com"); - url->port = 9801; - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri15(pj_pool_t *pool) -{ - /* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */ - pjsip_sip_uri *url; - url = pjsip_sip_uri_create(pool, 0); - pj_strdup2(pool, &url->host, ALPHANUM "-_.com"); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri16(pj_pool_t *pool) -{ - /* "sip:" USER_CHAR ":" PASS_CHAR "@host" */ - pjsip_sip_uri *url; - url = pjsip_sip_uri_create(pool, 0); - pj_strdup2(pool, &url->user, USER_CHAR); - pj_strdup2(pool, &url->passwd, PASS_CHAR); - pj_strdup2(pool, &url->host, "host"); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri17(pj_pool_t *pool) -{ - /* "sip:host;user=ip;" PARAM_CHAR "%21=" PARAM_CHAR "%21;lr;other=1;transport=sctp;other2" */ - pjsip_sip_uri *url; - url = pjsip_sip_uri_create(pool, 0); - pj_strdup2(pool, &url->host, "host"); - pj_strdup2(pool, &url->user_param, "ip"); - pj_strdup2(pool, &url->transport_param, "sctp"); - param_add(url->other_param, PARAM_CHAR "!", PARAM_CHAR "!"); - param_add(url->other_param, "other", "1"); - param_add(url->other_param, "other2", ""); - url->lr_param = 1; - return (pjsip_uri*)url; -} - - -static pjsip_uri *create_uri25(pj_pool_t *pool) -{ - /* "tel:+1-201-555-0123" */ - pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); - - uri->number = pj_str("+1-201-555-0123"); - return (pjsip_uri*)uri; -} - -static pjsip_uri *create_uri26(pj_pool_t *pool) -{ - /* tel:7042;phone-context=example.com */ - pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); - - uri->number = pj_str("7042"); - uri->context = pj_str("example.com"); - return (pjsip_uri*)uri; -} - -static pjsip_uri *create_uri27(pj_pool_t *pool) -{ - /* "tel:863-1234;phone-context=+1-914-555" */ - pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); - - uri->number = pj_str("863-1234"); - uri->context = pj_str("+1-914-555"); - return (pjsip_uri*)uri; -} - -/* "tel:1" */ -static pjsip_uri *create_uri28(pj_pool_t *pool) -{ - pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); - - uri->number = pj_str("1"); - return (pjsip_uri*)uri; -} - -/* "tel:(44).1234-*#+Deaf" */ -static pjsip_uri *create_uri29(pj_pool_t *pool) -{ - pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); - - uri->number = pj_str("(44).1234-*#+Deaf"); - return (pjsip_uri*)uri; -} - -/* "tel:+1;isub=/:@&$,-_.!~*'()[]/:&$aA1%21+=" */ -static pjsip_uri *create_uri30(pj_pool_t *pool) -{ - pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); - - uri->number = pj_str("+1"); - uri->isub_param = pj_str("/:@&$,-_.!~*'()[]/:&$aA1!+="); - return (pjsip_uri*)uri; -} - -/* "tel:+1;ext=+123" */ -static pjsip_uri *create_uri31(pj_pool_t *pool) -{ - pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); - - uri->number = pj_str("+1"); - uri->ext_param = pj_str("+123"); - return (pjsip_uri*)uri; -} - -/* "tel:911;phone-context=+1-911" */ -static pjsip_uri *create_uri32(pj_pool_t *pool) -{ - pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); - - uri->number = pj_str("911"); - uri->context = pj_str("+1-911"); - return (pjsip_uri*)uri; -} - -/* "tel:911;phone-context=emergency.example.com" */ -static pjsip_uri *create_uri33(pj_pool_t *pool) -{ - pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); - - uri->number = pj_str("911"); - uri->context = pj_str("EMERGENCY.EXAMPLE.COM"); - return (pjsip_uri*)uri; -} - -/* "tel:911;p1=p1;p2=p2" */ -static pjsip_uri *create_uri34(pj_pool_t *pool) -{ - pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); - pjsip_param *p; - - uri->number = pj_str("911"); - - p = PJ_POOL_ALLOC_T(pool, pjsip_param); - p->name = p->value = pj_str("p1"); - pj_list_insert_before(&uri->other_param, p); - - return (pjsip_uri*)uri; -} - -/* "sip:user@[::1];maddr=[::01]" */ -static pjsip_uri *create_uri35( pj_pool_t *pool ) -{ - pjsip_sip_uri *url; - url = pjsip_sip_uri_create(pool, 0); - url->user = pj_str("user"); - url->host = pj_str("::1"); - url->maddr_param = pj_str("::01"); - return (pjsip_uri*)url; -} - -/* "sip:[::1];maddr=[::01]" */ -static pjsip_uri *create_uri36( pj_pool_t *pool ) -{ - pjsip_sip_uri *url; - url = pjsip_sip_uri_create(pool, 0); - url->host = pj_str("::1"); - url->maddr_param = pj_str("::01"); - return (pjsip_uri*)url; - -} - -/* "\"\xC0\x81\" " */ -static pjsip_uri *create_uri37( pj_pool_t *pool ) -{ - pjsip_name_addr *name; - pjsip_sip_uri *url; - - name = pjsip_name_addr_create(pool); - name->display = pj_str("\xC0\x81"); - - url = pjsip_sip_uri_create(pool, 0); - url->host = pj_str("localhost"); - - name->uri = (pjsip_uri*)url; - - return (pjsip_uri*)name; - -} - -/* "\xC0\x81 " */ -static pjsip_uri *create_uri38( pj_pool_t *pool ) -{ - pjsip_name_addr *name; - pjsip_sip_uri *url; - - name = pjsip_name_addr_create(pool); - name->display = pj_str("\xC0\x81"); - - url = pjsip_sip_uri_create(pool, 0); - url->host = pj_str("localhost"); - - name->uri = (pjsip_uri*)url; - - return (pjsip_uri*)name; - -} - -static pjsip_uri *create_dummy(pj_pool_t *pool) -{ - PJ_UNUSED_ARG(pool); - return NULL; -} - -/*****************************************************************************/ - -/* - * Test one test entry. - */ -static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) -{ - pj_status_t status; - int len; - char *input; - pjsip_uri *parsed_uri, *ref_uri; - pj_str_t s1 = {NULL, 0}, s2 = {NULL, 0}; - pj_timestamp t1, t2; - - if (entry->len == 0) - entry->len = pj_ansi_strlen(entry->str); - -#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0 - input = pj_pool_alloc(pool, entry->len + 1); - pj_memcpy(input, entry->str, entry->len); - input[entry->len] = '\0'; -#else - input = entry->str; -#endif - - /* Parse URI text. */ - pj_get_timestamp(&t1); - var.parse_len = var.parse_len + entry->len; - parsed_uri = pjsip_parse_uri(pool, input, entry->len, 0); - if (!parsed_uri) { - /* Parsing failed. If the entry says that this is expected, then - * return OK. - */ - status = entry->status==ERR_SYNTAX_ERR ? PJ_SUCCESS : -10; - if (status != 0) { - PJ_LOG(3,(THIS_FILE, " uri parse error!\n" - " uri='%s'\n", - input)); - } - goto on_return; - } - pj_get_timestamp(&t2); - pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&var.parse_time, &t2); - - /* Create the reference URI. */ - ref_uri = entry->creator(pool); - - /* Print both URI. */ - s1.ptr = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); - s2.ptr = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); - - pj_get_timestamp(&t1); - len = pjsip_uri_print( PJSIP_URI_IN_OTHER, parsed_uri, s1.ptr, PJSIP_MAX_URL_SIZE); - if (len < 1) { - status = -20; - goto on_return; - } - s1.ptr[len] = '\0'; - s1.slen = len; - - var.print_len = var.print_len + len; - pj_get_timestamp(&t2); - pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&var.print_time, &t2); - - len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE); - if (len < 1) { - status = -30; - goto on_return; - } - s2.ptr[len] = '\0'; - s2.slen = len; - - /* Full comparison of parsed URI with reference URI. */ - pj_get_timestamp(&t1); - status = pjsip_uri_cmp(PJSIP_URI_IN_OTHER, parsed_uri, ref_uri); - if (status != 0) { - /* Not equal. See if this is the expected status. */ - status = entry->status==ERR_NOT_EQUAL ? PJ_SUCCESS : -40; - if (status != 0) { - PJ_LOG(3,(THIS_FILE, " uri comparison mismatch, status=%d:\n" - " uri1='%s'\n" - " uri2='%s'", - status, s1.ptr, s2.ptr)); - } - goto on_return; - - } else { - /* Equal. See if this is the expected status. */ - status = entry->status==PJ_SUCCESS ? PJ_SUCCESS : -50; - if (status != PJ_SUCCESS) { - goto on_return; - } - } - - var.cmp_len = var.cmp_len + len; - pj_get_timestamp(&t2); - pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&var.cmp_time, &t2); - - /* Compare text. */ - if (entry->printed) { - if (pj_strcmp2(&s1, entry->printed) != 0) { - /* Not equal. */ - PJ_LOG(3,(THIS_FILE, " uri print mismatch:\n" - " printed='%s'\n" - " expectd='%s'", - s1.ptr, entry->printed)); - status = -60; - } - } else { - if (pj_strcmp(&s1, &s2) != 0) { - /* Not equal. */ - PJ_LOG(3,(THIS_FILE, " uri print mismatch:\n" - " uri1='%s'\n" - " uri2='%s'", - s1.ptr, s2.ptr)); - status = -70; - } - } - -on_return: - return status; -} - - -static int simple_uri_test(void) -{ - unsigned i; - pj_pool_t *pool; - pj_status_t status; - - PJ_LOG(3,(THIS_FILE, " simple test")); - for (i=0; i max) max = run[i].parse; - - PJ_LOG(3,("", " Maximum URI parse/sec=%u", max)); - - pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be parsed with " - "pjsip_parse_uri() per second " - "(tested with %d URI set, with average length of " - "%d chars)", - (int)PJ_ARRAY_SIZE(uri_test_array), avg_len); - - report_ival("uri-parse-per-sec", max, "URI/sec", desc); - - /* URI parsing bandwidth */ - report_ival("uri-parse-bandwidth-mb", avg_len*max/1000000, "MB/sec", - "URI parsing bandwidth in megabytes (number of megabytes " - "worth of URI that can be parsed per second)"); - - - /* Print maximum print/sec */ - for (i=0, max=0; i max) max = run[i].print; - - PJ_LOG(3,("", " Maximum URI print/sec=%u", max)); - - pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be printed with " - "pjsip_uri_print() per second " - "(tested with %d URI set, with average length of " - "%d chars)", - (int)PJ_ARRAY_SIZE(uri_test_array), avg_len); - - report_ival("uri-print-per-sec", max, "URI/sec", desc); - - /* Print maximum detect/sec */ - for (i=0, max=0; i max) max = run[i].cmp; - - PJ_LOG(3,("", " Maximum URI comparison/sec=%u", max)); - - pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be compared with " - "pjsip_uri_cmp() per second " - "(tested with %d URI set, with average length of " - "%d chars)", - (int)PJ_ARRAY_SIZE(uri_test_array), avg_len); - - report_ival("uri-cmp-per-sec", max, "URI/sec", desc); - -#endif /* INCLUDE_BENCHMARKS */ - - return PJ_SUCCESS; -} - diff --git a/pjsip/src/test/dlg_core_test.c b/pjsip/src/test/dlg_core_test.c new file mode 100644 index 00000000..ae278cbd --- /dev/null +++ b/pjsip/src/test/dlg_core_test.c @@ -0,0 +1,23 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + +#include "test.h" +#include + diff --git a/pjsip/src/test/dns_test.c b/pjsip/src/test/dns_test.c new file mode 100644 index 00000000..a9ffec01 --- /dev/null +++ b/pjsip/src/test/dns_test.c @@ -0,0 +1,618 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ +#include "test.h" +#include +#include +#include + +/* For logging purpose. */ +#define THIS_FILE "dns_test.c" + +struct result +{ + pj_status_t status; + pjsip_server_addresses servers; +}; + + +static void cb(pj_status_t status, + void *token, + const struct pjsip_server_addresses *addr) +{ + struct result *result = (struct result*) token; + + result->status = status; + if (status == PJ_SUCCESS) + pj_memcpy(&result->servers, addr, sizeof(*addr)); +} + + +static void add_dns_entries(pj_dns_resolver *resv) +{ + /* Inject DNS SRV entry */ + pj_dns_parsed_packet pkt; + pj_dns_parsed_query q; + pj_dns_parsed_rr ans[4]; + pj_dns_parsed_rr ar[5]; + pj_str_t tmp; + unsigned i; + + /* + * This is answer to SRV query to "example.com" domain, and + * the answer contains full reference to the A records of + * the server. The full DNS records is : + + _sip._udp.example.com 3600 IN SRV 0 0 5060 sip01.example.com. + _sip._udp.example.com 3600 IN SRV 0 20 5060 sip02.example.com. + _sip._udp.example.com 3600 IN SRV 0 10 5060 sip03.example.com. + _sip._udp.example.com 3600 IN SRV 1 0 5060 sip04.example.com. + + sip01.example.com. 3600 IN A 1.1.1.1 + sip02.example.com. 3600 IN A 2.2.2.2 + sip03.example.com. 3600 IN A 3.3.3.3 + sip04.example.com. 3600 IN A 4.4.4.4 + + ; Additionally, add A record for "example.com" + example.com. 3600 IN A 5.5.5.5 + + */ + pj_bzero(&pkt, sizeof(pkt)); + pj_bzero(ans, sizeof(ans)); + pj_bzero(ar, sizeof(ar)); + + pkt.hdr.flags = PJ_DNS_SET_QR(1); + pkt.hdr.anscount = PJ_ARRAY_SIZE(ans); + pkt.hdr.arcount = 0; + pkt.ans = ans; + pkt.arr = ar; + + ans[0].name = pj_str("_sip._udp.example.com"); + ans[0].type = PJ_DNS_TYPE_SRV; + ans[0].dnsclass = PJ_DNS_CLASS_IN; + ans[0].ttl = 3600; + ans[0].rdata.srv.prio = 0; + ans[0].rdata.srv.weight = 0; + ans[0].rdata.srv.port = 5060; + ans[0].rdata.srv.target = pj_str("sip01.example.com"); + + ans[1].name = pj_str("_sip._udp.example.com"); + ans[1].type = PJ_DNS_TYPE_SRV; + ans[1].dnsclass = PJ_DNS_CLASS_IN; + ans[1].ttl = 3600; + ans[1].rdata.srv.prio = 0; + ans[1].rdata.srv.weight = 20; + ans[1].rdata.srv.port = 5060; + ans[1].rdata.srv.target = pj_str("sip02.example.com"); + + ans[2].name = pj_str("_sip._udp.example.com"); + ans[2].type = PJ_DNS_TYPE_SRV; + ans[2].dnsclass = PJ_DNS_CLASS_IN; + ans[2].ttl = 3600; + ans[2].rdata.srv.prio = 0; + ans[2].rdata.srv.weight = 10; + ans[2].rdata.srv.port = 5060; + ans[2].rdata.srv.target = pj_str("sip03.example.com"); + + ans[3].name = pj_str("_sip._udp.example.com"); + ans[3].type = PJ_DNS_TYPE_SRV; + ans[3].dnsclass = PJ_DNS_CLASS_IN; + ans[3].ttl = 3600; + ans[3].rdata.srv.prio = 1; + ans[3].rdata.srv.weight = 0; + ans[3].rdata.srv.port = 5060; + ans[3].rdata.srv.target = pj_str("sip04.example.com"); + + pj_dns_resolver_add_entry( resv, &pkt, PJ_FALSE); + + ar[0].name = pj_str("sip01.example.com"); + ar[0].type = PJ_DNS_TYPE_A; + ar[0].dnsclass = PJ_DNS_CLASS_IN; + ar[0].ttl = 3600; + ar[0].rdata.a.ip_addr = pj_inet_addr(pj_cstr(&tmp, "1.1.1.1")); + + ar[1].name = pj_str("sip02.example.com"); + ar[1].type = PJ_DNS_TYPE_A; + ar[1].dnsclass = PJ_DNS_CLASS_IN; + ar[1].ttl = 3600; + ar[1].rdata.a.ip_addr = pj_inet_addr(pj_cstr(&tmp, "2.2.2.2")); + + ar[2].name = pj_str("sip03.example.com"); + ar[2].type = PJ_DNS_TYPE_A; + ar[2].dnsclass = PJ_DNS_CLASS_IN; + ar[2].ttl = 3600; + ar[2].rdata.a.ip_addr = pj_inet_addr(pj_cstr(&tmp, "3.3.3.3")); + + ar[3].name = pj_str("sip04.example.com"); + ar[3].type = PJ_DNS_TYPE_A; + ar[3].dnsclass = PJ_DNS_CLASS_IN; + ar[3].ttl = 3600; + ar[3].rdata.a.ip_addr = pj_inet_addr(pj_cstr(&tmp, "4.4.4.4")); + + ar[4].name = pj_str("example.com"); + ar[4].type = PJ_DNS_TYPE_A; + ar[4].dnsclass = PJ_DNS_CLASS_IN; + ar[4].ttl = 3600; + ar[4].rdata.a.ip_addr = pj_inet_addr(pj_cstr(&tmp, "5.5.5.5")); + + /* + * Create individual A records for all hosts in "example.com" domain. + */ + for (i=0; icount != result.servers.count) { + PJ_LOG(3,(THIS_FILE, " test_resolve() error 10: result count mismatch")); + return 10; + } + + for (i=0; icount; ++i) { + pj_sockaddr_in *ra = (pj_sockaddr_in *)&ref->entry[i].addr; + pj_sockaddr_in *rb = (pj_sockaddr_in *)&result.servers.entry[i].addr; + + if (ra->sin_addr.s_addr != rb->sin_addr.s_addr) { + PJ_LOG(3,(THIS_FILE, " test_resolve() error 20: IP address mismatch")); + return 20; + } + if (ra->sin_port != rb->sin_port) { + PJ_LOG(3,(THIS_FILE, " test_resolve() error 30: port mismatch")); + return 30; + } + if (ref->entry[i].addr_len != result.servers.entry[i].addr_len) { + PJ_LOG(3,(THIS_FILE, " test_resolve() error 40: addr_len mismatch")); + return 40; + } + if (ref->entry[i].type != result.servers.entry[i].type) { + PJ_LOG(3,(THIS_FILE, " test_resolve() error 50: transport type mismatch")); + return 50; + } + } + } + + return PJ_SUCCESS; +} + +/* + * Perform round-robin/load balance test. + */ +static int round_robin_test(pj_pool_t *pool) +{ + enum { COUNT = 400, PCT_ALLOWANCE = 5 }; + unsigned i; + struct server_hit + { + char *ip_addr; + unsigned percent; + unsigned hits; + } server_hit[] = + { + { "1.1.1.1", 3, 0 }, + { "2.2.2.2", 65, 0 }, + { "3.3.3.3", 32, 0 }, + { "4.4.4.4", 0, 0 } + }; + + PJ_LOG(3,(THIS_FILE, " Performing round-robin/load-balance test..")); + + /* Do multiple resolve request to "example.com". + * The resolver should select the server based on the weight proportion + * the the servers in the SRV entry. + */ + for (i=0; isin_addr.s_addr) { + server_hit[j].hits++; + break; + } + } + + if (j == PJ_ARRAY_SIZE(server_hit)) { + PJ_LOG(1,(THIS_FILE, "..round_robin_test() error 10: returned address mismatch")); + return 10; + } + } + + /* Print the actual hit rate */ + for (i=0; i (int)server_hit[i].percent) + { + PJ_LOG(1,(THIS_FILE, + "..round_robin_test() error 20: " + "hit rate difference for server %s (%d%%) is more than " + "tolerable allowance (%d%%)", + server_hit[i].ip_addr, + actual_pct - server_hit[i].percent, + PCT_ALLOWANCE)); + return 20; + } + } + + PJ_LOG(3,(THIS_FILE, + " Load balance test success, hit-rate is " + "within %d%% allowance", PCT_ALLOWANCE)); + return PJ_SUCCESS; +} + + +#define C(expr) status = expr; \ + if (status != PJ_SUCCESS) app_perror(THIS_FILE, "Error", status); + +static void add_ref(pjsip_server_addresses *r, + pjsip_transport_type_e type, + char *addr, + int port) +{ + pj_sockaddr_in *a; + pj_str_t tmp; + + r->entry[r->count].type = type; + r->entry[r->count].priority = 0; + r->entry[r->count].weight = 0; + r->entry[r->count].addr_len = sizeof(pj_sockaddr_in); + + a = (pj_sockaddr_in *)&r->entry[r->count].addr; + a->sin_family = pj_AF_INET(); + tmp = pj_str(addr); + a->sin_addr = pj_inet_addr(&tmp); + a->sin_port = pj_htons((pj_uint16_t)port); + + r->count++; +} + +static void create_ref(pjsip_server_addresses *r, + pjsip_transport_type_e type, + char *addr, + int port) +{ + r->count = 0; + add_ref(r, type, addr, port); +} + + +/* + * Main test entry. + */ +int resolve_test(void) +{ + pj_pool_t *pool; + pj_dns_resolver *resv; + pj_str_t nameserver; + pj_uint16_t port = 5353; + pj_status_t status; + + pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000); + + status = pjsip_endpt_create_resolver(endpt, &resv); + + nameserver = pj_str("192.168.0.106"); + pj_dns_resolver_set_ns(resv, 1, &nameserver, &port); + pjsip_endpt_set_resolver(endpt, resv); + + add_dns_entries(resv); + + /* These all should be resolved as IP addresses (DNS A query) */ + { + pjsip_server_addresses ref; + create_ref(&ref, PJSIP_TRANSPORT_UDP, "1.1.1.1", 5060); + status = test_resolve("IP address without transport and port", pool, PJSIP_TRANSPORT_UNSPECIFIED, "1.1.1.1", 0, &ref); + if (status != PJ_SUCCESS) + return -100; + } + { + pjsip_server_addresses ref; + create_ref(&ref, PJSIP_TRANSPORT_UDP, "1.1.1.1", 5060); + status = test_resolve("IP address with explicit port", pool, PJSIP_TRANSPORT_UNSPECIFIED, "1.1.1.1", 5060, &ref); + if (status != PJ_SUCCESS) + return -110; + } + { + pjsip_server_addresses ref; + create_ref(&ref, PJSIP_TRANSPORT_TCP, "1.1.1.1", 5060); + status = test_resolve("IP address without port (TCP)", pool, PJSIP_TRANSPORT_TCP,"1.1.1.1", 0, &ref); + if (status != PJ_SUCCESS) + return -120; + } + { + pjsip_server_addresses ref; + create_ref(&ref, PJSIP_TRANSPORT_TLS, "1.1.1.1", 5061); + status = test_resolve("IP address without port (TLS)", pool, PJSIP_TRANSPORT_TLS, "1.1.1.1", 0, &ref); + if (status != PJ_SUCCESS) + return -130; + } + + /* This should be resolved as DNS A record (because port is present) */ + { + pjsip_server_addresses ref; + create_ref(&ref, PJSIP_TRANSPORT_UDP, "5.5.5.5", 5060); + status = test_resolve("domain name with port should resolve to A record", pool, PJSIP_TRANSPORT_UNSPECIFIED, "example.com", 5060, &ref); + if (status != PJ_SUCCESS) + return -140; + } + + /* This will fail to be resolved as SRV, resolver should fallback to + * resolving to A record. + */ + { + pjsip_server_addresses ref; + create_ref(&ref, PJSIP_TRANSPORT_UDP, "2.2.2.2", 5060); + status = test_resolve("failure with SRV fallback to A record", pool, PJSIP_TRANSPORT_UNSPECIFIED, "sip02.example.com", 0, &ref); + if (status != PJ_SUCCESS) + return -150; + } + + /* Same as above, but explicitly for TLS. */ + { + pjsip_server_addresses ref; + create_ref(&ref, PJSIP_TRANSPORT_TLS, "2.2.2.2", 5061); + status = test_resolve("failure with SRV fallback to A record (for TLS)", pool, PJSIP_TRANSPORT_TLS, "sip02.example.com", 0, &ref); + if (status != PJ_SUCCESS) + return -150; + } + + /* Standard DNS SRV followed by A recolution */ + { + pjsip_server_addresses ref; + create_ref(&ref, PJSIP_TRANSPORT_UDP, "6.6.6.6", 50060); + status = test_resolve("standard SRV resolution", pool, PJSIP_TRANSPORT_UNSPECIFIED, "domain.com", 0, &ref); + if (status != PJ_SUCCESS) + return -155; + } + + /* Standard DNS SRV followed by A recolution (explicit transport) */ + { + pjsip_server_addresses ref; + create_ref(&ref, PJSIP_TRANSPORT_TCP, "6.6.6.6", 50060); + add_ref(&ref, PJSIP_TRANSPORT_TCP, "7.7.7.7", 50060); + status = test_resolve("standard SRV resolution with explicit transport (TCP)", pool, PJSIP_TRANSPORT_TCP, "domain.com", 0, &ref); + if (status != PJ_SUCCESS) + return -160; + } + + + /* Round robin/load balance test */ + if (round_robin_test(pool) != 0) + return -170; + + /* Timeout test */ + { + status = test_resolve("timeout test", pool, PJSIP_TRANSPORT_UNSPECIFIED, "an.invalid.address", 0, NULL); + if (status == PJ_SUCCESS) + return -150; + } + + return 0; +} + diff --git a/pjsip/src/test/inv_offer_answer_test.c b/pjsip/src/test/inv_offer_answer_test.c new file mode 100644 index 00000000..22809ddf --- /dev/null +++ b/pjsip/src/test/inv_offer_answer_test.c @@ -0,0 +1,677 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + +#include "test.h" +#include +#include +#include + +#define THIS_FILE "inv_offer_answer_test.c" +#define PORT 5068 +#define CONTACT "sip:127.0.0.1:5068" +#define TRACE_(x) PJ_LOG(3,x) + +static struct oa_sdp_t +{ + const char *offer; + const char *answer; + unsigned pt_result; +} oa_sdp[] = +{ + { + /* Offer: */ + "v=0\r\n" + "o=alice 1 1 IN IP4 host.anywhere.com\r\n" + "s= \r\n" + "c=IN IP4 host.anywhere.com\r\n" + "t=0 0\r\n" + "m=audio 49170 RTP/AVP 0\r\n" + "a=rtpmap:0 PCMU/8000\r\n", + + /* Answer: */ + "v=0\r\n" + "o=bob 1 1 IN IP4 host.example.com\r\n" + "s= \r\n" + "c=IN IP4 host.example.com\r\n" + "t=0 0\r\n" + "m=audio 49920 RTP/AVP 0\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "m=video 0 RTP/AVP 31\r\n", + + 0 + }, + + { + /* Offer: */ + "v=0\r\n" + "o=alice 2 2 IN IP4 host.anywhere.com\r\n" + "s= \r\n" + "c=IN IP4 host.anywhere.com\r\n" + "t=0 0\r\n" + "m=audio 49170 RTP/AVP 8\r\n" + "a=rtpmap:0 PCMA/8000\r\n", + + /* Answer: */ + "v=0\r\n" + "o=bob 2 2 IN IP4 host.example.com\r\n" + "s= \r\n" + "c=IN IP4 host.example.com\r\n" + "t=0 0\r\n" + "m=audio 49920 RTP/AVP 8\r\n" + "a=rtpmap:0 PCMA/8000\r\n", + + 8 + }, + + { + /* Offer: */ + "v=0\r\n" + "o=alice 3 3 IN IP4 host.anywhere.com\r\n" + "s= \r\n" + "c=IN IP4 host.anywhere.com\r\n" + "t=0 0\r\n" + "m=audio 49170 RTP/AVP 3\r\n", + + /* Answer: */ + "v=0\r\n" + "o=bob 3 3 IN IP4 host.example.com\r\n" + "s= \r\n" + "c=IN IP4 host.example.com\r\n" + "t=0 0\r\n" + "m=audio 49920 RTP/AVP 3\r\n", + + 3 + }, + + { + /* Offer: */ + "v=0\r\n" + "o=alice 4 4 IN IP4 host.anywhere.com\r\n" + "s= \r\n" + "c=IN IP4 host.anywhere.com\r\n" + "t=0 0\r\n" + "m=audio 49170 RTP/AVP 4\r\n", + + /* Answer: */ + "v=0\r\n" + "o=bob 4 4 IN IP4 host.example.com\r\n" + "s= \r\n" + "c=IN IP4 host.example.com\r\n" + "t=0 0\r\n" + "m=audio 49920 RTP/AVP 4\r\n", + + 4 + } +}; + + + +typedef enum oa_t +{ + OFFERER_NONE, + OFFERER_UAC, + OFFERER_UAS +} oa_t; + +typedef struct inv_test_param_t +{ + char *title; + unsigned inv_option; + pj_bool_t need_established; + unsigned count; + oa_t oa[4]; +} inv_test_param_t; + +typedef struct inv_test_t +{ + inv_test_param_t param; + pjsip_inv_session *uac; + pjsip_inv_session *uas; + + pj_bool_t complete; + pj_bool_t uas_complete, + uac_complete; + + unsigned oa_index; + unsigned uac_update_cnt, + uas_update_cnt; +} inv_test_t; + + +/**************** GLOBALS ******************/ +static inv_test_t inv_test; +static unsigned job_cnt; + +typedef enum job_type +{ + SEND_OFFER, + ESTABLISH_CALL +} job_type; + +typedef struct job_t +{ + job_type type; + pjsip_role_e who; +} job_t; + +static job_t jobs[128]; + + +/**************** UTILS ******************/ +static pjmedia_sdp_session *create_sdp(pj_pool_t *pool, const char *body) +{ + pjmedia_sdp_session *sdp; + pj_str_t dup; + pj_status_t status; + + pj_strdup2_with_null(pool, &dup, body); + status = pjmedia_sdp_parse(pool, dup.ptr, dup.slen, &sdp); + pj_assert(status == PJ_SUCCESS); + + return sdp; +} + +/**************** INVITE SESSION CALLBACKS ******************/ +static void on_rx_offer(pjsip_inv_session *inv, + const pjmedia_sdp_session *offer) +{ + pjmedia_sdp_session *sdp; + + sdp = create_sdp(inv->dlg->pool, oa_sdp[inv_test.oa_index].answer); + pjsip_inv_set_sdp_answer(inv, sdp); + + if (inv_test.oa_index == inv_test.param.count-1 && + inv_test.param.need_established) + { + jobs[job_cnt].type = ESTABLISH_CALL; + jobs[job_cnt].who = PJSIP_ROLE_UAS; + job_cnt++; + } +} + + +static void on_create_offer(pjsip_inv_session *inv, + pjmedia_sdp_session **p_offer) +{ + pj_assert(!"Should not happen"); +} + +static void on_media_update(pjsip_inv_session *inv_ses, + pj_status_t status) +{ + if (inv_ses == inv_test.uas) { + inv_test.uas_update_cnt++; + pj_assert(inv_test.uas_update_cnt - inv_test.uac_update_cnt <= 1); + TRACE_((THIS_FILE, " Callee media is established")); + } else if (inv_ses == inv_test.uac) { + inv_test.uac_update_cnt++; + pj_assert(inv_test.uac_update_cnt - inv_test.uas_update_cnt <= 1); + TRACE_((THIS_FILE, " Caller media is established")); + + } else { + pj_assert(!"Unknown session!"); + } + + if (inv_test.uac_update_cnt == inv_test.uas_update_cnt) { + inv_test.oa_index++; + + if (inv_test.oa_index < inv_test.param.count) { + switch (inv_test.param.oa[inv_test.oa_index]) { + case OFFERER_UAC: + jobs[job_cnt].type = SEND_OFFER; + jobs[job_cnt].who = PJSIP_ROLE_UAC; + job_cnt++; + break; + case OFFERER_UAS: + jobs[job_cnt].type = SEND_OFFER; + jobs[job_cnt].who = PJSIP_ROLE_UAS; + job_cnt++; + break; + default: + pj_assert(!"Invalid oa"); + } + } + + pj_assert(job_cnt <= PJ_ARRAY_SIZE(jobs)); + } +} + +static void on_state_changed(pjsip_inv_session *inv, pjsip_event *e) +{ + const char *who = NULL; + + if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { + TRACE_((THIS_FILE, " %s call disconnected", + (inv==inv_test.uas ? "Callee" : "Caller"))); + return; + } + + if (inv->state != PJSIP_INV_STATE_CONFIRMED) + return; + + if (inv == inv_test.uas) { + inv_test.uas_complete = PJ_TRUE; + who = "Callee"; + } else if (inv == inv_test.uac) { + inv_test.uac_complete = PJ_TRUE; + who = "Caller"; + } else + pj_assert(!"No session"); + + TRACE_((THIS_FILE, " %s call is confirmed", who)); + + if (inv_test.uac_complete && inv_test.uas_complete) + inv_test.complete = PJ_TRUE; +} + + +/**************** MODULE TO RECEIVE INITIAL INVITE ******************/ + +static pj_bool_t on_rx_request(pjsip_rx_data *rdata) +{ + if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG && + rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) + { + pjsip_dialog *dlg; + pjmedia_sdp_session *sdp = NULL; + pj_str_t uri; + pjsip_tx_data *tdata; + pj_status_t status; + + /* + * Create UAS + */ + uri = pj_str(CONTACT); + status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, + &uri, &dlg); + pj_assert(status == PJ_SUCCESS); + + if (inv_test.param.oa[0] == OFFERER_UAC) + sdp = create_sdp(rdata->tp_info.pool, oa_sdp[0].answer); + else if (inv_test.param.oa[0] == OFFERER_UAS) + sdp = create_sdp(rdata->tp_info.pool, oa_sdp[0].offer); + else + pj_assert(!"Invalid offerer type"); + + status = pjsip_inv_create_uas(dlg, rdata, sdp, inv_test.param.inv_option, &inv_test.uas); + pj_assert(status == PJ_SUCCESS); + + TRACE_((THIS_FILE, " Sending 183 with SDP")); + + /* + * Answer with 183 + */ + status = pjsip_inv_initial_answer(inv_test.uas, rdata, 183, NULL, + NULL, &tdata); + pj_assert(status == PJ_SUCCESS); + + status = pjsip_inv_send_msg(inv_test.uas, tdata); + pj_assert(status == PJ_SUCCESS); + + return PJ_TRUE; + } + + return PJ_FALSE; +} + +static pjsip_module mod_inv_oa_test = +{ + NULL, NULL, /* prev, next. */ + { "mod-inv-oa-test", 15 }, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + &on_rx_request, /* on_rx_request() */ + NULL, /* on_rx_response() */ + NULL, /* on_tx_request. */ + NULL, /* on_tx_response() */ + NULL, /* on_tsx_state() */ +}; + + +/**************** THE TEST ******************/ +static void run_job(job_t *j) +{ + pjsip_inv_session *inv; + pjsip_tx_data *tdata; + pjmedia_sdp_session *sdp; + pj_status_t status; + + if (j->who == PJSIP_ROLE_UAC) + inv = inv_test.uac; + else + inv = inv_test.uas; + + switch (j->type) { + case SEND_OFFER: + sdp = create_sdp(inv->dlg->pool, oa_sdp[inv_test.oa_index].offer); + + TRACE_((THIS_FILE, " Sending UPDATE with offer")); + status = pjsip_inv_update(inv, NULL, sdp, &tdata); + pj_assert(status == PJ_SUCCESS); + + status = pjsip_inv_send_msg(inv, tdata); + pj_assert(status == PJ_SUCCESS); + break; + case ESTABLISH_CALL: + TRACE_((THIS_FILE, " Sending 200/OK")); + status = pjsip_inv_answer(inv, 200, NULL, NULL, &tdata); + pj_assert(status == PJ_SUCCESS); + + status = pjsip_inv_send_msg(inv, tdata); + pj_assert(status == PJ_SUCCESS); + break; + } +} + + +static int perform_test(inv_test_param_t *param) +{ + pj_str_t uri; + pjsip_dialog *dlg; + pjmedia_sdp_session *sdp; + pjsip_tx_data *tdata; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " %s", param->title)); + + pj_bzero(&inv_test, sizeof(inv_test)); + pj_memcpy(&inv_test.param, param, sizeof(*param)); + job_cnt = 0; + + uri = pj_str(CONTACT); + + /* + * Create UAC + */ + status = pjsip_dlg_create_uac(pjsip_ua_instance(), + &uri, &uri, &uri, &uri, &dlg); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, -10); + + if (inv_test.param.oa[0] == OFFERER_UAC) + sdp = create_sdp(dlg->pool, oa_sdp[0].offer); + else + sdp = NULL; + + status = pjsip_inv_create_uac(dlg, sdp, inv_test.param.inv_option, &inv_test.uac); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, -20); + + TRACE_((THIS_FILE, " Sending INVITE %s offer", (sdp ? "with" : "without"))); + + /* + * Make call! + */ + status = pjsip_inv_invite(inv_test.uac, &tdata); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30); + + status = pjsip_inv_send_msg(inv_test.uac, tdata); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30); + + /* + * Wait until test completes + */ + while (!inv_test.complete) { + pj_time_val delay = {0, 20}; + + pjsip_endpt_handle_events(endpt, &delay); + + while (job_cnt) { + job_t j; + + j = jobs[0]; + pj_array_erase(jobs, sizeof(jobs[0]), job_cnt, 0); + --job_cnt; + + run_job(&j); + } + } + + flush_events(100); + + /* + * Hangup + */ + TRACE_((THIS_FILE, " Disconnecting call")); + status = pjsip_inv_end_session(inv_test.uas, PJSIP_SC_DECLINE, 0, &tdata); + pj_assert(status == PJ_SUCCESS); + + status = pjsip_inv_send_msg(inv_test.uas, tdata); + pj_assert(status == PJ_SUCCESS); + + flush_events(500); + + return 0; +} + + +static pj_bool_t log_on_rx_msg(pjsip_rx_data *rdata) +{ + pjsip_msg *msg = rdata->msg_info.msg; + char info[80]; + + if (msg->type == PJSIP_REQUEST_MSG) + pj_ansi_snprintf(info, sizeof(info), "%.*s", + (int)msg->line.req.method.name.slen, + msg->line.req.method.name.ptr); + else + pj_ansi_snprintf(info, sizeof(info), "%d/%.*s", + msg->line.status.code, + (int)rdata->msg_info.cseq->method.name.slen, + rdata->msg_info.cseq->method.name.ptr); + + TRACE_((THIS_FILE, " Received %s %s sdp", info, + (msg->body ? "with" : "without"))); + + return PJ_FALSE; +} + + +/* Message logger module. */ +static pjsip_module mod_msg_logger = +{ + NULL, NULL, /* prev and next */ + { "mod-msg-loggee", 14}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + &log_on_rx_msg, /* on_rx_request() */ + &log_on_rx_msg, /* on_rx_response() */ + NULL, /* on_tx_request() */ + NULL, /* on_tx_response() */ + NULL, /* on_tsx_state() */ +}; + +static inv_test_param_t test_params[] = +{ +/* Normal scenario: + + UAC UAS + INVITE (offer) --> + 200/INVITE (answer) <-- + ACK --> + */ +#if 0 + { + "Standard INVITE with offer", + 0, + PJ_TRUE, + 1, + { OFFERER_UAC } + }, + + { + "Standard INVITE with offer, with 100rel", + PJSIP_INV_REQUIRE_100REL, + PJ_TRUE, + 1, + { OFFERER_UAC } + }, +#endif + +/* Delayed offer: + UAC UAS + INVITE (no SDP) --> + 200/INVITE (offer) <-- + ACK (answer) --> + */ +#if 1 + { + "INVITE with no offer", + 0, + PJ_TRUE, + 1, + { OFFERER_UAS } + }, + + { + "INVITE with no offer, with 100rel", + PJSIP_INV_REQUIRE_100REL, + PJ_TRUE, + 1, + { OFFERER_UAS } + }, +#endif + +/* Subsequent UAC offer with UPDATE: + + UAC UAS + INVITE (offer) --> + 180/rel (answer) <-- + UPDATE (offer) --> inv_update() on_rx_offer() + set_sdp_answer() + 200/UPDATE (answer) <-- + 200/INVITE <-- + ACK --> +*/ +#if 1 + { + "INVITE and UPDATE by UAC", + 0, + PJ_TRUE, + 2, + { OFFERER_UAC, OFFERER_UAC } + }, + { + "INVITE and UPDATE by UAC, with 100rel", + PJSIP_INV_REQUIRE_100REL, + PJ_TRUE, + 2, + { OFFERER_UAC, OFFERER_UAC } + }, +#endif + +/* Subsequent UAS offer with UPDATE: + + INVITE (offer --> + 180/rel (answer) <-- + UPDATE (offer) <-- inv_update() + on_rx_offer() + set_sdp_answer() + 200/UPDATE (answer) --> + UPDATE (offer) --> on_rx_offer() + set_sdp_answer() + 200/UPDATE (answer) <-- + 200/INVITE <-- + ACK --> + + */ + { + "INVITE and many UPDATE by UAC and UAS", + 0, + PJ_TRUE, + 4, + { OFFERER_UAC, OFFERER_UAS, OFFERER_UAC, OFFERER_UAS } + }, + +}; + + +static pjsip_dialog* on_dlg_forked(pjsip_dialog *first_set, pjsip_rx_data *res) +{ + return NULL; +} + + +static void on_new_session(pjsip_inv_session *inv, pjsip_event *e) +{ +} + + +int inv_offer_answer_test(void) +{ + unsigned i; + int rc = 0; + + /* Init UA layer */ + if (pjsip_ua_instance()->id == -1) { + pjsip_ua_init_param ua_param; + pj_bzero(&ua_param, sizeof(ua_param)); + ua_param.on_dlg_forked = &on_dlg_forked; + pjsip_ua_init_module(endpt, &ua_param); + } + + /* Init inv-usage */ + if (pjsip_inv_usage_instance()->id == -1) { + pjsip_inv_callback inv_cb; + pj_bzero(&inv_cb, sizeof(inv_cb)); + inv_cb.on_media_update = &on_media_update; + inv_cb.on_rx_offer = &on_rx_offer; + inv_cb.on_create_offer = &on_create_offer; + inv_cb.on_state_changed = &on_state_changed; + inv_cb.on_new_session = &on_new_session; + pjsip_inv_usage_init(endpt, &inv_cb); + } + + /* 100rel module */ + pjsip_100rel_init_module(endpt); + + /* Our module */ + pjsip_endpt_register_module(endpt, &mod_inv_oa_test); + pjsip_endpt_register_module(endpt, &mod_msg_logger); + + /* Create SIP UDP transport */ + { + pj_sockaddr_in addr; + pjsip_transport *tp; + pj_status_t status; + + pj_sockaddr_in_init(&addr, NULL, PORT); + status = pjsip_udp_transport_start(endpt, &addr, NULL, 1, &tp); + pj_assert(status == PJ_SUCCESS); + } + + /* Do tests */ + for (i=0; i + * + * 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 + */ +#include "test.h" +#include +#include +#include + +extern const char *system_name; + +static void usage() +{ + puts("Usage: test-pjsip"); + puts("Options:"); + puts(" -i,--interractive Key input at the end."); + puts(" -h,--help Show this screen"); + puts(" -l,--log-level N Set log level (0-6)"); +} + +int main(int argc, char *argv[]) +{ + int interractive = 0; + int retval; + char **opt_arg; + + /* Parse arguments. */ + opt_arg = argv+1; + while (*opt_arg) { + if (strcmp(*opt_arg, "-i") == 0 || + strcmp(*opt_arg, "--interractive") == 0) + { + interractive = 1; + } else if (strcmp(*opt_arg, "-h") == 0 || + strcmp(*opt_arg, "--help") == 0) + { + usage(); + return 1; + } else if (strcmp(*opt_arg, "-l") == 0 || + strcmp(*opt_arg, "--log-level") == 0) + { + ++opt_arg; + if (!opt_arg) { + usage(); + return 1; + } + log_level = atoi(*opt_arg); + } else if (strcmp(*opt_arg, "-s") == 0 || + strcmp(*opt_arg, "--system") == 0) + { + ++opt_arg; + if (!opt_arg) { + usage(); + return 1; + } + system_name = *opt_arg; + } else { + usage(); + return 1; + } + + ++opt_arg; + } + + retval = test_main(); + + if (interractive) { + char s[10]; + printf("\n"); fflush(stdout); + if (fgets(s, sizeof(s), stdin) == NULL) + return retval; + } + + return retval; +} diff --git a/pjsip/src/test/main_rtems.c b/pjsip/src/test/main_rtems.c new file mode 100644 index 00000000..a4d14e5a --- /dev/null +++ b/pjsip/src/test/main_rtems.c @@ -0,0 +1,12 @@ + +/* + * !! OIY OIY !! + * + * The purpose of this file is only to get pjsip-test linked. I haven't + * actually tried to run pjsip-test on RTEMS!! + * + */ + +#include "../../pjlib/src/pjlib-test/main_rtems.c" + + diff --git a/pjsip/src/test/main_win32.c b/pjsip/src/test/main_win32.c new file mode 100644 index 00000000..3043a395 --- /dev/null +++ b/pjsip/src/test/main_win32.c @@ -0,0 +1 @@ +#include "../../pjlib/src/pjlib-test/main_win32.c" diff --git a/pjsip/src/test/msg_err_test.c b/pjsip/src/test/msg_err_test.c new file mode 100644 index 00000000..46d28f15 --- /dev/null +++ b/pjsip/src/test/msg_err_test.c @@ -0,0 +1,101 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ +#include "test.h" +#include +#include + +#define THIS_FILE "msg_err_test.c" + + +static pj_bool_t verify_success(pjsip_msg *msg, + pjsip_parser_err_report *err_list) +{ + return PJ_TRUE; +} + +static struct test_entry +{ + char msg[1024]; + pj_bool_t (*verify)(pjsip_msg *msg, + pjsip_parser_err_report *err_list); + +} test_entries[] = +{ + /* Syntax error in status line */ + { + "SIP/2.0 200\r\n" + "H-Name: H-Value\r\n" + "\r\n", + &verify_success + }, + + /* Syntax error in header */ + { + "SIP/2.0 200 OK\r\n" + "Via: SIP/2.0\r\n" + "H-Name: H-Value\r\n" + "\r\n", + &verify_success + }, + + /* Multiple syntax errors in headers */ + { + "SIP/2.0 200 OK\r\n" + "Via: SIP/2.0\r\n" + "H-Name: H-Value\r\n" + "Via: SIP/2.0\r\n" + "\r\n", + &verify_success + } +}; + + +int msg_err_test(void) +{ + pj_pool_t *pool; + unsigned i; + + PJ_LOG(3,(THIS_FILE, "Testing parsing error")); + + pool = pjsip_endpt_create_pool(endpt, "msgerrtest", 4000, 4000); + + for (i=0; iline, e->col, + (int)e->hname.slen, + e->hname.ptr)); + e = e->next; + } + } + + pj_pool_release(pool); + return 0; +} diff --git a/pjsip/src/test/msg_logger.c b/pjsip/src/test/msg_logger.c new file mode 100644 index 00000000..8a71adcb --- /dev/null +++ b/pjsip/src/test/msg_logger.c @@ -0,0 +1,104 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ +#include "test.h" +#include +#include + +#define THIS_FILE "msg_logger.c" + +static pj_bool_t msg_log_enabled; + +static pj_bool_t on_rx_msg(pjsip_rx_data *rdata) +{ + if (msg_log_enabled) { + PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%s:%d:\n" + "%.*s\n" + "--end msg--", + rdata->msg_info.len, + pjsip_rx_data_get_info(rdata), + rdata->tp_info.transport->type_name, + rdata->pkt_info.src_name, + rdata->pkt_info.src_port, + rdata->msg_info.len, + rdata->msg_info.msg_buf)); + } + + return PJ_FALSE; +} + +static pj_status_t on_tx_msg(pjsip_tx_data *tdata) +{ + if (msg_log_enabled) { + PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%s:%d:\n" + "%.*s\n" + "--end msg--", + (tdata->buf.cur - tdata->buf.start), + pjsip_tx_data_get_info(tdata), + tdata->tp_info.transport->type_name, + tdata->tp_info.dst_name, + tdata->tp_info.dst_port, + (tdata->buf.cur - tdata->buf.start), + tdata->buf.start)); + } + return PJ_SUCCESS; +} + + +/* Message logger module. */ +static pjsip_module mod_msg_logger = +{ + NULL, NULL, /* prev and next */ + { "mod-msg-logger", 14}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + &on_rx_msg, /* on_rx_request() */ + &on_rx_msg, /* on_rx_response() */ + &on_tx_msg, /* on_tx_request() */ + &on_tx_msg, /* on_tx_response() */ + NULL, /* on_tsx_state() */ +}; + +int init_msg_logger(void) +{ + pj_status_t status; + + if (mod_msg_logger.id != -1) + return 0; + + status = pjsip_endpt_register_module(endpt, &mod_msg_logger); + if (status != PJ_SUCCESS) { + app_perror(" error registering module", status); + return -10; + } + + return 0; +} + +int msg_logger_set_enabled(pj_bool_t enabled) +{ + int val = msg_log_enabled; + msg_log_enabled = enabled; + return val; +} + diff --git a/pjsip/src/test/msg_test.c b/pjsip/src/test/msg_test.c new file mode 100644 index 00000000..840c40ff --- /dev/null +++ b/pjsip/src/test/msg_test.c @@ -0,0 +1,2058 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ +#include "test.h" +#include +#include + +#define POOL_SIZE 8000 +#if defined(PJ_DEBUG) && PJ_DEBUG!=0 +# define LOOP 10000 +#else +# define LOOP 100000 +#endif +#define AVERAGE_MSG_LEN 800 +#define THIS_FILE "msg_test.c" + +static pjsip_msg *create_msg0(pj_pool_t *pool); +static pjsip_msg *create_msg1(pj_pool_t *pool); + +#define STATUS_PARTIAL 1 +#define STATUS_SYNTAX_ERROR 2 + +#define FLAG_DETECT_ONLY 1 +#define FLAG_PARSE_ONLY 4 +#define FLAG_PRINT_ONLY 8 + +struct test_msg +{ + char msg[1024]; + pjsip_msg *(*creator)(pj_pool_t *pool); + pj_size_t len; + int expected_status; +} test_array[] = +{ +{ + /* 'Normal' message with all headers. */ + "INVITE sip:user@foo SIP/2.0\n" + "from: Hi I'm Joe ;tag=123457890123456\r" + "To: Fellow User \r\n" + "Call-ID: 12345678901234567890@bar\r\n" + "Content-Length: 0\r\n" + "CSeq: 123456 INVITE\n" + "Contact: ; q=0.5;expires=3600,sip:user@host;q=0.500\r" + " ,sip:user2@host2\n" + "Content-Type: text/html ; charset=ISO-8859-4\r" + "Route: ,\r\n" + " \r" + "Record-Route: ,\r\n" /* multiple routes+folding*/ + " \n" + "v: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c230\n" + "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n" /* folding. */ + " ;received=192.0.2.1\r\n" + "Via: SIP/2.0/UDP 10.2.1.1, SIP/2.0/TCP 192.168.1.1\n" + "Organization: \r" + "Max-Forwards: 70\n" + "X-Header: \r\n" /* empty header */ + "P-Associated-URI:\r\n" /* empty header without space */ + "\r\n", + &create_msg0, + 0, + PJ_SUCCESS +}, +{ + /* Typical response message. */ + "SIP/2.0 200 OK\r\n" + "Via: SIP/2.0/SCTP server10.biloxi.com;branch=z9hG4bKnashds8;rport;received=192.0.2.1\r\n" + "Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2\r\n" + "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds ;received=192.0.2.3\r\n" + "Route: \r\n" + "Route: \r\n" + "Max-Forwards: 70\r\n" + "To: Bob ;tag=a6c85cf\r\n" + "From: Alice ;tag=1928301774\r\n" + "Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n" + "CSeq: 314159 INVITE\r\n" + "Contact: \r\n" + "Content-Type: application/sdp\r\n" + "Content-Length: 150\r\n" + "\r\n" + "v=0\r\n" + "o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com\r\n" + "s=-\r\n" + "t=0 0\r\n" + "c=IN IP4 pc33.atlanta.com\r\n" + "m=audio 3456 RTP/AVP 0 1 3 99\r\n" + "a=rtpmap:0 PCMU/8000\r\n", + &create_msg1, + 0, + PJ_SUCCESS +}, +{ + /* Torture message from RFC 4475 + * 3.1.1.1 A short tortuous INVITE + */ + "INVITE sip:vivekg@chair-dnrc.example.com;unknownparam SIP/2.0\n" + "TO :\n" + " sip:vivekg@chair-dnrc.example.com ; tag = 1918181833n\n" + "from : \"J Rosenberg \\\\\\\"\" \n" + " ;\n" + " tag = 98asjd8\n" + "MaX-fOrWaRdS: 0068\n" + "Call-ID: wsinv.ndaksdj@192.0.2.1\n" + "Content-Length : 150\n" + "cseq: 0009\n" + " INVITE\n" + "Via : SIP / 2.0\n" + " /UDP\n" + " 192.0.2.2;rport;branch=390skdjuw\n" + "s :\n" + "NewFangledHeader: newfangled value\n" + " continued newfangled value\n" + "UnknownHeaderWithUnusualValue: ;;,,;;,;\n" + "Content-Type: application/sdp\n" + "Route:\n" + " \n" + "v: SIP / 2.0 / TCP spindle.example.com ;\n" + " branch = z9hG4bK9ikj8 ,\n" + " SIP / 2.0 / UDP 192.168.255.111 ; branch=\n" + " z9hG4bK30239\n" + "m:\"Quoted string \\\"\\\"\" ; newparam =\n" + " newvalue ;\n" + " secondparam ; q = 0.33\r\n" + "\r\n" + "v=0\r\n" + "o=mhandley 29739 7272939 IN IP4 192.0.2.3\r\n" + "s=-\r\n" + "c=IN IP4 192.0.2.4\r\n" + "t=0 0\r\n" + "m=audio 49217 RTP/AVP 0 12\r\n" + "m=video 3227 RTP/AVP 31\r\n" + "a=rtpmap:31 LPC\r\n", + NULL, + 0, + PJ_SUCCESS +}, +{ + /* Torture message from RFC 4475 + * 3.1.1.2 Wide Range of Valid Characters + */ + "!interesting-Method0123456789_*+`.%indeed'~ sip:1_unusual.URI~(to-be!sure)&isn't+it$/crazy?,/;;*:&it+has=1,weird!*pas$wo~d_too.(doesn't-it)@example.com SIP/2.0\n" + "Via: SIP/2.0/UDP host1.example.com;rport;branch=z9hG4bK-.!%66*_+`'~\n" + "To: \"BEL:\\\x07 NUL:\\\x00 DEL:\\\x7F\" \n" + "From: token1~` token2'+_ token3*%!.- ;fromParam''~+*_!.-%=\"\xD1\x80\xD0\xB0\xD0\xB1\xD0\xBE\xD1\x82\xD0\xB0\xD1\x8E\xD1\x89\xD0\xB8\xD0\xB9\";tag=_token~1'+`*%!-.\n" + "Call-ID: intmeth.word%ZK-!.*_+'@word`~)(><:\\/\"][?}{\n" + "CSeq: 139122385 !interesting-Method0123456789_*+`.%indeed'~\n" + "Max-Forwards: 255\n" + "extensionHeader-!.%*+_`'~: \xEF\xBB\xBF\xE5\xA4\xA7\xE5\x81\x9C\xE9\x9B\xBB\n" + "Content-Length: 0\r\n\r\n", + NULL, + 641, + PJ_SUCCESS +}, +{ + /* Torture message from RFC 4475 + * 3.1.1.3 Valid Use of the % Escaping Mechanism + */ + "INVITE sip:sips%3Auser%40example.com@example.net SIP/2.0\n" + "To: sip:%75se%72@example.com\n" + "From: ;tag=1234\n" + "Max-Forwards: 87\n" + "i: esc01.239409asdfakjkn23onasd0-3234\n" + "CSeq: 234234 INVITE\n" + "Via: SIP/2.0/UDP host5.example.net;rport;branch=z9hG4bKkdjuw\n" + "C: application/sdp\n" + "Contact:\n" + " \n" + "Content-Length: 150\r\n" + "\r\n" + "v=0\r\n" + "o=mhandley 29739 7272939 IN IP4 192.0.2.1\r\n" + "s=-\r\n" + "c=IN IP4 192.0.2.1\r\n" + "t=0 0\r\n" + "m=audio 49217 RTP/AVP 0 12\r\n" + "m=video 3227 RTP/AVP 31\r\n" + "a=rtpmap:31 LPC\r\n", + NULL, + 0, + PJ_SUCCESS +}, +{ + /* Torture message from RFC 4475 + * 3.1.1.4 Escaped Nulls in URIs + */ + "REGISTER sip:example.com SIP/2.0\r\n" + "To: sip:null-%00-null@example.com\r\n" + "From: sip:null-%00-null@example.com;tag=839923423\r\n" + "Max-Forwards: 70\r\n" + "Call-ID: escnull.39203ndfvkjdasfkq3w4otrq0adsfdfnavd\r\n" + "CSeq: 14398234 REGISTER\r\n" + "Via: SIP/2.0/UDP host5.example.com;rport;branch=z9hG4bKkdjuw\r\n" + "Contact: \r\n" + "Contact: \r\n" + "L:0\r\n" + "\r\n", + NULL, + 0, + PJ_SUCCESS +}, +{ + /* Torture message from RFC 4475 + * 3.1.1.5 Use of % When It Is Not an Escape + */ + "RE%47IST%45R sip:registrar.example.com SIP/2.0\r\n" + "To: \"%Z%45\" \r\n" + "From: \"%Z%45\" ;tag=f232jadfj23\r\n" + "Call-ID: esc02.asdfnqwo34rq23i34jrjasdcnl23nrlknsdf\r\n" + "Via: SIP/2.0/TCP host.example.com;rport;branch=z9hG4bK209%fzsnel234\r\n" + "CSeq: 29344 RE%47IST%45R\r\n" + "Max-Forwards: 70\r\n" + "Contact: \r\n" + "C%6Fntact: \r\n" + "Contact: \r\n" + "l: 0\r\n" + "\r\n", + NULL, + 0, + PJ_SUCCESS +} +}; + +static struct +{ + int flag; + pj_highprec_t detect_len, parse_len, print_len; + pj_timestamp detect_time, parse_time, print_time; +} var; + +static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry ) +{ + pjsip_msg *parsed_msg, *ref_msg = NULL; + static pjsip_msg *print_msg; + pj_status_t status = PJ_SUCCESS; + int len; + pj_str_t str1, str2; + pjsip_hdr *hdr1, *hdr2; + pj_timestamp t1, t2; + pjsip_parser_err_report err_list; + pj_size_t msg_size; + char msgbuf1[PJSIP_MAX_PKT_LEN]; + char msgbuf2[PJSIP_MAX_PKT_LEN]; + enum { BUFLEN = 512 }; + + if (entry->len==0) + entry->len = pj_ansi_strlen(entry->msg); + + if (var.flag & FLAG_PARSE_ONLY) + goto parse_msg; + + if (var.flag & FLAG_PRINT_ONLY) { + if (print_msg == NULL) + print_msg = entry->creator(pool); + goto print_msg; + } + + /* Detect message. */ + var.detect_len = var.detect_len + entry->len; + pj_get_timestamp(&t1); + status = pjsip_find_msg(entry->msg, entry->len, PJ_FALSE, &msg_size); + if (status != PJ_SUCCESS) { + if (status!=PJSIP_EPARTIALMSG || + entry->expected_status!=STATUS_PARTIAL) + { + app_perror(" error: unable to detect message", status); + return -5; + } + } + if (msg_size != entry->len) { + PJ_LOG(3,(THIS_FILE, " error: size mismatch")); + return -6; + } + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&var.detect_time, &t2); + + if (var.flag & FLAG_DETECT_ONLY) + return PJ_SUCCESS; + + /* Parse message. */ +parse_msg: + var.parse_len = var.parse_len + entry->len; + pj_get_timestamp(&t1); + pj_list_init(&err_list); + parsed_msg = pjsip_parse_msg(pool, entry->msg, entry->len, &err_list); + if (parsed_msg == NULL) { + if (entry->expected_status != STATUS_SYNTAX_ERROR) { + status = -10; + if (err_list.next != &err_list) { + PJ_LOG(3,(THIS_FILE, " Syntax error in line %d col %d", + err_list.next->line, err_list.next->col)); + } + goto on_return; + } + } + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&var.parse_time, &t2); + + if ((var.flag & FLAG_PARSE_ONLY) || entry->creator==NULL) + return PJ_SUCCESS; + + /* Create reference message. */ + ref_msg = entry->creator(pool); + + /* Create buffer for comparison. */ + str1.ptr = (char*)pj_pool_alloc(pool, BUFLEN); + str2.ptr = (char*)pj_pool_alloc(pool, BUFLEN); + + /* Compare message type. */ + if (parsed_msg->type != ref_msg->type) { + status = -20; + goto on_return; + } + + /* Compare request or status line. */ + if (parsed_msg->type == PJSIP_REQUEST_MSG) { + pjsip_method *m1 = &parsed_msg->line.req.method; + pjsip_method *m2 = &ref_msg->line.req.method; + + if (pjsip_method_cmp(m1, m2) != 0) { + status = -30; + goto on_return; + } + status = pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, + parsed_msg->line.req.uri, + ref_msg->line.req.uri); + if (status != PJ_SUCCESS) { + app_perror(" error: request URI mismatch", status); + status = -31; + goto on_return; + } + } else { + if (parsed_msg->line.status.code != ref_msg->line.status.code) { + PJ_LOG(3,(THIS_FILE, " error: status code mismatch")); + status = -32; + goto on_return; + } + if (pj_strcmp(&parsed_msg->line.status.reason, + &ref_msg->line.status.reason) != 0) + { + PJ_LOG(3,(THIS_FILE, " error: status text mismatch")); + status = -33; + goto on_return; + } + } + + /* Compare headers. */ + hdr1 = parsed_msg->hdr.next; + hdr2 = ref_msg->hdr.next; + + while (hdr1 != &parsed_msg->hdr && hdr2 != &ref_msg->hdr) { + len = hdr1->vptr->print_on(hdr1, str1.ptr, BUFLEN); + if (len < 1) { + status = -40; + goto on_return; + } + str1.ptr[len] = '\0'; + str1.slen = len; + + len = hdr2->vptr->print_on(hdr2, str2.ptr, BUFLEN); + if (len < 1) { + status = -50; + goto on_return; + } + str2.ptr[len] = '\0'; + str2.slen = len; + + if (pj_strcmp(&str1, &str2) != 0) { + status = -60; + PJ_LOG(3,(THIS_FILE, " error: header string mismatch:\n" + " h1='%s'\n" + " h2='%s'\n", + str1.ptr, str2.ptr)); + goto on_return; + } + + hdr1 = hdr1->next; + hdr2 = hdr2->next; + } + + if (hdr1 != &parsed_msg->hdr || hdr2 != &ref_msg->hdr) { + status = -70; + goto on_return; + } + + /* Compare body? */ + if (parsed_msg->body==NULL && ref_msg->body==NULL) + goto print_msg; + + /* Compare msg body length. */ + if (parsed_msg->body->len != ref_msg->body->len) { + status = -80; + goto on_return; + } + + /* Compare msg body content type. */ + if (pj_strcmp(&parsed_msg->body->content_type.type, + &ref_msg->body->content_type.type) != 0) { + status = -90; + goto on_return; + } + if (pj_strcmp(&parsed_msg->body->content_type.subtype, + &ref_msg->body->content_type.subtype) != 0) { + status = -100; + goto on_return; + } + + /* Compare body content. */ + str1.slen = parsed_msg->body->print_body(parsed_msg->body, + msgbuf1, sizeof(msgbuf1)); + if (str1.slen < 1) { + status = -110; + goto on_return; + } + str1.ptr = msgbuf1; + + str2.slen = ref_msg->body->print_body(ref_msg->body, + msgbuf2, sizeof(msgbuf2)); + if (str2.slen < 1) { + status = -120; + goto on_return; + } + str2.ptr = msgbuf2; + + if (pj_strcmp(&str1, &str2) != 0) { + status = -140; + goto on_return; + } + + /* Print message. */ +print_msg: + var.print_len = var.print_len + entry->len; + pj_get_timestamp(&t1); + if (var.flag && FLAG_PRINT_ONLY) + ref_msg = print_msg; + len = pjsip_msg_print(ref_msg, msgbuf1, PJSIP_MAX_PKT_LEN); + if (len < 1) { + status = -150; + goto on_return; + } + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&var.print_time, &t2); + + + status = PJ_SUCCESS; + +on_return: + return status; +} + + +static pjsip_msg *create_msg0(pj_pool_t *pool) +{ + + pjsip_msg *msg; + pjsip_name_addr *name_addr; + pjsip_sip_uri *url; + pjsip_fromto_hdr *fromto; + pjsip_cid_hdr *cid; + pjsip_clen_hdr *clen; + pjsip_cseq_hdr *cseq; + pjsip_contact_hdr *contact; + pjsip_ctype_hdr *ctype; + pjsip_routing_hdr *routing; + pjsip_via_hdr *via; + pjsip_generic_string_hdr *generic; + pj_str_t str; + + msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG); + + /* "INVITE sip:user@foo SIP/2.0\n" */ + pjsip_method_set(&msg->line.req.method, PJSIP_INVITE_METHOD); + url = pjsip_sip_uri_create(pool, 0); + msg->line.req.uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "user"); + pj_strdup2(pool, &url->host, "foo"); + + /* "From: Hi I'm Joe ;tag=123457890123456\r" */ + fromto = pjsip_from_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto); + pj_strdup2(pool, &fromto->tag, "123457890123456"); + name_addr = pjsip_name_addr_create(pool); + fromto->uri = (pjsip_uri*)name_addr; + pj_strdup2(pool, &name_addr->display, "Hi I'm Joe"); + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "joe.user"); + pj_strdup2(pool, &url->host, "bar.otherdomain.com"); + + /* "To: Fellow User \r\n" */ + fromto = pjsip_to_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto); + name_addr = pjsip_name_addr_create(pool); + fromto->uri = (pjsip_uri*)name_addr; + pj_strdup2(pool, &name_addr->display, "Fellow User"); + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "user"); + pj_strdup2(pool, &url->host, "foo.bar.domain.com"); + + /* "Call-ID: 12345678901234567890@bar\r\n" */ + cid = pjsip_cid_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)cid); + pj_strdup2(pool, &cid->id, "12345678901234567890@bar"); + + /* "Content-Length: 0\r\n" */ + clen = pjsip_clen_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)clen); + clen->len = 0; + + /* "CSeq: 123456 INVITE\n" */ + cseq = pjsip_cseq_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)cseq); + cseq->cseq = 123456; + pjsip_method_set(&cseq->method, PJSIP_INVITE_METHOD); + + /* "Contact: ;q=0.5;expires=3600*/ + contact = pjsip_contact_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); + contact->q1000 = 500; + contact->expires = 3600; + name_addr = pjsip_name_addr_create(pool); + contact->uri = (pjsip_uri*)name_addr; + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "joe"); + pj_strdup2(pool, &url->host, "bar"); + + /*, sip:user@host;q=0.500\r" */ + contact = pjsip_contact_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); + contact->q1000 = 500; + name_addr = pjsip_name_addr_create(pool); + contact->uri = (pjsip_uri*)name_addr; + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "user"); + pj_strdup2(pool, &url->host, "host"); + + /* " ,sip:user2@host2\n" */ + contact = pjsip_contact_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); + name_addr = pjsip_name_addr_create(pool); + contact->uri = (pjsip_uri*)name_addr; + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "user2"); + pj_strdup2(pool, &url->host, "host2"); + + /* "Content-Type: text/html; charset=ISO-8859-4\r" */ + ctype = pjsip_ctype_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)ctype); + pj_strdup2(pool, &ctype->media.type, "text"); + pj_strdup2(pool, &ctype->media.subtype, "html"); + pj_strdup2(pool, &ctype->media.param, ";charset=ISO-8859-4"); + + /* "Route: ,\r\n" */ + routing = pjsip_route_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); + url = pjsip_sip_uri_create(pool, 0); + routing->name_addr.uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com"); + url->lr_param = 1; + + /* " \r" */ + routing = pjsip_route_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); + url = pjsip_sip_uri_create(pool, 0); + routing->name_addr.uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->host, "server10.biloxi.com"); + url->lr_param = 1; + + /* "Record-Route: ,\r\n" */ + routing = pjsip_rr_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); + url = pjsip_sip_uri_create(pool, 0); + routing->name_addr.uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->host, "server10.biloxi.com"); + url->lr_param = 0; + + /* " \n" */ + routing = pjsip_rr_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); + url = pjsip_sip_uri_create(pool, 0); + routing->name_addr.uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com"); + url->lr_param = 1; + + /* "Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c230\n" */ + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + pj_strdup2(pool, &via->transport, "SCTP"); + pj_strdup2(pool, &via->sent_by.host, "bigbox3.site3.atlanta.com"); + pj_strdup2(pool, &via->branch_param, "z9hG4bK77ef4c230"); + + /* "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n" + " ;received=192.0.2.1\r\n" */ + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + pj_strdup2(pool, &via->transport, "UDP"); + pj_strdup2(pool, &via->sent_by.host, "pc33.atlanta.com"); + pj_strdup2(pool, &via->branch_param, "z9hG4bKnashds8"); + pj_strdup2(pool, &via->recvd_param, "192.0.2.1"); + + + /* "Via: SIP/2.0/UDP 10.2.1.1, */ + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + pj_strdup2(pool, &via->transport, "UDP"); + pj_strdup2(pool, &via->sent_by.host, "10.2.1.1"); + + + /*SIP/2.0/TCP 192.168.1.1\n" */ + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + pj_strdup2(pool, &via->transport, "TCP"); + pj_strdup2(pool, &via->sent_by.host, "192.168.1.1"); + + /* "Organization: \r" */ + str.ptr = "Organization"; + str.slen = 12; + generic = pjsip_generic_string_hdr_create(pool, &str, NULL); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); + generic->hvalue.ptr = NULL; + generic->hvalue.slen = 0; + + /* "Max-Forwards: 70\n" */ + str.ptr = "Max-Forwards"; + str.slen = 12; + generic = pjsip_generic_string_hdr_create(pool, &str, NULL); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); + str.ptr = "70"; + str.slen = 2; + generic->hvalue = str; + + /* "X-Header: \r\n" */ + str.ptr = "X-Header"; + str.slen = 8; + generic = pjsip_generic_string_hdr_create(pool, &str, NULL); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); + str.ptr = NULL; + str.slen = 0; + generic->hvalue = str; + + /* P-Associated-URI:\r\n */ + str.ptr = "P-Associated-URI"; + str.slen = 16; + generic = pjsip_generic_string_hdr_create(pool, &str, NULL); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); + str.ptr = NULL; + str.slen = 0; + generic->hvalue = str; + + return msg; +} + +static pjsip_msg *create_msg1(pj_pool_t *pool) +{ + pjsip_via_hdr *via; + pjsip_route_hdr *route; + pjsip_name_addr *name_addr; + pjsip_sip_uri *url; + pjsip_max_fwd_hdr *max_fwd; + pjsip_to_hdr *to; + pjsip_from_hdr *from; + pjsip_contact_hdr *contact; + pjsip_ctype_hdr *ctype; + pjsip_cid_hdr *cid; + pjsip_clen_hdr *clen; + pjsip_cseq_hdr *cseq; + pjsip_msg *msg = pjsip_msg_create(pool, PJSIP_RESPONSE_MSG); + pjsip_msg_body *body; + + //"SIP/2.0 200 OK\r\n" + msg->line.status.code = 200; + msg->line.status.reason = pj_str("OK"); + + //"Via: SIP/2.0/SCTP server10.biloxi.com;branch=z9hG4bKnashds8;rport;received=192.0.2.1\r\n" + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + via->transport = pj_str("SCTP"); + via->sent_by.host = pj_str("server10.biloxi.com"); + via->branch_param = pj_str("z9hG4bKnashds8"); + via->rport_param = 0; + via->recvd_param = pj_str("192.0.2.1"); + + //"Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2\r\n" + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + via->transport = pj_str("UDP"); + via->sent_by.host = pj_str("bigbox3.site3.atlanta.com"); + via->branch_param = pj_str("z9hG4bK77ef4c2312983.1"); + via->recvd_param = pj_str("192.0.2.2"); + + //"Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds ;received=192.0.2.3\r\n" + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + via->transport = pj_str("UDP"); + via->sent_by.host = pj_str("pc33.atlanta.com"); + via->branch_param = pj_str("z9hG4bK776asdhds"); + via->recvd_param = pj_str("192.0.2.3"); + + //"Route: \r\n" + route = pjsip_route_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)route); + url = pjsip_sip_uri_create(pool, PJ_FALSE); + route->name_addr.uri = (pjsip_uri*)url; + url->host = pj_str("proxy.sipprovider.com"); + + //"Route: \r\n" + route = pjsip_route_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)route); + url = pjsip_sip_uri_create(pool, PJ_FALSE); + route->name_addr.uri = (pjsip_uri*)url; + url->host = pj_str("proxy.supersip.com"); + url->port = 5060; + + //"Max-Forwards: 70\r\n" + max_fwd = pjsip_max_fwd_hdr_create(pool, 70); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)max_fwd); + + //"To: Bob ;tag=a6c85cf\r\n" + to = pjsip_to_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)to); + name_addr = pjsip_name_addr_create(pool); + name_addr->display = pj_str("Bob"); + to->uri = (pjsip_uri*)name_addr; + url = pjsip_sip_uri_create(pool, PJ_FALSE); + name_addr->uri = (pjsip_uri*)url; + url->user = pj_str("bob"); + url->host = pj_str("biloxi.com"); + to->tag = pj_str("a6c85cf"); + + //"From: Alice ;tag=1928301774\r\n" + from = pjsip_from_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)from); + name_addr = pjsip_name_addr_create(pool); + name_addr->display = pj_str("Alice"); + from->uri = (pjsip_uri*)name_addr; + url = pjsip_sip_uri_create(pool, PJ_FALSE); + name_addr->uri = (pjsip_uri*)url; + url->user = pj_str("alice"); + url->host = pj_str("atlanta.com"); + from->tag = pj_str("1928301774"); + + //"Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n" + cid = pjsip_cid_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)cid); + cid->id = pj_str("a84b4c76e66710@pc33.atlanta.com"); + + //"CSeq: 314159 INVITE\r\n" + cseq = pjsip_cseq_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)cseq); + cseq->cseq = 314159; + pjsip_method_set(&cseq->method, PJSIP_INVITE_METHOD); + + //"Contact: \r\n" + contact = pjsip_contact_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); + name_addr = pjsip_name_addr_create(pool); + contact->uri = (pjsip_uri*)name_addr; + url = pjsip_sip_uri_create(pool, PJ_TRUE); + name_addr->uri = (pjsip_uri*)url; + url->user = pj_str("bob"); + url->host = pj_str("192.0.2.4"); + + //"Content-Type: application/sdp\r\n" + ctype = pjsip_ctype_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)ctype); + ctype->media.type = pj_str("application"); + ctype->media.subtype = pj_str("sdp"); + + //"Content-Length: 150\r\n" + clen = pjsip_clen_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)clen); + clen->len = 150; + + // Body + body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body); + msg->body = body; + body->content_type.type = pj_str("application"); + body->content_type.subtype = pj_str("sdp"); + body->data = (void*) + "v=0\r\n" + "o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com\r\n" + "s=-\r\n" + "t=0 0\r\n" + "c=IN IP4 pc33.atlanta.com\r\n" + "m=audio 3456 RTP/AVP 0 1 3 99\r\n" + "a=rtpmap:0 PCMU/8000\r\n"; + body->len = pj_ansi_strlen((const char*) body->data); + body->print_body = &pjsip_print_text_body; + + return msg; +} + +/*****************************************************************************/ + +static pj_status_t simple_test(void) +{ + unsigned i; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " simple test..")); + for (i=0; i" + +#define HDR_FLAG_PARSE_FAIL 1 +#define HDR_FLAG_DONT_PRINT 2 + +struct hdr_test_t +{ + char *hname; + char *hshort_name; + char *hcontent; + int (*test)(pjsip_hdr*); + unsigned flags; +} hdr_test_data[] = +{ + { + /* Empty Accept */ + "Accept", NULL, + "", + &hdr_test_accept0 + }, + + { + /* Overflowing generic string header */ + "Accept", NULL, + "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ + "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ + "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ + "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ + "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ + "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ + "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, " \ + "a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a", + &hdr_test_success, + HDR_FLAG_PARSE_FAIL + }, + + { + /* Normal Accept */ + "Accept", NULL, + "application/*, text/plain", + &hdr_test_accept1 + }, + + { + /* Accept with params */ + "Accept", NULL, + "application/*;p1=v1, text/plain", + &hdr_test_accept2 + }, + + { + /* Empty Allow */ + "Allow", NULL, + "", + &hdr_test_allow0, + }, + + { + /* Authorization, testing which params should be quoted */ + "Authorization", NULL, + "Digest username=\"username\", realm=\"realm\", nonce=\"nonce\", " \ + "uri=\"sip:domain\", response=\"RESPONSE\", algorithm=MD5, " \ + "cnonce=\"CNONCE\", opaque=\"OPAQUE\", qop=auth, nc=00000001", + &hdr_test_authorization + }, + + { + /* Call ID */ + "Call-ID", "i", + "-.!%*_+`'~()<>:\\\"/[]?{}", + &hdr_test_cid, + }, + + { + /* Parameter belong to hparam */ + "Contact", "m", + SIMPLE_ADDR_SPEC ";p1=v1", + &hdr_test_contact0, + HDR_FLAG_DONT_PRINT + }, + + { + /* generic-param in Contact header */ + "Contact", "m", + NAME_ADDR ";" GENERIC_PARAM, + &hdr_test_contact1 + }, + + { + /* q=0 parameter in Contact header */ + "Contact", "m", + NAME_ADDR ";q=0", + &hdr_test_contact_q0, + HDR_FLAG_DONT_PRINT + }, + + { + /* q=0.5 parameter in Contact header */ + "Contact", "m", + NAME_ADDR ";q=0.5", + &hdr_test_contact_q1 + }, + + { + /* q=1 parameter in Contact header */ + "Contact", "m", + NAME_ADDR ";q=1", + &hdr_test_contact_q2 + }, + + { + /* q=1.0 parameter in Contact header */ + "Contact", "m", + NAME_ADDR ";q=1.0", + &hdr_test_contact_q3, + HDR_FLAG_DONT_PRINT + }, + + { + /* q=1.1 parameter in Contact header */ + "Contact", "m", + NAME_ADDR ";q=1.15", + &hdr_test_contact_q4 + }, + + { + /* Content-Length */ + "Content-Length", "l", + "10", + &hdr_test_content_length + }, + + { + /* Content-Type, with generic-param */ + "Content-Type", "c", + "application/sdp" ";" GENERIC_PARAM, + &hdr_test_content_type, + HDR_FLAG_DONT_PRINT + }, + + { + /* From, testing parameters and generic-param */ + "From", "f", + NAME_ADDR ";" GENERIC_PARAM, + &hdr_test_from + }, + + { + /* Proxy-Authenticate, testing which params should be quoted */ + "Proxy-Authenticate", NULL, + "Digest realm=\"realm\",domain=\"sip:domain\",nonce=\"nonce\"," \ + "opaque=\"opaque\",stale=true,algorithm=MD5,qop=\"auth\"", + &hdr_test_proxy_authenticate + }, + + { + /* Record-Route, param belong to header */ + "Record-Route", NULL, + NAME_ADDR ";" GENERIC_PARAM, + &hdr_test_record_route + }, + + { + /* Empty Supported */ + "Supported", "k", + "", + &hdr_test_supported, + }, + + { + /* To */ + "To", "t", + NAME_ADDR ";" GENERIC_PARAM, + &hdr_test_to + }, + + { + /* Via */ + "Via", "v", + "SIP/2.0/XYZ host" ";" GENERIC_PARAM, + &hdr_test_via + }, + + { + /* Via with IPv6 */ + "Via", "v", + "SIP/2.0/UDP [::1]", + &hdr_test_via_ipv6_1 + }, + + { + /* Via with IPv6 */ + "Via", "v", + "SIP/2.0/UDP [::1]:5061", + &hdr_test_via_ipv6_2 + }, + + { + /* Via with IPv6 */ + "Via", "v", + "SIP/2.0/UDP [::1];rport=5061;received=::2", + &hdr_test_via_ipv6_3 + }, + + { + /* Retry-After header with comment */ + "Retry-After", NULL, + "10(Already Pending Register)", + &hdr_test_retry_after1 + }, + + { + /* Non-ASCII UTF-8 characters in Subject */ + "Subject", NULL, + "\xC0\x81", + &hdr_test_subject_utf + } +}; + +static int hdr_test_success(pjsip_hdr *h) +{ + PJ_UNUSED_ARG(h); + return 0; +} + +/* "" */ +static int hdr_test_accept0(pjsip_hdr *h) +{ + pjsip_accept_hdr *hdr = (pjsip_accept_hdr*)h; + + if (h->type != PJSIP_H_ACCEPT) + return -1010; + + if (hdr->count != 0) + return -1020; + + return 0; +} + +/* "application/ *, text/plain\r\n" */ +static int hdr_test_accept1(pjsip_hdr *h) +{ + pjsip_accept_hdr *hdr = (pjsip_accept_hdr*)h; + + if (h->type != PJSIP_H_ACCEPT) + return -1110; + + if (hdr->count != 2) + return -1120; + + if (pj_strcmp2(&hdr->values[0], "application/*")) + return -1130; + + if (pj_strcmp2(&hdr->values[1], "text/plain")) + return -1140; + + return 0; +} + +/* "application/ *;p1=v1, text/plain\r\n" */ +static int hdr_test_accept2(pjsip_hdr *h) +{ + pjsip_accept_hdr *hdr = (pjsip_accept_hdr*)h; + + if (h->type != PJSIP_H_ACCEPT) + return -1210; + + if (hdr->count != 2) + return -1220; + + if (pj_strcmp2(&hdr->values[0], "application/*;p1=v1")) + return -1230; + + if (pj_strcmp2(&hdr->values[1], "text/plain")) + return -1240; + + return 0; +} + +/* "" */ +static int hdr_test_allow0(pjsip_hdr *h) +{ + pjsip_allow_hdr *hdr = (pjsip_allow_hdr*)h; + + if (h->type != PJSIP_H_ALLOW) + return -1310; + + if (hdr->count != 0) + return -1320; + + return 0; + +} + + +/* + "Digest username=\"username\", realm=\"realm\", nonce=\"nonce\", " \ + "uri=\"sip:domain\", response=\"RESPONSE\", algorithm=MD5, " \ + "cnonce=\"CNONCE\", opaque=\"OPAQUE\", qop=auth, nc=00000001", + */ +static int hdr_test_authorization(pjsip_hdr *h) +{ + pjsip_authorization_hdr *hdr = (pjsip_authorization_hdr*)h; + + if (h->type != PJSIP_H_AUTHORIZATION) + return -1410; + + if (pj_strcmp2(&hdr->scheme, "Digest")) + return -1420; + + if (pj_strcmp2(&hdr->credential.digest.username, "username")) + return -1421; + + if (pj_strcmp2(&hdr->credential.digest.realm, "realm")) + return -1422; + + if (pj_strcmp2(&hdr->credential.digest.nonce, "nonce")) + return -1423; + + if (pj_strcmp2(&hdr->credential.digest.uri, "sip:domain")) + return -1424; + + if (pj_strcmp2(&hdr->credential.digest.response, "RESPONSE")) + return -1425; + + if (pj_strcmp2(&hdr->credential.digest.algorithm, "MD5")) + return -1426; + + if (pj_strcmp2(&hdr->credential.digest.cnonce, "CNONCE")) + return -1427; + + if (pj_strcmp2(&hdr->credential.digest.opaque, "OPAQUE")) + return -1428; + + if (pj_strcmp2(&hdr->credential.digest.qop, "auth")) + return -1429; + + if (pj_strcmp2(&hdr->credential.digest.nc, "00000001")) + return -1430; + + return 0; +} + + +/* + "-.!%*_+`'~()<>:\\\"/[]?{}\r\n" + */ +static int hdr_test_cid(pjsip_hdr *h) +{ + pjsip_cid_hdr *hdr = (pjsip_cid_hdr*)h; + + if (h->type != PJSIP_H_CALL_ID) + return -1510; + + if (pj_strcmp2(&hdr->id, "-.!%*_+`'~()<>:\\\"/[]?{}")) + return -1520; + + return 0; +} + +/* + #define SIMPLE_ADDR_SPEC "sip:host" + */ +static int test_simple_addr_spec(pjsip_uri *uri) +{ + pjsip_sip_uri *sip_uri = (pjsip_sip_uri *)pjsip_uri_get_uri(uri); + + if (!PJSIP_URI_SCHEME_IS_SIP(uri)) + return -900; + + if (pj_strcmp2(&sip_uri->host, "host")) + return -910; + + if (sip_uri->port != 0) + return -920; + + return 0; +} + +/* +#define PARAM_CHAR "][/:&+$" +#define SIMPLE_ADDR_SPEC "sip:host" +#define ADDR_SPEC SIMPLE_ADDR_SPEC ";"PARAM_CHAR"="PARAM_CHAR ";p1=\";\"" +#define NAME_ADDR "<" ADDR_SPEC ">" + */ +static int nameaddr_test(void *uri) +{ + pjsip_sip_uri *sip_uri=(pjsip_sip_uri *)pjsip_uri_get_uri((pjsip_uri*)uri); + pjsip_param *param; + int rc; + + if (!PJSIP_URI_SCHEME_IS_SIP(uri)) + return -930; + + rc = test_simple_addr_spec((pjsip_uri*)sip_uri); + if (rc != 0) + return rc; + + if (pj_list_size(&sip_uri->other_param) != 2) + return -940; + + param = sip_uri->other_param.next; + + if (pj_strcmp2(¶m->name, PARAM_CHAR)) + return -942; + + if (pj_strcmp2(¶m->value, PARAM_CHAR)) + return -943; + + param = param->next; + if (pj_strcmp2(¶m->name, "p1")) + return -942; + if (pj_strcmp2(¶m->value, "\";\"")) + return -943; + + return 0; +} + +/* +#define GENERIC_PARAM "p0=a;p1=\"ab:;cd\";p2=ab%3acd;p3" + */ +static int generic_param_test(pjsip_param *param_head) +{ + pjsip_param *param; + + if (pj_list_size(param_head) != 4) + return -950; + + param = param_head->next; + + if (pj_strcmp2(¶m->name, "p0")) + return -952; + if (pj_strcmp2(¶m->value, "a")) + return -953; + + param = param->next; + if (pj_strcmp2(¶m->name, "p1")) + return -954; + if (pj_strcmp2(¶m->value, "\"ab:;cd\"")) + return -955; + + param = param->next; + if (pj_strcmp2(¶m->name, "p2")) + return -956; + if (pj_strcmp2(¶m->value, "ab:cd")) + return -957; + + param = param->next; + if (pj_strcmp2(¶m->name, "p3")) + return -958; + if (pj_strcmp2(¶m->value, "")) + return -959; + + return 0; +} + + + +/* + SIMPLE_ADDR_SPEC ";p1=v1\r\n" + */ +static int hdr_test_contact0(pjsip_hdr *h) +{ + pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; + pjsip_param *param; + int rc; + + if (h->type != PJSIP_H_CONTACT) + return -1610; + + rc = test_simple_addr_spec(hdr->uri); + if (rc != 0) + return rc; + + if (pj_list_size(&hdr->other_param) != 1) + return -1620; + + param = hdr->other_param.next; + + if (pj_strcmp2(¶m->name, "p1")) + return -1630; + + if (pj_strcmp2(¶m->value, "v1")) + return -1640; + + return 0; +} + +/* + NAME_ADDR GENERIC_PARAM "\r\n", + */ +static int hdr_test_contact1(pjsip_hdr *h) +{ + pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; + int rc; + + if (h->type != PJSIP_H_CONTACT) + return -1710; + + rc = nameaddr_test(hdr->uri); + if (rc != 0) + return rc; + + rc = generic_param_test(&hdr->other_param); + if (rc != 0) + return rc; + + return 0; +} + +/* + NAME_ADDR ";q=0" + */ +static int hdr_test_contact_q0(pjsip_hdr *h) +{ + pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; + int rc; + + if (h->type != PJSIP_H_CONTACT) + return -1710; + + rc = nameaddr_test(hdr->uri); + if (rc != 0) + return rc; + + if (hdr->q1000 != 0) + return -1711; + + return 0; +} + +/* + NAME_ADDR ";q=0.5" + */ +static int hdr_test_contact_q1(pjsip_hdr *h) +{ + pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; + int rc; + + if (h->type != PJSIP_H_CONTACT) + return -1710; + + rc = nameaddr_test(hdr->uri); + if (rc != 0) + return rc; + + if (hdr->q1000 != 500) + return -1712; + + return 0; +} + +/* + NAME_ADDR ";q=1" + */ +static int hdr_test_contact_q2(pjsip_hdr *h) +{ + pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; + int rc; + + if (h->type != PJSIP_H_CONTACT) + return -1710; + + rc = nameaddr_test(hdr->uri); + if (rc != 0) + return rc; + + if (hdr->q1000 != 1000) + return -1713; + + return 0; +} + +/* + NAME_ADDR ";q=1.0" + */ +static int hdr_test_contact_q3(pjsip_hdr *h) +{ + pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; + int rc; + + if (h->type != PJSIP_H_CONTACT) + return -1710; + + rc = nameaddr_test(hdr->uri); + if (rc != 0) + return rc; + + if (hdr->q1000 != 1000) + return -1714; + + return 0; +} + +/* + NAME_ADDR ";q=1.15" + */ +static int hdr_test_contact_q4(pjsip_hdr *h) +{ + pjsip_contact_hdr *hdr = (pjsip_contact_hdr*)h; + int rc; + + if (h->type != PJSIP_H_CONTACT) + return -1710; + + rc = nameaddr_test(hdr->uri); + if (rc != 0) + return rc; + + if (hdr->q1000 != 1150) + return -1715; + + return 0; +} + +/* + "10" + */ +static int hdr_test_content_length(pjsip_hdr *h) +{ + pjsip_clen_hdr *hdr = (pjsip_clen_hdr*)h; + + if (h->type != PJSIP_H_CONTENT_LENGTH) + return -1810; + + if (hdr->len != 10) + return -1820; + + return 0; +} + +/* + "application/sdp" GENERIC_PARAM, + */ +static int hdr_test_content_type(pjsip_hdr *h) +{ + pjsip_ctype_hdr *hdr = (pjsip_ctype_hdr*)h; + + if (h->type != PJSIP_H_CONTENT_TYPE) + return -1910; + + if (pj_strcmp2(&hdr->media.type, "application")) + return -1920; + + if (pj_strcmp2(&hdr->media.subtype, "sdp")) + return -1930; + + /* Currently, if the media parameter contains escaped characters, + * pjsip will print the parameter unescaped. + */ + PJ_TODO(FIX_PARAMETER_IN_MEDIA_TYPE); + + if (pj_strcmp2(&hdr->media.param, ";" GENERIC_PARAM_PARSED)) + return -1940; + + return 0; +} + +/* + NAME_ADDR GENERIC_PARAM, + */ +static int hdr_test_from(pjsip_hdr *h) +{ + pjsip_from_hdr *hdr = (pjsip_from_hdr*)h; + int rc; + + if (h->type != PJSIP_H_FROM) + return -2010; + + rc = nameaddr_test(hdr->uri); + if (rc != 0) + return rc; + + rc = generic_param_test(&hdr->other_param); + if (rc != 0) + return rc; + + return 0; +} + +/* + "Digest realm=\"realm\", domain=\"sip:domain\", nonce=\"nonce\", " \ + "opaque=\"opaque\", stale=true, algorithm=MD5, qop=\"auth\"", + */ +static int hdr_test_proxy_authenticate(pjsip_hdr *h) +{ + pjsip_proxy_authenticate_hdr *hdr = (pjsip_proxy_authenticate_hdr*)h; + + if (h->type != PJSIP_H_PROXY_AUTHENTICATE) + return -2110; + + if (pj_strcmp2(&hdr->scheme, "Digest")) + return -2120; + + if (pj_strcmp2(&hdr->challenge.digest.realm, "realm")) + return -2130; + + if (pj_strcmp2(&hdr->challenge.digest.domain, "sip:domain")) + return -2140; + + if (pj_strcmp2(&hdr->challenge.digest.nonce, "nonce")) + return -2150; + + if (pj_strcmp2(&hdr->challenge.digest.opaque, "opaque")) + return -2160; + + if (hdr->challenge.digest.stale != 1) + return -2170; + + if (pj_strcmp2(&hdr->challenge.digest.algorithm, "MD5")) + return -2180; + + if (pj_strcmp2(&hdr->challenge.digest.qop, "auth")) + return -2190; + + return 0; +} + +/* + NAME_ADDR GENERIC_PARAM, + */ +static int hdr_test_record_route(pjsip_hdr *h) +{ + pjsip_rr_hdr *hdr = (pjsip_rr_hdr*)h; + int rc; + + if (h->type != PJSIP_H_RECORD_ROUTE) + return -2210; + + rc = nameaddr_test(&hdr->name_addr); + if (rc != 0) + return rc; + + rc = generic_param_test(&hdr->other_param); + if (rc != 0) + return rc; + + return 0; + +} + +/* + " \r\n" + */ +static int hdr_test_supported(pjsip_hdr *h) +{ + pjsip_supported_hdr *hdr = (pjsip_supported_hdr*)h; + + if (h->type != PJSIP_H_SUPPORTED) + return -2310; + + if (hdr->count != 0) + return -2320; + + return 0; +} + +/* + NAME_ADDR GENERIC_PARAM, + */ +static int hdr_test_to(pjsip_hdr *h) +{ + pjsip_to_hdr *hdr = (pjsip_to_hdr*)h; + int rc; + + if (h->type != PJSIP_H_TO) + return -2410; + + rc = nameaddr_test(hdr->uri); + if (rc != 0) + return rc; + + rc = generic_param_test(&hdr->other_param); + if (rc != 0) + return rc; + + return 0; +} + +/* + "SIP/2.0 host" GENERIC_PARAM + */ +static int hdr_test_via(pjsip_hdr *h) +{ + pjsip_via_hdr *hdr = (pjsip_via_hdr*)h; + int rc; + + if (h->type != PJSIP_H_VIA) + return -2510; + + if (pj_strcmp2(&hdr->transport, "XYZ")) + return -2515; + + if (pj_strcmp2(&hdr->sent_by.host, "host")) + return -2520; + + if (hdr->sent_by.port != 0) + return -2530; + + rc = generic_param_test(&hdr->other_param); + if (rc != 0) + return rc; + + return 0; +} + + +/* + "SIP/2.0/UDP [::1]" + */ +static int hdr_test_via_ipv6_1(pjsip_hdr *h) +{ + pjsip_via_hdr *hdr = (pjsip_via_hdr*)h; + + if (h->type != PJSIP_H_VIA) + return -2610; + + if (pj_strcmp2(&hdr->transport, "UDP")) + return -2615; + + if (pj_strcmp2(&hdr->sent_by.host, "::1")) + return -2620; + + if (hdr->sent_by.port != 0) + return -2630; + + return 0; +} + +/* "SIP/2.0/UDP [::1]:5061" */ +static int hdr_test_via_ipv6_2(pjsip_hdr *h) +{ + pjsip_via_hdr *hdr = (pjsip_via_hdr*)h; + + if (h->type != PJSIP_H_VIA) + return -2710; + + if (pj_strcmp2(&hdr->transport, "UDP")) + return -2715; + + if (pj_strcmp2(&hdr->sent_by.host, "::1")) + return -2720; + + if (hdr->sent_by.port != 5061) + return -2730; + + return 0; +} + +/* "SIP/2.0/UDP [::1];rport=5061;received=::2" */ +static int hdr_test_via_ipv6_3(pjsip_hdr *h) +{ + pjsip_via_hdr *hdr = (pjsip_via_hdr*)h; + + if (h->type != PJSIP_H_VIA) + return -2810; + + if (pj_strcmp2(&hdr->transport, "UDP")) + return -2815; + + if (pj_strcmp2(&hdr->sent_by.host, "::1")) + return -2820; + + if (hdr->sent_by.port != 0) + return -2830; + + if (pj_strcmp2(&hdr->recvd_param, "::2")) + return -2840; + + if (hdr->rport_param != 5061) + return -2850; + + return 0; +} + +/* "10(Already Pending Register)" */ +static int hdr_test_retry_after1(pjsip_hdr *h) +{ + pjsip_retry_after_hdr *hdr = (pjsip_retry_after_hdr*)h; + + if (h->type != PJSIP_H_RETRY_AFTER) + return -2910; + + if (hdr->ivalue != 10) + return -2920; + + if (pj_strcmp2(&hdr->comment, "Already Pending Register")) + return -2930; + + return 0; +} + +/* Subject: \xC0\x81 */ +static int hdr_test_subject_utf(pjsip_hdr *h) +{ + pjsip_subject_hdr *hdr = (pjsip_subject_hdr*)h; + + if (pj_strcmp2(&h->name, "Subject")) + return -2950; + + if (pj_strcmp2(&hdr->hvalue, "\xC0\x81")) + return -2960; + + return 0; +} + +static int hdr_test(void) +{ + unsigned i; + + PJ_LOG(3,(THIS_FILE, " testing header parsing..")); + + for (i=0; ihname); + len = strlen(test->hcontent); +#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0 + PJ_ASSERT_RETURN(len < sizeof(hcontent), PJSIP_EMSGTOOLONG); + strcpy(hcontent, test->hcontent); +#else + hcontent = test->hcontent; +#endif + + parsed_hdr1 = (pjsip_hdr*) pjsip_parse_hdr(pool, &hname, + hcontent, len, + &parsed_len); + if (parsed_hdr1 == NULL) { + if (test->flags & HDR_FLAG_PARSE_FAIL) { + pj_pool_release(pool); + continue; + } + PJ_LOG(3,(THIS_FILE, " error parsing header %s: %s", test->hname, test->hcontent)); + return -500; + } + + /* Test the parsing result */ + if (test->test && (rc=test->test(parsed_hdr1)) != 0) { + PJ_LOG(3,(THIS_FILE, " validation failed for header %s: %s", test->hname, test->hcontent)); + PJ_LOG(3,(THIS_FILE, " error code is %d", rc)); + return -502; + } + +#if 1 + /* Parse with hshortname, if present */ + if (test->hshort_name) { + hname = pj_str(test->hshort_name); + len = strlen(test->hcontent); +#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0 + PJ_ASSERT_RETURN(len < sizeof(hcontent), PJSIP_EMSGTOOLONG); + strcpy(hcontent, test->hcontent); +#else + hcontent = test->hcontent; +#endif + + parsed_hdr2 = (pjsip_hdr*) pjsip_parse_hdr(pool, &hname, hcontent, len, &parsed_len); + if (parsed_hdr2 == NULL) { + PJ_LOG(3,(THIS_FILE, " error parsing header %s: %s", test->hshort_name, test->hcontent)); + return -510; + } + } +#endif + + if (test->flags & HDR_FLAG_DONT_PRINT) { + pj_pool_release(pool); + continue; + } + + /* Print the original header */ + input = (char*) pj_pool_alloc(pool, 1024); + len = pj_ansi_snprintf(input, 1024, "%s: %s", test->hname, test->hcontent); + if (len < 1 || len >= 1024) + return -520; + + /* Print the parsed header*/ + output = (char*) pj_pool_alloc(pool, 1024); + len = pjsip_hdr_print_on(parsed_hdr1, output, 1024); + if (len < 1 || len >= 1024) { + PJ_LOG(3,(THIS_FILE, " header too long: %s: %s", test->hname, test->hcontent)); + return -530; + } + output[len] = 0; + + if (strcmp(input, output) != 0) { + PJ_LOG(3,(THIS_FILE, " header character by character comparison failed.")); + PJ_LOG(3,(THIS_FILE, " original header=|%s|", input)); + PJ_LOG(3,(THIS_FILE, " parsed header =|%s|", output)); + return -540; + } + + pj_pool_release(pool); + } + + return 0; +} + + +/*****************************************************************************/ + +int msg_test(void) +{ + enum { COUNT = 1, DETECT=0, PARSE=1, PRINT=2 }; + struct { + unsigned detect; + unsigned parse; + unsigned print; + } run[COUNT]; + unsigned i, max, avg_len; + char desc[250]; + pj_status_t status; + + status = hdr_test(); + if (status != 0) + return status; + + status = simple_test(); + if (status != PJ_SUCCESS) + return status; + +#if INCLUDE_BENCHMARKS + for (i=0; i max) max = run[i].detect; + + PJ_LOG(3,("", " Maximum message detection/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP messages " + "can be pre-parse by pjsip_find_msg() " + "per second (tested with %d message sets with " + "average message length of " + "%d bytes)", (int)PJ_ARRAY_SIZE(test_array), avg_len); + report_ival("msg-detect-per-sec", max, "msg/sec", desc); + + /* Print maximum parse/sec */ + for (i=0, max=0; i max) max = run[i].parse; + + PJ_LOG(3,("", " Maximum message parsing/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP messages " + "can be parsed by pjsip_parse_msg() " + "per second (tested with %d message sets with " + "average message length of " + "%d bytes)", (int)PJ_ARRAY_SIZE(test_array), avg_len); + report_ival("msg-parse-per-sec", max, "msg/sec", desc); + + /* Msg parsing bandwidth */ + report_ival("msg-parse-bandwidth-mb", avg_len*max/1000000, "MB/sec", + "Message parsing bandwidth in megabytes (number of megabytes" + " worth of SIP messages that can be parsed per second). " + "The value is derived from msg-parse-per-sec above."); + + + /* Print maximum print/sec */ + for (i=0, max=0; i max) max = run[i].print; + + PJ_LOG(3,("", " Maximum message print/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP messages " + "can be printed by pjsip_msg_print()" + " per second (tested with %d message sets with " + "average message length of " + "%d bytes)", (int)PJ_ARRAY_SIZE(test_array), avg_len); + + report_ival("msg-print-per-sec", max, "msg/sec", desc); + + /* Msg print bandwidth */ + report_ival("msg-printed-bandwidth-mb", avg_len*max/1000000, "MB/sec", + "Message print bandwidth in megabytes (total size of " + "SIP messages printed per second). " + "The value is derived from msg-print-per-sec above."); + +#endif /* INCLUDE_BENCHMARKS */ + + return PJ_SUCCESS; +} + + + + diff --git a/pjsip/src/test/regc_test.c b/pjsip/src/test/regc_test.c new file mode 100644 index 00000000..0d668782 --- /dev/null +++ b/pjsip/src/test/regc_test.c @@ -0,0 +1,1162 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ +#include "test.h" +#include +#include +#include + +#define THIS_FILE "regc_test.c" + + +/************************************************************************/ +/* A module to inject error into outgoing sending operation */ +static pj_status_t mod_send_on_tx_request(pjsip_tx_data *tdata); + +static struct +{ + pjsip_module mod; + unsigned count; + unsigned count_before_reject; +} send_mod = +{ + { + NULL, NULL, /* prev, next. */ + { "mod-send", 8 }, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + NULL, /* on_rx_request() */ + NULL, /* on_rx_response() */ + &mod_send_on_tx_request, /* on_tx_request. */ + NULL, /* on_tx_response() */ + NULL, /* on_tsx_state() */ + }, + 0, + 0xFFFF +}; + + +static pj_status_t mod_send_on_tx_request(pjsip_tx_data *tdata) +{ + PJ_UNUSED_ARG(tdata); + + if (++send_mod.count > send_mod.count_before_reject) + return PJ_ECANCELLED; + else + return PJ_SUCCESS; +}; + + +/************************************************************************/ +/* Registrar for testing */ +static pj_bool_t regs_rx_request(pjsip_rx_data *rdata); + +enum contact_op +{ + NONE, /* don't put Contact header */ + EXACT, /* return exact contact */ + MODIFIED, /* return modified Contact header */ +}; + +struct registrar_cfg +{ + pj_bool_t respond; /* should it respond at all */ + unsigned status_code; /* final response status code */ + pj_bool_t authenticate; /* should we authenticate? */ + enum contact_op contact_op; /* What should we do with Contact */ + unsigned expires_param; /* non-zero to put in expires param */ + unsigned expires; /* non-zero to put in Expires header*/ + + pj_str_t more_contacts; /* Additional Contact headers to put*/ +}; + +static struct registrar +{ + pjsip_module mod; + struct registrar_cfg cfg; + unsigned response_cnt; +} registrar = +{ + { + NULL, NULL, /* prev, next. */ + { "registrar", 9 }, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + ®s_rx_request, /* on_rx_request() */ + NULL, /* on_rx_response() */ + NULL, /* on_tx_request. */ + NULL, /* on_tx_response() */ + NULL, /* on_tsx_state() */ + } +}; + +static pj_bool_t regs_rx_request(pjsip_rx_data *rdata) +{ + pjsip_msg *msg = rdata->msg_info.msg; + pjsip_hdr hdr_list; + int code; + pj_status_t status; + + if (msg->line.req.method.id != PJSIP_REGISTER_METHOD) + return PJ_FALSE; + + if (!registrar.cfg.respond) + return PJ_TRUE; + + pj_list_init(&hdr_list); + + if (registrar.cfg.authenticate && + pjsip_msg_find_hdr(msg, PJSIP_H_AUTHORIZATION, NULL)==NULL) + { + pjsip_generic_string_hdr *hwww; + const pj_str_t hname = pj_str("WWW-Authenticate"); + const pj_str_t hvalue = pj_str("Digest realm=\"test\""); + + hwww = pjsip_generic_string_hdr_create(rdata->tp_info.pool, &hname, + &hvalue); + pj_list_push_back(&hdr_list, hwww); + + code = 401; + + } else { + if (registrar.cfg.contact_op == EXACT || + registrar.cfg.contact_op == MODIFIED) + { + pjsip_hdr *hsrc; + + for (hsrc=msg->hdr.next; hsrc!=&msg->hdr; hsrc=hsrc->next) { + pjsip_contact_hdr *hdst; + + if (hsrc->type != PJSIP_H_CONTACT) + continue; + + hdst = (pjsip_contact_hdr*) + pjsip_hdr_clone(rdata->tp_info.pool, hsrc); + + if (hdst->expires==0) + continue; + + if (registrar.cfg.contact_op == MODIFIED) { + if (PJSIP_URI_SCHEME_IS_SIP(hdst->uri) || + PJSIP_URI_SCHEME_IS_SIPS(hdst->uri)) + { + pjsip_sip_uri *sip_uri = (pjsip_sip_uri*) + pjsip_uri_get_uri(hdst->uri); + sip_uri->host = pj_str("x-modified-host"); + sip_uri->port = 1; + } + } + + if (registrar.cfg.expires_param) + hdst->expires = registrar.cfg.expires_param; + + pj_list_push_back(&hdr_list, hdst); + } + } + + if (registrar.cfg.more_contacts.slen) { + pjsip_generic_string_hdr *hcontact; + const pj_str_t hname = pj_str("Contact"); + + hcontact = pjsip_generic_string_hdr_create(rdata->tp_info.pool, &hname, + ®istrar.cfg.more_contacts); + pj_list_push_back(&hdr_list, hcontact); + } + + if (registrar.cfg.expires) { + pjsip_expires_hdr *hexp; + + hexp = pjsip_expires_hdr_create(rdata->tp_info.pool, + registrar.cfg.expires); + pj_list_push_back(&hdr_list, hexp); + } + + registrar.response_cnt++; + + code = registrar.cfg.status_code; + } + + status = pjsip_endpt_respond(endpt, NULL, rdata, code, NULL, + &hdr_list, NULL, NULL); + pj_assert(status == PJ_SUCCESS); + + return PJ_TRUE; +} + + +/************************************************************************/ +/* Client registration test session */ +struct client +{ + /* Result/expected result */ + int error; + int code; + pj_bool_t have_reg; + int expiration; + unsigned contact_cnt; + pj_bool_t auth; + + /* Commands */ + pj_bool_t destroy_on_cb; + + /* Status */ + pj_bool_t done; + + /* Additional results */ + int interval; + int next_reg; +}; + +/* regc callback */ +static void client_cb(struct pjsip_regc_cbparam *param) +{ + struct client *client = (struct client*) param->token; + pjsip_regc_info info; + pj_status_t status; + + client->done = PJ_TRUE; + + status = pjsip_regc_get_info(param->regc, &info); + pj_assert(status == PJ_SUCCESS); + + client->error = (param->status != PJ_SUCCESS); + client->code = param->code; + + if (client->error) + return; + + client->have_reg = info.auto_reg && info.interval>0 && + param->expiration>0; + client->expiration = param->expiration; + client->contact_cnt = param->contact_cnt; + client->interval = info.interval; + client->next_reg = info.next_reg; + + if (client->destroy_on_cb) + pjsip_regc_destroy(param->regc); +} + + +/* Generic client test session */ +static struct client client_result; +static int do_test(const char *title, + const struct registrar_cfg *srv_cfg, + const struct client *client_cfg, + const pj_str_t *registrar_uri, + unsigned contact_cnt, + const pj_str_t contacts[], + unsigned expires, + pj_bool_t leave_session, + pjsip_regc **p_regc) +{ + pjsip_regc *regc; + unsigned i; + const pj_str_t aor = pj_str(""); + pjsip_tx_data *tdata; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " %s", title)); + + /* Modify registrar settings */ + pj_memcpy(®istrar.cfg, srv_cfg, sizeof(*srv_cfg)); + + pj_bzero(&client_result, sizeof(client_result)); + client_result.destroy_on_cb = client_cfg->destroy_on_cb; + + status = pjsip_regc_create(endpt, &client_result, &client_cb, ®c); + if (status != PJ_SUCCESS) + return -100; + + status = pjsip_regc_init(regc, registrar_uri, &aor, &aor, contact_cnt, + contacts, expires ? expires : 60); + if (status != PJ_SUCCESS) { + pjsip_regc_destroy(regc); + return -110; + } + + if (client_cfg->auth) { + pjsip_cred_info cred; + + pj_bzero(&cred, sizeof(cred)); + cred.realm = pj_str("*"); + cred.scheme = pj_str("digest"); + cred.username = pj_str("user"); + cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; + cred.data = pj_str("password"); + + status = pjsip_regc_set_credentials(regc, 1, &cred); + if (status != PJ_SUCCESS) { + pjsip_regc_destroy(regc); + return -115; + } + } + + /* Register */ + status = pjsip_regc_register(regc, PJ_TRUE, &tdata); + if (status != PJ_SUCCESS) { + pjsip_regc_destroy(regc); + return -120; + } + status = pjsip_regc_send(regc, tdata); + + /* That's it, wait until the callback is sent */ + for (i=0; i<600 && !client_result.done; ++i) { + flush_events(100); + } + + if (!client_result.done) { + PJ_LOG(3,(THIS_FILE, " error: test has timed out")); + pjsip_regc_destroy(regc); + return -200; + } + + /* Destroy the regc, we're done with the test, unless we're + * instructed to leave the session open. + */ + if (!leave_session && !client_cfg->destroy_on_cb) + pjsip_regc_destroy(regc); + + /* Compare results with expected results */ + + if (client_result.error != client_cfg->error) { + PJ_LOG(3,(THIS_FILE, " error: expecting err=%d, got err=%d", + client_cfg->error, client_result.error)); + return -210; + } + if (client_result.code != client_cfg->code) { + PJ_LOG(3,(THIS_FILE, " error: expecting code=%d, got code=%d", + client_cfg->code, client_result.code)); + return -220; + } + if (client_result.expiration != client_cfg->expiration) { + PJ_LOG(3,(THIS_FILE, " error: expecting expiration=%d, got expiration=%d", + client_cfg->expiration, client_result.expiration)); + return -240; + } + if (client_result.contact_cnt != client_cfg->contact_cnt) { + PJ_LOG(3,(THIS_FILE, " error: expecting contact_cnt=%d, got contact_cnt=%d", + client_cfg->contact_cnt, client_result.contact_cnt)); + return -250; + } + if (client_result.have_reg != client_cfg->have_reg) { + PJ_LOG(3,(THIS_FILE, " error: expecting have_reg=%d, got have_reg=%d", + client_cfg->have_reg, client_result.have_reg)); + return -260; + } + if (client_result.interval != client_result.expiration) { + PJ_LOG(3,(THIS_FILE, " error: interval (%d) is different than expiration (%d)", + client_result.interval, client_result.expiration)); + return -270; + } + if (client_result.expiration > 0 && client_result.next_reg < 1) { + PJ_LOG(3,(THIS_FILE, " error: next_reg=%d, expecting positive number because expiration is %d", + client_result.next_reg, client_result.expiration)); + return -280; + } + + /* Looks like everything is okay. */ + if (leave_session) { + *p_regc = regc; + } + + return 0; +} + + +/************************************************************************/ +/* Customized tests */ + +/* Check that client is sending register refresh */ +static int keep_alive_test(const pj_str_t *registrar_uri) +{ + enum { TIMEOUT = 40 }; + struct registrar_cfg server_cfg = + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_FALSE, EXACT, TIMEOUT, 0, {NULL, 0}}; + struct client client_cfg = + /* error code have_reg expiration contact_cnt auth? destroy*/ + { PJ_FALSE, 200, PJ_TRUE, TIMEOUT, 1, PJ_FALSE,PJ_FALSE}; + pj_str_t contact = pj_str(""); + + + pjsip_regc *regc; + unsigned i; + int ret; + + ret = do_test("register refresh (takes ~40 secs)", &server_cfg, &client_cfg, registrar_uri, + 1, &contact, TIMEOUT, PJ_TRUE, ®c); + if (ret != 0) + return ret; + + /* Reset server response_cnt */ + registrar.response_cnt = 0; + + /* Wait until keep-alive/refresh is done */ + for (i=0; i<(TIMEOUT-1)*10 && registrar.response_cnt==0; ++i) { + flush_events(100); + } + + if (registrar.response_cnt==0) { + PJ_LOG(3,(THIS_FILE, " error: no refresh is received")); + return -400; + } + + if (client_result.error) { + PJ_LOG(3,(THIS_FILE, " error: got error")); + return -410; + } + if (client_result.code != 200) { + PJ_LOG(3,(THIS_FILE, " error: expecting code=%d, got code=%d", + 200, client_result.code)); + return -420; + } + if (client_result.expiration != TIMEOUT) { + PJ_LOG(3,(THIS_FILE, " error: expecting expiration=%d, got expiration=%d", + TIMEOUT, client_result.expiration)); + return -440; + } + if (client_result.contact_cnt != 1) { + PJ_LOG(3,(THIS_FILE, " error: expecting contact_cnt=%d, got contact_cnt=%d", + TIMEOUT, client_result.contact_cnt)); + return -450; + } + if (client_result.have_reg == 0) { + PJ_LOG(3,(THIS_FILE, " error: expecting have_reg=%d, got have_reg=%d", + 1, client_result.have_reg)); + return -460; + } + if (client_result.interval != TIMEOUT) { + PJ_LOG(3,(THIS_FILE, " error: interval (%d) is different than expiration (%d)", + client_result.interval, TIMEOUT)); + return -470; + } + if (client_result.expiration > 0 && client_result.next_reg < 1) { + PJ_LOG(3,(THIS_FILE, " error: next_reg=%d, expecting positive number because expiration is %d", + client_result.next_reg, client_result.expiration)); + return -480; + } + + /* Success */ + pjsip_regc_destroy(regc); + return 0; +} + + +/* Send error on refresh */ +static int refresh_error(const pj_str_t *registrar_uri, + pj_bool_t destroy_on_cb) +{ + enum { TIMEOUT = 40 }; + struct registrar_cfg server_cfg = + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_FALSE, EXACT, TIMEOUT, 0, {NULL, 0}}; + struct client client_cfg = + /* error code have_reg expiration contact_cnt auth? destroy*/ + { PJ_FALSE, 200, PJ_TRUE, TIMEOUT, 1, PJ_FALSE,PJ_FALSE}; + pj_str_t contact = pj_str(""); + + pjsip_regc *regc; + unsigned i; + int ret; + + ret = do_test("refresh error (takes ~40 secs)", &server_cfg, &client_cfg, registrar_uri, + 1, &contact, TIMEOUT, PJ_TRUE, ®c); + if (ret != 0) + return ret; + + /* Reset server response_cnt */ + registrar.response_cnt = 0; + + /* inject error for transmission */ + send_mod.count = 0; + send_mod.count_before_reject = 0; + + /* reconfigure client */ + client_result.done = PJ_FALSE; + client_result.destroy_on_cb = destroy_on_cb; + + /* Wait until keep-alive/refresh is done */ + for (i=0; i", 7 }, + { "", 7 }, + { "", 7 } + }; + + pjsip_regc *regc; + pjsip_contact_hdr *h1, *h2; + pjsip_sip_uri *u1, *u2; + unsigned i; + pj_status_t status; + pjsip_tx_data *tdata = NULL; + int ret = 0; + + /* initially only has 1 contact */ + ret = do_test("update test", &server_cfg, &client_cfg, registrar_uri, + 1, &contacts[0], TIMEOUT, PJ_TRUE, ®c); + if (ret != 0) { + return -600; + } + + /***** + * replace the contact with new one + */ + PJ_LOG(3,(THIS_FILE, " replacing contact")); + status = pjsip_regc_update_contact(regc, 1, &contacts[1]); + if (status != PJ_SUCCESS) { + ret = -610; + goto on_return; + } + + status = pjsip_regc_register(regc, PJ_TRUE, &tdata); + if (status != PJ_SUCCESS) { + ret = -620; + goto on_return; + } + + /* Check that the REGISTER contains two Contacts: + * - ;expires=0, + * - + */ + h1 = (pjsip_contact_hdr*) + pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL); + if (!h1) { + ret = -630; + goto on_return; + } + if ((void*)h1->next == (void*)&tdata->msg->hdr) + h2 = NULL; + else + h2 = (pjsip_contact_hdr*) + pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h1->next); + if (!h2) { + ret = -640; + goto on_return; + } + /* must not have other Contact header */ + if ((void*)h2->next != (void*)&tdata->msg->hdr && + pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h2->next) != NULL) + { + ret = -645; + goto on_return; + } + + u1 = (pjsip_sip_uri*) pjsip_uri_get_uri(h1->uri); + u2 = (pjsip_sip_uri*) pjsip_uri_get_uri(h2->uri); + + if (*u1->host.ptr == 'a') { + if (h1->expires != 0) { + ret = -650; + goto on_return; + } + if (h2->expires == 0) { + ret = -660; + goto on_return; + } + + } else { + pj_assert(*u1->host.ptr == 'b'); + if (h1->expires == 0) { + ret = -670; + goto on_return; + } + if (h2->expires != 0) { + ret = -680; + goto on_return; + } + } + + /* Destroy tdata */ + pjsip_tx_data_dec_ref(tdata); + tdata = NULL; + + + + /** + * First loop, it will update with more contacts. Second loop + * should do nothing. + */ + for (i=0; i<2; ++i) { + if (i==0) + PJ_LOG(3,(THIS_FILE, " replacing with more contacts")); + else + PJ_LOG(3,(THIS_FILE, " updating contacts with same contacts")); + + status = pjsip_regc_update_contact(regc, 2, &contacts[1]); + if (status != PJ_SUCCESS) { + ret = -710; + goto on_return; + } + + status = pjsip_regc_register(regc, PJ_TRUE, &tdata); + if (status != PJ_SUCCESS) { + ret = -720; + goto on_return; + } + + /* Check that the REGISTER contains two Contacts: + * - + * - + */ + h1 = (pjsip_contact_hdr*) + pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL); + if (!h1) { + ret = -730; + goto on_return; + } + if ((void*)h1->next == (void*)&tdata->msg->hdr) + h2 = NULL; + else + h2 = (pjsip_contact_hdr*) + pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h1->next); + if (!h2) { + ret = -740; + goto on_return; + } + /* must not have other Contact header */ + if ((void*)h2->next != (void*)&tdata->msg->hdr && + pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, h2->next) != NULL) + { + ret = -745; + goto on_return; + } + + /* both contacts must not have expires=0 parameter */ + if (h1->expires == 0) { + ret = -750; + goto on_return; + } + if (h2->expires == 0) { + ret = -760; + goto on_return; + } + + /* Destroy tdata */ + pjsip_tx_data_dec_ref(tdata); + tdata = NULL; + } + +on_return: + if (tdata) pjsip_tx_data_dec_ref(tdata); + pjsip_regc_destroy(regc); + return ret; +}; + + +/* send error on authentication */ +static int auth_send_error(const pj_str_t *registrar_uri, + pj_bool_t destroy_on_cb) +{ + enum { TIMEOUT = 40 }; + struct registrar_cfg server_cfg = + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_TRUE, EXACT, 75, 0, {NULL, 0}}; + struct client client_cfg = + /* error code have_reg expiration contact_cnt auth? destroy*/ + { PJ_TRUE, 401, PJ_FALSE, -1, 0, PJ_TRUE, PJ_TRUE}; + pj_str_t contact = pj_str(""); + + pjsip_regc *regc; + int ret; + + client_cfg.destroy_on_cb = destroy_on_cb; + + /* inject error for second request retry */ + send_mod.count = 0; + send_mod.count_before_reject = 1; + + ret = do_test("auth send error", &server_cfg, &client_cfg, registrar_uri, + 1, &contact, TIMEOUT, PJ_TRUE, ®c); + + send_mod.count_before_reject = 0xFFFF; + + return ret; +}; + + + + +/************************************************************************/ +enum +{ + OFF = 1, + ON = 2, + ON_OFF = 3, +}; + +int regc_test(void) +{ + struct test_rec { + unsigned check_contact; + unsigned add_xuid_param; + + const char *title; + char *alt_registrar; + unsigned contact_cnt; + char *contacts[4]; + unsigned expires; + struct registrar_cfg server_cfg; + struct client client_cfg; + } test_rec[] = + { + /* immediate error */ + { + OFF, /* check_contact */ + OFF, /* add_xuid_param */ + "immediate error", /* title */ + "sip:unresolved-host-xyy", /* alt_registrar */ + 1, /* contact cnt */ + { "sip:user@127.0.0.1:5060" }, /* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_FALSE, 200, PJ_FALSE, NONE, 0, 0, {NULL, 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth?*/ + { PJ_FALSE, 503, PJ_FALSE, -1, 0, PJ_FALSE} + }, + + /* timeout test */ + { + OFF, /* check_contact */ + OFF, /* add_xuid_param */ + "timeout test (takes ~32 secs)",/* title */ + NULL, /* alt_registrar */ + 1, /* contact cnt */ + { "sip:user@127.0.0.1:5060" }, /* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_FALSE, 200, PJ_FALSE, NONE, 0, 0, {NULL, 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth? */ + { PJ_FALSE, 408, PJ_FALSE, -1, 0, PJ_FALSE} + }, + + /* Basic successful registration scenario: + * a good registrar returns the Contact header as is and + * add expires parameter. In this test no additional bindings + * are returned. + */ + { + ON_OFF, /* check_contact */ + ON_OFF, /* add_xuid_param */ + "basic", /* title */ + NULL, /* alt_registrar */ + 1, /* contact cnt */ + { "" }, /* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_FALSE, EXACT, 75, 65, {NULL, 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth?*/ + { PJ_FALSE, 200, PJ_TRUE, 75, 1, PJ_FALSE} + }, + + /* Basic successful registration scenario with authentication + */ + { + ON_OFF, /* check_contact */ + ON_OFF, /* add_xuid_param */ + "authentication", /* title */ + NULL, /* alt_registrar */ + 1, /* contact cnt */ + { "" }, /* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_TRUE, EXACT, 75, 65, {NULL, 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth?*/ + { PJ_FALSE, 200, PJ_TRUE, 75, 1, PJ_TRUE} + }, + + /* a good registrar returns the Contact header as is and + * add expires parameter. Also it adds bindings from other + * clients in this test. + */ + { + ON_OFF, /* check_contact */ + ON, /* add_xuid_param */ + "more bindings in response", /* title */ + NULL, /* alt_registrar */ + 1, /* contact cnt */ + { "" }, /* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_FALSE, EXACT, 75, 65, {";expires=70", 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth?*/ + { PJ_FALSE, 200, PJ_TRUE, 75, 2, PJ_FALSE} + }, + + + /* a bad registrar returns modified Contact header, but it + * still returns all parameters intact. In this case + * the expiration is taken from the expires param because + * of matching xuid param or because the number of + * Contact header matches. + */ + { + ON_OFF, /* check_contact */ + ON_OFF, /* add_xuid_param */ + "registrar modifies Contact header", /* title */ + NULL, /* alt_registrar */ + 1, /* contact cnt */ + { "" }, /* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_FALSE, MODIFIED, 75, 65, {NULL, 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth?*/ + { PJ_FALSE, 200, PJ_TRUE, 75, 1, PJ_FALSE} + }, + + + /* a bad registrar returns modified Contact header, but it + * still returns all parameters intact. In addition it returns + * bindings from other clients. + * + * In this case the expiration is taken from the expires param + * because add_xuid_param is enabled. + */ + { + ON_OFF, /* check_contact */ + ON, /* add_xuid_param */ + "registrar modifies Contact header and add bindings", /* title */ + NULL, /* alt_registrar */ + 1, /* contact cnt */ + { "" }, /* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_FALSE, MODIFIED, 75, 65, {";expires=70", 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth?*/ + { PJ_FALSE, 200, PJ_TRUE, 75, 2, PJ_FALSE} + }, + + + /* a bad registrar returns completely different Contact and + * all parameters are gone. In this case the expiration is + * also taken from the expires param since the number of + * header matches. + */ + { + ON_OFF, /* check_contact */ + ON_OFF, /* add_xuid_param */ + "registrar replaces Contact header", /* title */ + NULL, /* alt_registrar */ + 1, /* contact cnt */ + { "" }, /* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 202, PJ_FALSE, NONE, 0, 65, {";expires=75", 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth?*/ + { PJ_FALSE, 202, PJ_TRUE, 75, 1, PJ_FALSE} + }, + + + /* a bad registrar returns completely different Contact (and + * all parameters are gone) and it also includes bindings from + * other clients. + * In this case the expiration is taken from the Expires header. + */ + { + ON_OFF, /* check_contact */ + ON_OFF, /* add_xuid_param */ + " as above with additional bindings", /* title */ + NULL, /* alt_registrar */ + 1, /* contact cnt */ + { "" }, /* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_FALSE, NONE, 0, 65, {";expires=75, ", 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth?*/ + { PJ_FALSE, 200, PJ_TRUE, 65, 2, PJ_FALSE} + }, + + /* the registrar doesn't return any bindings, but for some + * reason it includes an Expires header. + * In this case the expiration is taken from the Expires header. + */ + { + ON_OFF, /* check_contact */ + ON_OFF, /* add_xuid_param */ + "no Contact but with Expires", /* title */ + NULL, /* alt_registrar */ + 1, /* contact cnt */ + { "" }, /* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_FALSE, NONE, 0, 65, {NULL, 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth?*/ + { PJ_FALSE, 200, PJ_TRUE, 65, 0, PJ_FALSE} + }, + + /* Neither Contact header nor Expires header are present. + * In this case the expiration is taken from the request. + */ + { + ON_OFF, /* check_contact */ + ON_OFF, /* add_xuid_param */ + "no Contact and no Expires", /* title */ + NULL, /* alt_registrar */ + 1, /* contact cnt */ + { "" },/* contacts[] */ + 600, /* expires */ + + /* registrar config: */ + /* respond code auth contact exp_prm expires more_contacts */ + { PJ_TRUE, 200, PJ_FALSE, NONE, 0, 0, {NULL, 0}}, + + /* client expected results: */ + /* error code have_reg expiration contact_cnt auth?*/ + { PJ_FALSE, 200, PJ_TRUE, 600, 0, PJ_FALSE} + }, + }; + + unsigned i; + pj_sockaddr_in addr; + pjsip_transport *udp = NULL; + pj_uint16_t port; + char registrar_uri_buf[80]; + pj_str_t registrar_uri; + int rc = 0; + + pj_sockaddr_in_init(&addr, 0, 0); + + /* Acquire existing transport, if any */ + rc = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, &addr, sizeof(addr), NULL, &udp); + if (rc == PJ_SUCCESS) { + port = pj_sockaddr_get_port(&udp->local_addr); + pjsip_transport_dec_ref(udp); + udp = NULL; + } else { + rc = pjsip_udp_transport_start(endpt, NULL, NULL, 1, &udp); + if (rc != PJ_SUCCESS) { + app_perror(" error creating UDP transport", rc); + rc = -2; + goto on_return; + } + + port = pj_sockaddr_get_port(&udp->local_addr); + } + + /* Register registrar module */ + rc = pjsip_endpt_register_module(endpt, ®istrar.mod); + if (rc != PJ_SUCCESS) { + app_perror(" error registering module", rc); + rc = -3; + goto on_return; + } + + /* Register send module */ + rc = pjsip_endpt_register_module(endpt, &send_mod.mod); + if (rc != PJ_SUCCESS) { + app_perror(" error registering module", rc); + rc = -3; + goto on_return; + } + + pj_ansi_snprintf(registrar_uri_buf, sizeof(registrar_uri_buf), + "sip:127.0.0.1:%d", (int)port); + registrar_uri = pj_str(registrar_uri_buf); + + for (i=0; ialt_registrar == NULL) { + reg_uri = registrar_uri; + } else { + reg_uri = pj_str(t->alt_registrar); + } + + /* Build contact pj_str_t's */ + for (j=0; jcontact_cnt; ++j) { + contacts[j] = pj_str(t->contacts[j]); + } + + /* Normalize more_contacts field */ + if (t->server_cfg.more_contacts.ptr) + t->server_cfg.more_contacts.slen = strlen(t->server_cfg.more_contacts.ptr); + + /* Do tests with three combinations: + * - check_contact on/off + * - add_xuid_param on/off + * - destroy_on_callback on/off + */ + for (x=1; x<=2; ++x) { + unsigned y; + + if ((t->check_contact & x) == 0) + continue; + + pjsip_cfg()->regc.check_contact = (x-1); + + for (y=1; y<=2; ++y) { + unsigned z; + + if ((t->add_xuid_param & y) == 0) + continue; + + pjsip_cfg()->regc.add_xuid_param = (y-1); + + for (z=0; z<=1; ++z) { + char new_title[200]; + + t->client_cfg.destroy_on_cb = z; + + sprintf(new_title, "%s [check=%d, xuid=%d, destroy=%d]", + t->title, pjsip_cfg()->regc.check_contact, + pjsip_cfg()->regc.add_xuid_param, z); + rc = do_test(new_title, &t->server_cfg, &t->client_cfg, + ®_uri, t->contact_cnt, contacts, + t->expires, PJ_FALSE, NULL); + if (rc != 0) + goto on_return; + } + + } + } + + /* Sleep between test groups to avoid using up too many + * active transactions. + */ + pj_thread_sleep(1000); + } + + /* keep-alive test */ + rc = keep_alive_test(®istrar_uri); + if (rc != 0) + goto on_return; + + /* Send error on refresh without destroy on callback */ + rc = refresh_error(®istrar_uri, PJ_FALSE); + if (rc != 0) + goto on_return; + + /* Send error on refresh, destroy on callback */ + rc = refresh_error(®istrar_uri, PJ_TRUE); + if (rc != 0) + goto on_return; + + /* Updating contact */ + rc = update_test(®istrar_uri); + if (rc != 0) + goto on_return; + + /* Send error during auth, don't destroy on callback */ + rc = auth_send_error(®istrar_uri, PJ_FALSE); + if (rc != 0) + goto on_return; + + /* Send error during auth, destroy on callback */ + rc = auth_send_error(®istrar_uri, PJ_FALSE); + if (rc != 0) + goto on_return; + +on_return: + if (registrar.mod.id != -1) { + pjsip_endpt_unregister_module(endpt, ®istrar.mod); + } + if (send_mod.mod.id != -1) { + pjsip_endpt_unregister_module(endpt, &send_mod.mod); + } + if (udp) { + pjsip_transport_dec_ref(udp); + } + return rc; +} + + diff --git a/pjsip/src/test/test.c b/pjsip/src/test/test.c new file mode 100644 index 00000000..5ce2b71a --- /dev/null +++ b/pjsip/src/test/test.c @@ -0,0 +1,392 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + + +#include "test.h" +#include +#include +#include + +#define THIS_FILE "test.c" + +#define DO_TEST(test) do { \ + PJ_LOG(3, (THIS_FILE, "Running %s...", #test)); \ + rc = test; \ + PJ_LOG(3, (THIS_FILE, \ + "%s(%d)", \ + (rc ? "..ERROR" : "..success"), rc)); \ + if (rc!=0) goto on_return; \ + } while (0) + +#define DO_TSX_TEST(test, param) \ + do { \ + PJ_LOG(3, (THIS_FILE, "Running %s(%s)...", #test, (param)->tp_type)); \ + rc = test(param); \ + PJ_LOG(3, (THIS_FILE, \ + "%s(%d)", \ + (rc ? "..ERROR" : "..success"), rc)); \ + if (rc!=0) goto on_return; \ + } while (0) + + +pjsip_endpoint *endpt; +int log_level = 3; +int param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | + PJ_LOG_HAS_MICRO_SEC; + +static pj_oshandle_t fd_report; +const char *system_name = "Unknown"; +static char buf[1024]; + +void app_perror(const char *msg, pj_status_t rc) +{ + char errbuf[256]; + + PJ_CHECK_STACK(); + + pj_strerror(rc, errbuf, sizeof(errbuf)); + PJ_LOG(3,(THIS_FILE, "%s: [pj_status_t=%d] %s", msg, rc, errbuf)); + +} + +void flush_events(unsigned duration) +{ + pj_time_val stop_time; + + pj_gettimeofday(&stop_time); + stop_time.msec += duration; + pj_time_val_normalize(&stop_time); + + /* Process all events for the specified duration. */ + for (;;) { + pj_time_val timeout = {0, 1}, now; + + pjsip_endpt_handle_events(endpt, &timeout); + + pj_gettimeofday(&now); + if (PJ_TIME_VAL_GTE(now, stop_time)) + break; + } +} + +pj_status_t register_static_modules(pj_size_t *count, pjsip_module **modules) +{ + *count = 0; + return PJ_SUCCESS; +} + +static pj_status_t init_report(void) +{ + char tmp[80]; + pj_time_val timestamp; + pj_parsed_time date_time; + pj_ssize_t len; + pj_status_t status; + + pj_ansi_sprintf(tmp, "pjsip-static-bench-%s-%s.htm", PJ_OS_NAME, PJ_CC_NAME); + + status = pj_file_open(NULL, tmp, PJ_O_WRONLY, &fd_report); + if (status != PJ_SUCCESS) + return status; + + /* Title */ + len = pj_ansi_sprintf(buf, "\n" + " \n" + " PJSIP %s (%s) - Static Benchmark\n" + " \n" + "\n" + "\n", + PJ_VERSION, + (PJ_DEBUG ? "Debug" : "Release")); + pj_file_write(fd_report, buf, &len); + + + /* Title */ + len = pj_ansi_sprintf(buf, "

PJSIP %s (%s) - Static Benchmark

\n", + PJ_VERSION, + (PJ_DEBUG ? "Debug" : "Release")); + pj_file_write(fd_report, buf, &len); + + len = pj_ansi_sprintf(buf, "

Below is the benchmark result generated " + "by test-pjsip program. The program " + "is single-threaded only.

\n"); + pj_file_write(fd_report, buf, &len); + + + /* Write table heading */ + len = pj_ansi_sprintf(buf, "\n" + " \n" + " \n" + " \n" + " \n"); + pj_file_write(fd_report, buf, &len); + + + /* Write version */ + report_sval("version", PJ_VERSION, "", "PJLIB/PJSIP version"); + + + /* Debug or release */ + report_sval("build-type", (PJ_DEBUG ? "Debug" : "Release"), "", "Build type"); + + + /* Write timestamp */ + pj_gettimeofday(×tamp); + report_ival("timestamp", timestamp.sec, "", "System timestamp of the test"); + + + /* Write time of day */ + pj_time_decode(×tamp, &date_time); + len = pj_ansi_sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d", + date_time.year, date_time.mon+1, date_time.day, + date_time.hour, date_time.min, date_time.sec); + report_sval("date-time", tmp, "", "Date/time of the test"); + + + /* Write System */ + report_sval("system", system_name, "", "System description"); + + + /* Write OS type */ + report_sval("os-family", PJ_OS_NAME, "", "Operating system family"); + + + /* Write CC name */ + len = pj_ansi_sprintf(tmp, "%s-%d.%d.%d", PJ_CC_NAME, + PJ_CC_VER_1, PJ_CC_VER_2, PJ_CC_VER_2); + report_sval("cc-name", tmp, "", "Compiler name and version"); + + + return PJ_SUCCESS; +} + +void report_sval(const char *name, const char* value, const char *valname, + const char *desc) +{ + pj_ssize_t len; + + len = pj_ansi_sprintf(buf, " \n" + " \n" + " \n" + " \n", + name, value, valname, desc); + pj_file_write(fd_report, buf, &len); +} + + +void report_ival(const char *name, int value, const char *valname, + const char *desc) +{ + pj_ssize_t len; + + len = pj_ansi_sprintf(buf, " \n" + " \n" + " \n" + " \n", + name, value, valname, desc); + pj_file_write(fd_report, buf, &len); + +} + +static void close_report(void) +{ + pj_ssize_t len; + + if (fd_report) { + len = pj_ansi_sprintf(buf, "
VariableValueDescription
%s%s %s%s
%s%d %s%s
\n\n\n"); + pj_file_write(fd_report, buf, &len); + + pj_file_close(fd_report); + } +} + + +int test_main(void) +{ + pj_status_t rc; + pj_caching_pool caching_pool; + const char *filename; + unsigned tsx_test_cnt=0; + struct tsx_test_param tsx_test[10]; + pj_status_t status; +#if INCLUDE_TSX_TEST + unsigned i; + pjsip_transport *tp; +#if PJ_HAS_TCP + pjsip_tpfactory *tpfactory; +#endif /* PJ_HAS_TCP */ +#endif /* INCLUDE_TSX_TEST */ + int line; + + pj_log_set_level(log_level); + pj_log_set_decor(param_log_decor); + + if ((rc=pj_init()) != PJ_SUCCESS) { + app_perror("pj_init", rc); + return rc; + } + + if ((rc=pjlib_util_init()) != PJ_SUCCESS) { + app_perror("pj_init", rc); + return rc; + } + + status = init_report(); + if (status != PJ_SUCCESS) + return status; + + pj_dump_config(); + + pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, + PJSIP_TEST_MEM_SIZE ); + + rc = pjsip_endpt_create(&caching_pool.factory, "endpt", &endpt); + if (rc != PJ_SUCCESS) { + app_perror("pjsip_endpt_create", rc); + pj_caching_pool_destroy(&caching_pool); + return rc; + } + + PJ_LOG(3,(THIS_FILE,"")); + + /* Init logger module. */ + init_msg_logger(); + msg_logger_set_enabled(1); + + /* Start transaction layer module. */ + rc = pjsip_tsx_layer_init_module(endpt); + if (rc != PJ_SUCCESS) { + app_perror(" Error initializing transaction module", rc); + goto on_return; + } + + /* Create loop transport. */ + rc = pjsip_loop_start(endpt, NULL); + if (rc != PJ_SUCCESS) { + app_perror(" error: unable to create datagram loop transport", + rc); + goto on_return; + } + tsx_test[tsx_test_cnt].port = 5060; + tsx_test[tsx_test_cnt].tp_type = "loop-dgram"; + tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_LOOP_DGRAM; + ++tsx_test_cnt; + + +#if INCLUDE_URI_TEST + DO_TEST(uri_test()); +#endif + +#if INCLUDE_MSG_TEST + DO_TEST(msg_test()); + DO_TEST(msg_err_test()); +#endif + +#if INCLUDE_TXDATA_TEST + DO_TEST(txdata_test()); +#endif + +#if INCLUDE_TSX_BENCH + DO_TEST(tsx_bench()); +#endif + +#if INCLUDE_UDP_TEST + DO_TEST(transport_udp_test()); +#endif + +#if INCLUDE_LOOP_TEST + DO_TEST(transport_loop_test()); +#endif + +#if INCLUDE_TCP_TEST + DO_TEST(transport_tcp_test()); +#endif + +#if INCLUDE_RESOLVE_TEST + DO_TEST(resolve_test()); +#endif + + +#if INCLUDE_TSX_TEST + status = pjsip_udp_transport_start(endpt, NULL, NULL, 1, &tp); + if (status == PJ_SUCCESS) { + tsx_test[tsx_test_cnt].port = tp->local_name.port; + tsx_test[tsx_test_cnt].tp_type = "udp"; + tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_UDP; + ++tsx_test_cnt; + } + +#if PJ_HAS_TCP + status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); + if (status == PJ_SUCCESS) { + tsx_test[tsx_test_cnt].port = tpfactory->addr_name.port; + tsx_test[tsx_test_cnt].tp_type = "tcp"; + tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_TCP; + ++tsx_test_cnt; + } else { + app_perror("Unable to create TCP", status); + rc = -4; + goto on_return; + } +#endif + + + for (i=0; i + * + * 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 + */ +#ifndef __TEST_H__ +#define __TEST_H__ + +#include + +extern pjsip_endpoint *endpt; + +#define TEST_UDP_PORT 15060 +#define TEST_UDP_PORT_STR "15060" + +/** + * Memory size to use in caching pool. + * Default: 2MB + */ +#ifndef PJSIP_TEST_MEM_SIZE +# define PJSIP_TEST_MEM_SIZE (2*1024*1024) +#endif + + + +#define INCLUDE_MESSAGING_GROUP 1 +#define INCLUDE_TRANSPORT_GROUP 1 +#define INCLUDE_TSX_GROUP 1 +#define INCLUDE_INV_GROUP 1 +#define INCLUDE_REGC_GROUP 1 + +#define INCLUDE_BENCHMARKS 1 + +/* + * Include tests that normally would fail under certain gcc + * optimization levels. + */ +#ifndef INCLUDE_GCC_TEST +# define INCLUDE_GCC_TEST 0 +#endif + + +#define INCLUDE_URI_TEST INCLUDE_MESSAGING_GROUP +#define INCLUDE_MSG_TEST INCLUDE_MESSAGING_GROUP +#define INCLUDE_TXDATA_TEST INCLUDE_MESSAGING_GROUP +#define INCLUDE_TSX_BENCH INCLUDE_MESSAGING_GROUP +#define INCLUDE_UDP_TEST INCLUDE_TRANSPORT_GROUP +#define INCLUDE_LOOP_TEST INCLUDE_TRANSPORT_GROUP +#define INCLUDE_TCP_TEST INCLUDE_TRANSPORT_GROUP +#define INCLUDE_RESOLVE_TEST INCLUDE_TRANSPORT_GROUP +#define INCLUDE_TSX_TEST INCLUDE_TSX_GROUP +#define INCLUDE_INV_OA_TEST INCLUDE_INV_GROUP +#define INCLUDE_REGC_TEST INCLUDE_REGC_GROUP + + +/* The tests */ +int uri_test(void); +int msg_test(void); +int msg_err_test(void); +int txdata_test(void); +int tsx_bench(void); +int transport_udp_test(void); +int transport_loop_test(void); +int transport_tcp_test(void); +int resolve_test(void); +int regc_test(void); + +struct tsx_test_param +{ + int type; + int port; + char *tp_type; +}; + +int tsx_basic_test(struct tsx_test_param *param); +int tsx_uac_test(struct tsx_test_param *param); +int tsx_uas_test(struct tsx_test_param *param); + +/* Transport test helpers (transport_test.c). */ +int generic_transport_test(pjsip_transport *tp); +int transport_send_recv_test( pjsip_transport_type_e tp_type, + pjsip_transport *ref_tp, + char *target_url, + int *p_usec_rtt); +int transport_rt_test( pjsip_transport_type_e tp_type, + pjsip_transport *ref_tp, + char *target_url, + int *pkt_lost); +int transport_load_test(char *target_url); + +/* Invite session */ +int inv_offer_answer_test(void); + +/* Test main entry */ +int test_main(void); + +/* Test utilities. */ +void app_perror(const char *msg, pj_status_t status); +int init_msg_logger(void); +int msg_logger_set_enabled(pj_bool_t enabled); +void flush_events(unsigned duration); + + +void report_ival(const char *name, int value, const char *valname, const char *desc); +void report_sval(const char *name, const char* value, const char *valname, const char *desc); + + +/* Settings. */ +extern int log_level; + +#endif /* __TEST_H__ */ diff --git a/pjsip/src/test/transport_loop_test.c b/pjsip/src/test/transport_loop_test.c new file mode 100644 index 00000000..a28b7b07 --- /dev/null +++ b/pjsip/src/test/transport_loop_test.c @@ -0,0 +1,127 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + +#include "test.h" +#include +#include + +#define THIS_FILE "transport_loop_test.c" + +static int datagram_loop_test() +{ + enum { LOOP = 8 }; + pjsip_transport *loop; + int i, pkt_lost; + pj_sockaddr_in addr; + pj_status_t status; + long ref_cnt; + int rtt[LOOP], min_rtt; + + PJ_LOG(3,(THIS_FILE, "testing datagram loop transport")); + + /* Test acquire transport. */ + status = pjsip_endpt_acquire_transport( endpt, PJSIP_TRANSPORT_LOOP_DGRAM, + &addr, sizeof(addr), NULL, &loop); + if (status != PJ_SUCCESS) { + app_perror(" error: loop transport is not configured", status); + return -20; + } + + /* Get initial reference counter */ + ref_cnt = pj_atomic_get(loop->ref_cnt); + + /* Test basic transport attributes */ + status = generic_transport_test(loop); + if (status != PJ_SUCCESS) + return status; + + /* Basic transport's send/receive loopback test. */ + for (i=0; iref_cnt) != ref_cnt) { + PJ_LOG(3,(THIS_FILE, " error: ref counter is not %d (%d)", + ref_cnt, pj_atomic_get(loop->ref_cnt))); + return -51; + } + + /* Decrement reference. */ + pjsip_transport_dec_ref(loop); + + return 0; +} + +int transport_loop_test(void) +{ + int status; + + status = datagram_loop_test(); + if (status != 0) + return status; + + return 0; +} diff --git a/pjsip/src/test/transport_tcp_test.c b/pjsip/src/test/transport_tcp_test.c new file mode 100644 index 00000000..d012fb0e --- /dev/null +++ b/pjsip/src/test/transport_tcp_test.c @@ -0,0 +1,155 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + +#include "test.h" +#include +#include + +#define THIS_FILE "transport_tcp_test.c" + + +/* + * TCP transport test. + */ +#if PJ_HAS_TCP +int transport_tcp_test(void) +{ + enum { SEND_RECV_LOOP = 8 }; + pjsip_tpfactory *tpfactory; + pjsip_transport *tcp; + pj_sockaddr_in rem_addr; + pj_status_t status; + char url[PJSIP_MAX_URL_SIZE]; + int rtt[SEND_RECV_LOOP], min_rtt; + int i, pkt_lost; + + /* Start TCP listener on arbitrary port. */ + status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to start TCP transport", status); + return -10; + } + + + /* Get the listener address */ + status = pj_sockaddr_in_init(&rem_addr, &tpfactory->addr_name.host, + (pj_uint16_t)tpfactory->addr_name.port); + if (status != PJ_SUCCESS) { + app_perror(" Error: possibly invalid TCP address name", status); + return -14; + } + + pj_ansi_sprintf(url, "sip:alice@%s:%d;transport=tcp", + pj_inet_ntoa(rem_addr.sin_addr), + pj_ntohs(rem_addr.sin_port)); + + + /* Acquire one TCP transport. */ + status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP, + &rem_addr, sizeof(rem_addr), + NULL, &tcp); + if (status != PJ_SUCCESS || tcp == NULL) { + app_perror(" Error: unable to acquire TCP transport", status); + return -17; + } + + /* After pjsip_endpt_acquire_transport, TCP transport must have + * reference counter 1. + */ + if (pj_atomic_get(tcp->ref_cnt) != 1) + return -20; + + /* Test basic transport attributes */ + status = generic_transport_test(tcp); + if (status != PJ_SUCCESS) + return status; + + + /* Check again that reference counter is 1. */ + if (pj_atomic_get(tcp->ref_cnt) != 1) + return -40; + + /* Load test */ + if (transport_load_test(url) != 0) + return -60; + + /* Basic transport's send/receive loopback test. */ + for (i=0; iref_cnt) != 1) + return -80; + + /* Destroy this transport. */ + pjsip_transport_dec_ref(tcp); + + /* Force destroy this transport. */ + status = pjsip_transport_destroy(tcp); + if (status != PJ_SUCCESS) + return -90; + + /* Unregister factory */ + status = pjsip_tpmgr_unregister_tpfactory(pjsip_endpt_get_tpmgr(endpt), + tpfactory); + if (status != PJ_SUCCESS) + return -95; + + /* Flush events. */ + PJ_LOG(3,(THIS_FILE, " Flushing events, 1 second...")); + flush_events(1000); + + /* Done */ + return 0; +} +#else /* PJ_HAS_TCP */ +int transport_tcp_test(void) +{ + return 0; +} +#endif /* PJ_HAS_TCP */ diff --git a/pjsip/src/test/transport_test.c b/pjsip/src/test/transport_test.c new file mode 100644 index 00000000..9f19b68f --- /dev/null +++ b/pjsip/src/test/transport_test.c @@ -0,0 +1,760 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + +#include "test.h" +#include +#include + +#define THIS_FILE "transport_test.c" + +/////////////////////////////////////////////////////////////////////////////// +/* + * Generic testing for transport, to make sure that basic + * attributes have been initialized properly. + */ +int generic_transport_test(pjsip_transport *tp) +{ + PJ_LOG(3,(THIS_FILE, " structure test...")); + + /* Check that local address name is valid. */ + { + struct pj_in_addr addr; + + /* Note: inet_aton() returns non-zero if addr is valid! */ + if (pj_inet_aton(&tp->local_name.host, &addr) != 0) { + if (addr.s_addr==PJ_INADDR_ANY || addr.s_addr==PJ_INADDR_NONE) { + PJ_LOG(3,(THIS_FILE, " Error: invalid address name")); + return -420; + } + } else { + /* It's okay. local_name.host may be a hostname instead of + * IP address. + */ + } + } + + /* Check that port is valid. */ + if (tp->local_name.port <= 0) { + return -430; + } + + /* Check length of address (for now we only check against sockaddr_in). */ + if (tp->addr_len != sizeof(pj_sockaddr_in)) + return -440; + + /* Check type. */ + if (tp->key.type == PJSIP_TRANSPORT_UNSPECIFIED) + return -450; + + /* That's it. */ + return PJ_SUCCESS; +} + +/////////////////////////////////////////////////////////////////////////////// +/* + * Send/receive test. + * + * This test sends a request to loopback address; as soon as request is + * received, response will be sent, and time is recorded. + * + * The main purpose is to test that the basic transport functionalities works, + * before we continue with more complicated tests. + */ +#define FROM_HDR "Bob " +#define CONTACT_HDR "Bob " +#define CALL_ID_HDR "SendRecv-Test" +#define CSEQ_VALUE 100 +#define BODY "Hello World!" + +static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata); +static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata); + +/* Flag to indicate message has been received + * (or failed to send) + */ +#define NO_STATUS -2 +static int send_status = NO_STATUS; +static int recv_status = NO_STATUS; +static pj_timestamp my_send_time, my_recv_time; + +/* Module to receive messages for this test. */ +static pjsip_module my_module = +{ + NULL, NULL, /* prev and next */ + { "Transport-Test", 14}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + &my_on_rx_request, /* on_rx_request() */ + &my_on_rx_response, /* on_rx_response() */ + NULL, /* on_tsx_state() */ +}; + + +static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata) +{ + /* Check that this is our request. */ + if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) { + /* It is! */ + /* Send response. */ + pjsip_tx_data *tdata; + pjsip_response_addr res_addr; + pj_status_t status; + + status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata); + if (status != PJ_SUCCESS) { + recv_status = status; + return PJ_TRUE; + } + status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr); + if (status != PJ_SUCCESS) { + recv_status = status; + pjsip_tx_data_dec_ref(tdata); + return PJ_TRUE; + } + status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + recv_status = status; + pjsip_tx_data_dec_ref(tdata); + return PJ_TRUE; + } + return PJ_TRUE; + } + + /* Not ours. */ + return PJ_FALSE; +} + +static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata) +{ + if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) { + pj_get_timestamp(&my_recv_time); + recv_status = PJ_SUCCESS; + return PJ_TRUE; + } + return PJ_FALSE; +} + +/* Transport callback. */ +static void send_msg_callback(pjsip_send_state *stateless_data, + pj_ssize_t sent, pj_bool_t *cont) +{ + if (sent < 1) { + /* Obtain the error code. */ + send_status = -sent; + } else { + send_status = PJ_SUCCESS; + } + + /* Don't want to continue. */ + *cont = PJ_FALSE; +} + + +/* Test that we receive loopback message. */ +int transport_send_recv_test( pjsip_transport_type_e tp_type, + pjsip_transport *ref_tp, + char *target_url, + int *p_usec_rtt) +{ + pj_bool_t msg_log_enabled; + pj_status_t status; + pj_str_t target, from, to, contact, call_id, body; + pjsip_method method; + pjsip_tx_data *tdata; + pj_time_val timeout; + + PJ_LOG(3,(THIS_FILE, " single message round-trip test...")); + + /* Register out test module to receive the message (if necessary). */ + if (my_module.id == -1) { + status = pjsip_endpt_register_module( endpt, &my_module ); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to register module", status); + return -500; + } + } + + /* Disable message logging. */ + msg_log_enabled = msg_logger_set_enabled(0); + + /* Create a request message. */ + target = pj_str(target_url); + from = pj_str(FROM_HDR); + to = pj_str(target_url); + contact = pj_str(CONTACT_HDR); + call_id = pj_str(CALL_ID_HDR); + body = pj_str(BODY); + + pjsip_method_set(&method, PJSIP_OPTIONS_METHOD); + status = pjsip_endpt_create_request( endpt, &method, &target, &from, &to, + &contact, &call_id, CSEQ_VALUE, + &body, &tdata ); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return -510; + } + + /* Reset statuses */ + send_status = recv_status = NO_STATUS; + + /* Start time. */ + pj_get_timestamp(&my_send_time); + + /* Send the message (statelessly). */ + PJ_LOG(5,(THIS_FILE, "Sending request to %.*s", + (int)target.slen, target.ptr)); + status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, + &send_msg_callback); + if (status != PJ_SUCCESS) { + /* Immediate error! */ + pjsip_tx_data_dec_ref(tdata); + send_status = status; + } + + /* Set the timeout (2 seconds from now) */ + pj_gettimeofday(&timeout); + timeout.sec += 2; + + /* Loop handling events until we get status */ + do { + pj_time_val now; + pj_time_val poll_interval = { 0, 10 }; + + pj_gettimeofday(&now); + if (PJ_TIME_VAL_GTE(now, timeout)) { + PJ_LOG(3,(THIS_FILE, " error: timeout in send/recv test")); + status = -540; + goto on_return; + } + + if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) { + app_perror(" error sending message", send_status); + status = -550; + goto on_return; + } + + if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) { + app_perror(" error receiving message", recv_status); + status = -560; + goto on_return; + } + + if (send_status!=NO_STATUS && recv_status!=NO_STATUS) { + /* Success! */ + break; + } + + pjsip_endpt_handle_events(endpt, &poll_interval); + + } while (1); + + if (status == PJ_SUCCESS) { + unsigned usec_rt; + usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time); + + PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt)); + + *p_usec_rtt = usec_rt; + } + + /* Restore message logging. */ + msg_logger_set_enabled(msg_log_enabled); + + status = PJ_SUCCESS; + +on_return: + return status; +} + + +/////////////////////////////////////////////////////////////////////////////// +/* + * Multithreaded round-trip test + * + * This test will spawn multiple threads, each of them send a request. As soon + * as request is received, response will be sent, and time is recorded. + * + * The main purpose of this test is to ensure there's no crash when multiple + * threads are sending/receiving messages. + * + */ +static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata); +static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata); + +static pjsip_module rt_module = +{ + NULL, NULL, /* prev and next */ + { "Transport-RT-Test", 17}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + &rt_on_rx_request, /* on_rx_request() */ + &rt_on_rx_response, /* on_rx_response() */ + NULL, /* tsx_handler() */ +}; + +static struct +{ + pj_thread_t *thread; + pj_timestamp send_time; + pj_timestamp total_rt_time; + int sent_request_count, recv_response_count; + pj_str_t call_id; + pj_timer_entry timeout_timer; + pj_timer_entry tx_timer; + pj_mutex_t *mutex; +} rt_test_data[16]; + +static char rt_target_uri[64]; +static pj_bool_t rt_stop; +static pj_str_t rt_call_id; + +static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata) +{ + if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) { + pjsip_tx_data *tdata; + pjsip_response_addr res_addr; + pj_status_t status; + + status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata); + if (status != PJ_SUCCESS) { + app_perror(" error creating response", status); + return PJ_TRUE; + } + status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr); + if (status != PJ_SUCCESS) { + app_perror(" error in get response address", status); + pjsip_tx_data_dec_ref(tdata); + return PJ_TRUE; + } + status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + app_perror(" error sending response", status); + pjsip_tx_data_dec_ref(tdata); + return PJ_TRUE; + } + return PJ_TRUE; + + } + return PJ_FALSE; +} + +static pj_status_t rt_send_request(int thread_id) +{ + pj_status_t status; + pj_str_t target, from, to, contact, call_id; + pjsip_tx_data *tdata; + pj_time_val timeout_delay; + + pj_mutex_lock(rt_test_data[thread_id].mutex); + + /* Create a request message. */ + target = pj_str(rt_target_uri); + from = pj_str(FROM_HDR); + to = pj_str(rt_target_uri); + contact = pj_str(CONTACT_HDR); + call_id = rt_test_data[thread_id].call_id; + + status = pjsip_endpt_create_request( endpt, &pjsip_options_method, + &target, &from, &to, + &contact, &call_id, -1, + NULL, &tdata ); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + pj_mutex_unlock(rt_test_data[thread_id].mutex); + return -610; + } + + /* Start time. */ + pj_get_timestamp(&rt_test_data[thread_id].send_time); + + /* Send the message (statelessly). */ + status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + /* Immediate error! */ + app_perror(" error: send request", status); + pjsip_tx_data_dec_ref(tdata); + pj_mutex_unlock(rt_test_data[thread_id].mutex); + return -620; + } + + /* Update counter. */ + rt_test_data[thread_id].sent_request_count++; + + /* Set timeout timer. */ + if (rt_test_data[thread_id].timeout_timer.user_data != NULL) { + pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer); + } + timeout_delay.sec = 100; timeout_delay.msec = 0; + rt_test_data[thread_id].timeout_timer.user_data = (void*)1; + pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].timeout_timer, + &timeout_delay); + + pj_mutex_unlock(rt_test_data[thread_id].mutex); + return PJ_SUCCESS; +} + +static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata) +{ + if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) { + char *pos = pj_strchr(&rdata->msg_info.cid->id, '/')+1; + int thread_id = (*pos - '0'); + pj_timestamp recv_time; + + pj_mutex_lock(rt_test_data[thread_id].mutex); + + /* Stop timer. */ + pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer); + + /* Update counter and end-time. */ + rt_test_data[thread_id].recv_response_count++; + pj_get_timestamp(&recv_time); + + pj_sub_timestamp(&recv_time, &rt_test_data[thread_id].send_time); + pj_add_timestamp(&rt_test_data[thread_id].total_rt_time, &recv_time); + + if (!rt_stop) { + pj_time_val tx_delay = { 0, 0 }; + pj_assert(rt_test_data[thread_id].tx_timer.user_data == NULL); + rt_test_data[thread_id].tx_timer.user_data = (void*)1; + pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].tx_timer, + &tx_delay); + } + + pj_mutex_unlock(rt_test_data[thread_id].mutex); + + return PJ_TRUE; + } + return PJ_FALSE; +} + +static void rt_timeout_timer( pj_timer_heap_t *timer_heap, + struct pj_timer_entry *entry ) +{ + pj_mutex_lock(rt_test_data[entry->id].mutex); + + PJ_UNUSED_ARG(timer_heap); + PJ_LOG(3,(THIS_FILE, " timeout waiting for response")); + rt_test_data[entry->id].timeout_timer.user_data = NULL; + + if (rt_test_data[entry->id].tx_timer.user_data == NULL) { + pj_time_val delay = { 0, 0 }; + rt_test_data[entry->id].tx_timer.user_data = (void*)1; + pjsip_endpt_schedule_timer(endpt, &rt_test_data[entry->id].tx_timer, + &delay); + } + + pj_mutex_unlock(rt_test_data[entry->id].mutex); +} + +static void rt_tx_timer( pj_timer_heap_t *timer_heap, + struct pj_timer_entry *entry ) +{ + pj_mutex_lock(rt_test_data[entry->id].mutex); + + PJ_UNUSED_ARG(timer_heap); + pj_assert(rt_test_data[entry->id].tx_timer.user_data != NULL); + rt_test_data[entry->id].tx_timer.user_data = NULL; + rt_send_request(entry->id); + + pj_mutex_unlock(rt_test_data[entry->id].mutex); +} + + +static int rt_worker_thread(void *arg) +{ + int i; + pj_time_val poll_delay = { 0, 10 }; + + /* Sleep to allow main threads to run. */ + pj_thread_sleep(10); + + while (!rt_stop) { + pjsip_endpt_handle_events(endpt, &poll_delay); + } + + /* Exhaust responses. */ + for (i=0; i<100; ++i) + pjsip_endpt_handle_events(endpt, &poll_delay); + + return 0; +} + +int transport_rt_test( pjsip_transport_type_e tp_type, + pjsip_transport *ref_tp, + char *target_url, + int *lost) +{ + enum { THREADS = 4, INTERVAL = 10 }; + int i; + pj_status_t status; + pj_pool_t *pool; + pj_bool_t logger_enabled; + + pj_timestamp zero_time, total_time; + unsigned usec_rt; + unsigned total_sent; + unsigned total_recv; + + PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...", + THREADS)); + PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..", + INTERVAL)); + + /* Make sure msg logger is disabled. */ + logger_enabled = msg_logger_set_enabled(0); + + /* Register module (if not yet registered) */ + if (rt_module.id == -1) { + status = pjsip_endpt_register_module( endpt, &rt_module ); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to register module", status); + return -600; + } + } + + /* Create pool for this test. */ + pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000); + if (!pool) + return -610; + + /* Initialize static test data. */ + pj_ansi_strcpy(rt_target_uri, target_url); + rt_call_id = pj_str("RT-Call-Id/"); + rt_stop = PJ_FALSE; + + /* Initialize thread data. */ + for (i=0; imsg_info.cseq->cseq != mod_load.next_seq) { + PJ_LOG(1,("THIS_FILE", " err: expecting cseq %u, got %u", + mod_load.next_seq, rdata->msg_info.cseq->cseq)); + mod_load.err = PJ_TRUE; + mod_load.next_seq = rdata->msg_info.cseq->cseq + 1; + } else + mod_load.next_seq++; + return PJ_TRUE; +} + +int transport_load_test(char *target_url) +{ + enum { COUNT = 2000 }; + unsigned i; + pj_status_t status = PJ_SUCCESS; + + /* exhaust packets */ + do { + pj_time_val delay = {1, 0}; + i = 0; + pjsip_endpt_handle_events2(endpt, &delay, &i); + } while (i != 0); + + PJ_LOG(3,(THIS_FILE, " transport load test...")); + + if (mod_load.mod.id == -1) { + status = pjsip_endpt_register_module( endpt, &mod_load.mod); + if (status != PJ_SUCCESS) { + app_perror("error registering module", status); + return -1; + } + } + mod_load.err = PJ_FALSE; + mod_load.next_seq = 0; + + for (i=0; i"); + call_id = pj_str("thecallid"); + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &target, &from, + &target, &from, &call_id, + i, NULL, &tdata ); + if (status != PJ_SUCCESS) { + app_perror("error creating request", status); + goto on_return; + } + + status = pjsip_endpt_send_request_stateless(endpt, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + app_perror("error sending request", status); + goto on_return; + } + } + + do { + pj_time_val delay = {1, 0}; + i = 0; + pjsip_endpt_handle_events2(endpt, &delay, &i); + } while (i != 0); + + if (mod_load.next_seq != COUNT) { + PJ_LOG(1,("THIS_FILE", " err: expecting %u msg, got only %u", + COUNT, mod_load.next_seq)); + status = -2; + goto on_return; + } + +on_return: + if (mod_load.mod.id != -1) { + pjsip_endpt_unregister_module( endpt, &mod_load.mod); + mod_load.mod.id = -1; + } + if (status != PJ_SUCCESS || mod_load.err) { + return -2; + } + PJ_LOG(3,(THIS_FILE, " success")); + return 0; +} + + diff --git a/pjsip/src/test/transport_udp_test.c b/pjsip/src/test/transport_udp_test.c new file mode 100644 index 00000000..81e8d69c --- /dev/null +++ b/pjsip/src/test/transport_udp_test.c @@ -0,0 +1,128 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + +#include "test.h" +#include +#include + +#define THIS_FILE "transport_udp_test.c" + + +/* + * UDP transport test. + */ +int transport_udp_test(void) +{ + enum { SEND_RECV_LOOP = 8 }; + pjsip_transport *udp_tp, *tp; + pj_sockaddr_in addr, rem_addr; + pj_str_t s; + pj_status_t status; + int rtt[SEND_RECV_LOOP], min_rtt; + int i, pkt_lost; + + pj_sockaddr_in_init(&addr, NULL, TEST_UDP_PORT); + + /* Start UDP transport. */ + status = pjsip_udp_transport_start( endpt, &addr, NULL, 1, &udp_tp); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to start UDP transport", status); + return -10; + } + + /* UDP transport must have initial reference counter set to 1. */ + if (pj_atomic_get(udp_tp->ref_cnt) != 1) + return -20; + + /* Test basic transport attributes */ + status = generic_transport_test(udp_tp); + if (status != PJ_SUCCESS) + return status; + + /* Test that transport manager is returning the correct + * transport. + */ + pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80); + status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, + &rem_addr, sizeof(rem_addr), + NULL, &tp); + if (status != PJ_SUCCESS) + return -50; + if (tp != udp_tp) + return -60; + + /* pjsip_endpt_acquire_transport() adds reference, so we need + * to decrement it. + */ + pjsip_transport_dec_ref(tp); + + /* Check again that reference counter is 1. */ + if (pj_atomic_get(udp_tp->ref_cnt) != 1) + return -70; + + /* Basic transport's send/receive loopback test. */ + pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "127.0.0.1"), TEST_UDP_PORT); + for (i=0; iref_cnt) != 1) + return -80; + + /* Destroy this transport. */ + pjsip_transport_dec_ref(udp_tp); + + /* Force destroy this transport. */ + status = pjsip_transport_destroy(udp_tp); + if (status != PJ_SUCCESS) + return -90; + + /* Flush events. */ + PJ_LOG(3,(THIS_FILE, " Flushing events, 1 second...")); + flush_events(1000); + + /* Done */ + return 0; +} diff --git a/pjsip/src/test/tsx_basic_test.c b/pjsip/src/test/tsx_basic_test.c new file mode 100644 index 00000000..f030ea06 --- /dev/null +++ b/pjsip/src/test/tsx_basic_test.c @@ -0,0 +1,157 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + +#include "test.h" +#include +#include + +#define THIS_FILE "tsx_basic_test.c" + +static char TARGET_URI[PJSIP_MAX_URL_SIZE]; +static char FROM_URI[PJSIP_MAX_URL_SIZE]; + + +/* Test transaction layer. */ +static int tsx_layer_test(void) +{ + pj_str_t target, from, tsx_key; + pjsip_tx_data *tdata; + pjsip_transaction *tsx, *found; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " transaction layer test")); + + target = pj_str(TARGET_URI); + from = pj_str(FROM_URI); + + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, + &from, &target, NULL, NULL, -1, NULL, + &tdata); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return -110; + } + + status = pjsip_tsx_create_uac(NULL, tdata, &tsx); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create transaction", status); + return -120; + } + + pj_strdup(tdata->pool, &tsx_key, &tsx->transaction_key); + + found = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE); + if (found != tsx) { + return -130; + } + + pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); + flush_events(500); + + if (pjsip_tx_data_dec_ref(tdata) != PJSIP_EBUFDESTROYED) { + return -140; + } + + return 0; +} + +/* Double terminate test. */ +static int double_terminate(void) +{ + pj_str_t target, from, tsx_key; + pjsip_tx_data *tdata; + pjsip_transaction *tsx; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " double terminate test")); + + target = pj_str(TARGET_URI); + from = pj_str(FROM_URI); + + /* Create request. */ + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, + &from, &target, NULL, NULL, -1, NULL, + &tdata); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return -10; + } + + /* Create transaction. */ + status = pjsip_tsx_create_uac(NULL, tdata, &tsx); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create transaction", status); + return -20; + } + + /* Save transaction key for later. */ + pj_strdup_with_null(tdata->pool, &tsx_key, &tsx->transaction_key); + + /* Add reference to transmit buffer (tsx_send_msg() will dec txdata). */ + pjsip_tx_data_add_ref(tdata); + + /* Send message to start timeout timer. */ + status = pjsip_tsx_send_msg(tsx, NULL); + + /* Terminate transaction. */ + status = pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to terminate transaction", status); + return -30; + } + + tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); + if (tsx) { + /* Terminate transaction again. */ + pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to terminate transaction", status); + return -40; + } + pj_mutex_unlock(tsx->mutex); + } + + flush_events(500); + if (pjsip_tx_data_dec_ref(tdata) != PJSIP_EBUFDESTROYED) { + return -50; + } + + return PJ_SUCCESS; +} + +int tsx_basic_test(struct tsx_test_param *param) +{ + int status; + + pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + + status = tsx_layer_test(); + if (status != 0) + return status; + + status = double_terminate(); + if (status != 0) + return status; + + return 0; +} diff --git a/pjsip/src/test/tsx_bench.c b/pjsip/src/test/tsx_bench.c new file mode 100644 index 00000000..6f217a2b --- /dev/null +++ b/pjsip/src/test/tsx_bench.c @@ -0,0 +1,280 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ +#include "test.h" +#include +#include + +#define THIS_FILE "tsx_uas_test.c" + + +static pjsip_module mod_tsx_user; + +static int uac_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) +{ + unsigned i; + pjsip_tx_data *request; + pjsip_transaction **tsx; + pj_timestamp t1, t2, elapsed; + pjsip_via_hdr *via; + pj_status_t status; + + /* Create the request first. */ + pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); + pj_str_t str_from = pj_str("\"Local User\" "); + pj_str_t str_to = pj_str("\"Remote User\" "); + pj_str_t str_contact = str_from; + + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &str_target, &str_from, &str_to, + &str_contact, NULL, -1, NULL, + &request); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return status; + } + + via = (pjsip_via_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_VIA, + NULL); + + /* Create transaction array */ + tsx = (pjsip_transaction**) pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*)); + + pj_bzero(&mod_tsx_user, sizeof(mod_tsx_user)); + mod_tsx_user.id = -1; + + /* Benchmark */ + elapsed.u64 = 0; + pj_get_timestamp(&t1); + for (i=0; ibranch_param.slen = 0; + } + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&elapsed, &t2); + + p_elapsed->u64 = elapsed.u64; + status = PJ_SUCCESS; + +on_error: + for (i=0; i"); + pj_str_t str_to = pj_str("\"Remote User\" "); + pj_str_t str_contact = str_from; + + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &str_target, &str_from, &str_to, + &str_contact, NULL, -1, NULL, + &request); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return status; + } + + /* Create Via */ + via = pjsip_via_hdr_create(request->pool); + via->sent_by.host = pj_str("192.168.0.7"); + via->sent_by.port = 5061; + via->transport = pj_str("udp"); + via->rport_param = 1; + via->recvd_param = pj_str("192.168.0.7"); + pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); + + + /* Create "dummy" rdata from the tdata */ + pj_bzero(&rdata, sizeof(pjsip_rx_data)); + rdata.tp_info.pool = request->pool; + rdata.msg_info.msg = request->msg; + rdata.msg_info.from = (pjsip_from_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.to = (pjsip_to_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); + rdata.msg_info.cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); + rdata.msg_info.cid = (pjsip_cid_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.via = via; + + pj_sockaddr_in_init(&remote, 0, 0); + status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, + &remote, sizeof(pj_sockaddr_in), + NULL, &rdata.tp_info.transport); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to get loop transport", status); + return status; + } + + + /* Create transaction array */ + tsx = (pjsip_transaction**) pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*)); + + pj_bzero(&mod_tsx_user, sizeof(mod_tsx_user)); + mod_tsx_user.id = -1; + + + /* Benchmark */ + elapsed.u64 = 0; + pj_get_timestamp(&t1); + for (i=0; ibranch_param.ptr = branch_buf; + via->branch_param.slen = PJSIP_RFC3261_BRANCH_LEN + + pj_ansi_sprintf(branch_buf+PJSIP_RFC3261_BRANCH_LEN, + "-%d", i); + status = pjsip_tsx_create_uas(&mod_tsx_user, &rdata, &tsx[i]); + if (status != PJ_SUCCESS) + goto on_error; + + } + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&elapsed, &t2); + + p_elapsed->u64 = elapsed.u64; + status = PJ_SUCCESS; + +on_error: + for (i=0; ipjsip_tsx_create_uac(), based on the time " + "to create %d simultaneous transactions above.", + WORKING_SET); + + report_ival("create-uac-tsx-per-sec", + speed, "tsx/sec", desc); + + + + /* + * Benchmark UAS + */ + PJ_LOG(3,(THIS_FILE, " benchmarking UAS transaction creation:")); + for (i=0; ipjsip_tsx_create_uas(), based on the time " + "to create %d simultaneous transactions above.", + WORKING_SET); + + report_ival("create-uas-tsx-per-sec", + speed, "tsx/sec", desc); + + return PJ_SUCCESS; +} + diff --git a/pjsip/src/test/tsx_uac_test.c b/pjsip/src/test/tsx_uac_test.c new file mode 100644 index 00000000..f725114a --- /dev/null +++ b/pjsip/src/test/tsx_uac_test.c @@ -0,0 +1,1450 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + +#include "test.h" +#include +#include + +#define THIS_FILE "tsx_uac_test.c" + + +/***************************************************************************** + ** + ** UAC tests. + ** + ** This file performs various tests for UAC transactions. Each test will have + ** a different Via branch param so that message receiver module and + ** transaction user module can identify which test is being carried out. + ** + ** TEST1_BRANCH_ID + ** Perform basic retransmission and timeout test. Message receiver will + ** verify that retransmission is received at correct time. + ** This test verifies the following requirements: + ** - retransmit timer doubles for INVITE + ** - retransmit timer doubles and caps off for non-INVITE + ** - retransmit timer timer is precise + ** - correct timeout and retransmission count + ** Requirements not tested: + ** - retransmit timer only starts after resolving has completed. + ** + ** TEST2_BRANCH_ID + ** Test scenario where resolver is unable to resolve destination host. + ** + ** TEST3_BRANCH_ID + ** Test scenario where transaction is terminated while resolver is still + ** running. + ** + ** TEST4_BRANCH_ID + ** Test scenario where transport failed after several retransmissions. + ** + ** TEST5_BRANCH_ID + ** Test scenario where transaction is terminated by user after several + ** retransmissions. + ** + ** TEST6_BRANCH_ID + ** Test successfull non-INVITE transaction. + ** It tests the following requirements: + ** - transaction correctly moves to COMPLETED state. + ** - retransmission must cease. + ** - tx_data must be maintained until state is terminated. + ** + ** TEST7_BRANCH_ID + ** Test successfull non-INVITE transaction, with provisional response. + ** + ** TEST8_BRANCH_ID + ** Test failed INVITE transaction (e.g. ACK must be received) + ** + ** TEST9_BRANCH_ID + ** Test failed INVITE transaction with provisional response. + ** + ** + ***************************************************************************** + */ + +static char *TEST1_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test1"; +static char *TEST2_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test2"; +static char *TEST3_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test3"; +static char *TEST4_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test4"; +static char *TEST5_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test5"; +static char *TEST6_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test6"; +static char *TEST7_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test7"; +static char *TEST8_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test8"; +static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test9"; + +#define TEST1_ALLOWED_DIFF (150) +#define TEST4_RETRANSMIT_CNT 3 +#define TEST5_RETRANSMIT_CNT 3 + +static char TARGET_URI[128]; +static char FROM_URI[128]; +static unsigned tp_flag; +static struct tsx_test_param *test_param; + +static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e); +static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata); + +/* UAC transaction user module. */ +static pjsip_module tsx_user = +{ + NULL, NULL, /* prev and next */ + { "Tsx-UAC-User", 12}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + NULL, /* on_rx_request() */ + NULL, /* on_rx_response() */ + NULL, /* on_tx_request() */ + NULL, /* on_tx_response() */ + &tsx_user_on_tsx_state, /* on_tsx_state() */ +}; + +/* Module to receive the loop-backed request. */ +static pjsip_module msg_receiver = +{ + NULL, NULL, /* prev and next */ + { "Msg-Receiver", 12}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + &msg_receiver_on_rx_request, /* on_rx_request() */ + NULL, /* on_rx_response() */ + NULL, /* on_tx_request() */ + NULL, /* on_tx_response() */ + NULL, /* on_tsx_state() */ +}; + +/* Static vars, which will be reset on each test. */ +static int recv_count; +static pj_time_val recv_last; +static pj_bool_t test_complete; + +/* Loop transport instance. */ +static pjsip_transport *loop; + +/* General timer entry to be used by tests. */ +static struct my_timer +{ + pj_timer_entry entry; + char key_buf[1024]; + pj_str_t tsx_key; +} timer; + +/* + * This is the handler to receive state changed notification from the + * transaction. It is used to verify that the transaction behaves according + * to the test scenario. + */ +static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) +{ + if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) { + /* + * Transaction with TEST1_BRANCH_ID should terminate with transaction + * timeout status. + */ + if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + if (test_complete == 0) + test_complete = 1; + + /* Test the status code. */ + if (tsx->status_code != PJSIP_SC_TSX_TIMEOUT) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, PJSIP_SC_TSX_TIMEOUT)); + test_complete = -710; + } + + + /* If transport is reliable, then there must not be any + * retransmissions. + */ + if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { + if (recv_count != 1) { + PJ_LOG(3,(THIS_FILE, + " error: there were %d (re)transmissions", + recv_count)); + test_complete = -715; + } + } else { + /* Check the number of transmissions, which must be + * 6 for INVITE and 10 for non-INVITE + */ + if (tsx->method.id==PJSIP_INVITE_METHOD && recv_count != 7) { + PJ_LOG(3,(THIS_FILE, + " error: there were %d (re)transmissions", + recv_count)); + test_complete = -716; + } else + if (tsx->method.id==PJSIP_OPTIONS_METHOD && recv_count != 11) { + PJ_LOG(3,(THIS_FILE, + " error: there were %d (re)transmissions", + recv_count)); + test_complete = -717; + } else + if (tsx->method.id!=PJSIP_INVITE_METHOD && + tsx->method.id!=PJSIP_OPTIONS_METHOD) + { + PJ_LOG(3,(THIS_FILE, " error: unexpected method")); + test_complete = -718; + } + } + } + + } else if (pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) { + /* + * Transaction with TEST2_BRANCH_ID should terminate with transport error. + */ + if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + /* Test the status code. */ + if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR)); + test_complete = -720; + } + + if (test_complete == 0) + test_complete = 1; + } + + } else if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) { + /* + * This test terminates the transaction while resolver is still + * running. + */ + if (tsx->state == PJSIP_TSX_STATE_CALLING) { + + /* Terminate the transaction. */ + pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); + + } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + /* Check if status code is correct. */ + if (tsx->status_code != PJSIP_SC_REQUEST_TERMINATED) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, PJSIP_SC_REQUEST_TERMINATED)); + test_complete = -730; + } + + if (test_complete == 0) + test_complete = 1; + + } + + } else if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) { + /* + * This test simulates transport failure after several + * retransmissions. + */ + if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + /* Status code must be transport error. */ + if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR)); + test_complete = -730; + } + + /* Must have correct retransmission count. */ + if (tsx->retransmit_count != TEST4_RETRANSMIT_CNT) { + PJ_LOG(3,(THIS_FILE, + " error: retransmit cnt is %d instead of %d", + tsx->retransmit_count, TEST4_RETRANSMIT_CNT)); + test_complete = -731; + } + + if (test_complete == 0) + test_complete = 1; + } + + + } else if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) { + /* + * This test simulates transport failure after several + * retransmissions. + */ + if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + /* Status code must be PJSIP_SC_REQUEST_TERMINATED. */ + if (tsx->status_code != PJSIP_SC_REQUEST_TERMINATED) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, PJSIP_SC_REQUEST_TERMINATED)); + test_complete = -733; + } + + /* Must have correct retransmission count. */ + if (tsx->retransmit_count != TEST5_RETRANSMIT_CNT) { + PJ_LOG(3,(THIS_FILE, + " error: retransmit cnt is %d instead of %d", + tsx->retransmit_count, TEST5_RETRANSMIT_CNT)); + test_complete = -734; + } + + if (test_complete == 0) + test_complete = 1; + } + + + } else if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) { + /* + * Successfull non-INVITE transaction. + */ + if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { + + /* Status code must be 202. */ + if (tsx->status_code != 202) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, 202)); + test_complete = -736; + } + + /* Must have correct retransmission count. */ + if (tsx->retransmit_count != 0) { + PJ_LOG(3,(THIS_FILE, + " error: retransmit cnt is %d instead of %d", + tsx->retransmit_count, 0)); + test_complete = -737; + } + + /* Must still keep last_tx */ + if (tsx->last_tx == NULL) { + PJ_LOG(3,(THIS_FILE, + " error: transaction lost last_tx")); + test_complete = -738; + } + + if (test_complete == 0) { + test_complete = 1; + pjsip_tsx_terminate(tsx, 202); + } + + } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + /* Previous state must be COMPLETED. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { + test_complete = -7381; + } + + } + + } else if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0) { + /* + * Successfull non-INVITE transaction. + */ + if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { + + /* Check prev state. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) { + PJ_LOG(3,(THIS_FILE, + " error: prev state is %s instead of %s", + pjsip_tsx_state_str((pjsip_tsx_state_e)e->body.tsx_state.prev_state), + pjsip_tsx_state_str(PJSIP_TSX_STATE_PROCEEDING))); + test_complete = -739; + } + + /* Status code must be 202. */ + if (tsx->status_code != 202) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, 202)); + test_complete = -740; + } + + /* Must have correct retransmission count. */ + if (tsx->retransmit_count != 0) { + PJ_LOG(3,(THIS_FILE, + " error: retransmit cnt is %d instead of %d", + tsx->retransmit_count, 0)); + test_complete = -741; + } + + /* Must still keep last_tx */ + if (tsx->last_tx == NULL) { + PJ_LOG(3,(THIS_FILE, + " error: transaction lost last_tx")); + test_complete = -741; + } + + if (test_complete == 0) { + test_complete = 1; + pjsip_tsx_terminate(tsx, 202); + } + + } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + /* Previous state must be COMPLETED. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { + test_complete = -742; + } + + } + + + } else if (pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0) { + /* + * Failed INVITE transaction. + */ + if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { + + /* Status code must be 301. */ + if (tsx->status_code != 301) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, 301)); + test_complete = -745; + } + + /* Must have correct retransmission count. */ + if (tsx->retransmit_count != 0) { + PJ_LOG(3,(THIS_FILE, + " error: retransmit cnt is %d instead of %d", + tsx->retransmit_count, 0)); + test_complete = -746; + } + + /* Must still keep last_tx */ + if (tsx->last_tx == NULL) { + PJ_LOG(3,(THIS_FILE, + " error: transaction lost last_tx")); + test_complete = -747; + } + + /* last_tx MUST be the INVITE request + * (authorization depends on this behavior) + */ + if (tsx->last_tx && tsx->last_tx->msg->line.req.method.id != + PJSIP_INVITE_METHOD) + { + PJ_LOG(3,(THIS_FILE, + " error: last_tx is not INVITE")); + test_complete = -748; + } + } + else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + test_complete = 1; + + /* Previous state must be COMPLETED. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { + test_complete = -750; + } + + /* Status code must be 301. */ + if (tsx->status_code != 301) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, 301)); + test_complete = -751; + } + + } + + + } else if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) { + /* + * Failed INVITE transaction with provisional response. + */ + if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { + + /* Previous state must be PJSIP_TSX_STATE_PROCEEDING. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) { + test_complete = -760; + } + + /* Status code must be 302. */ + if (tsx->status_code != 302) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, 302)); + test_complete = -761; + } + + /* Must have correct retransmission count. */ + if (tsx->retransmit_count != 0) { + PJ_LOG(3,(THIS_FILE, + " error: retransmit cnt is %d instead of %d", + tsx->retransmit_count, 0)); + test_complete = -762; + } + + /* Must still keep last_tx */ + if (tsx->last_tx == NULL) { + PJ_LOG(3,(THIS_FILE, + " error: transaction lost last_tx")); + test_complete = -763; + } + + /* last_tx MUST be INVITE. + * (authorization depends on this behavior) + */ + if (tsx->last_tx && tsx->last_tx->msg->line.req.method.id != + PJSIP_INVITE_METHOD) + { + PJ_LOG(3,(THIS_FILE, + " error: last_tx is not INVITE")); + test_complete = -764; + } + + } + else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + test_complete = 1; + + /* Previous state must be COMPLETED. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { + test_complete = -767; + } + + /* Status code must be 302. */ + if (tsx->status_code != 302) { + PJ_LOG(3,(THIS_FILE, + " error: status code is %d instead of %d", + tsx->status_code, 302)); + test_complete = -768; + } + + } + + } +} + +/* + * This timer callback is called to send delayed response. + */ +struct response +{ + pjsip_response_addr res_addr; + pjsip_tx_data *tdata; +}; + +static void send_response_callback( pj_timer_heap_t *timer_heap, + struct pj_timer_entry *entry) +{ + struct response *r = (struct response*) entry->user_data; + pjsip_transport *tp = r->res_addr.transport; + + pjsip_endpt_send_response(endpt, &r->res_addr, r->tdata, NULL, NULL); + if (tp) + pjsip_transport_dec_ref(tp); +} + +/* Timer callback to terminate a transaction. */ +static void terminate_tsx_callback( pj_timer_heap_t *timer_heap, + struct pj_timer_entry *entry) +{ + struct my_timer *m = (struct my_timer *)entry; + pjsip_transaction *tsx = pjsip_tsx_layer_find_tsx(&m->tsx_key, PJ_FALSE); + int status_code = entry->id; + + if (tsx) { + pjsip_tsx_terminate(tsx, status_code); + } +} + + +#define DIFF(a,b) ((amsg_info.via->branch_param, TEST1_BRANCH_ID) == 0) { + /* + * The TEST1_BRANCH_ID test performs the verifications for transaction + * retransmission mechanism. It will not answer the incoming request + * with any response. + */ + pjsip_msg *msg = rdata->msg_info.msg; + + PJ_LOG(4,(THIS_FILE, " received request")); + + /* Only wants to take INVITE or OPTIONS method. */ + if (msg->line.req.method.id != PJSIP_INVITE_METHOD && + msg->line.req.method.id != PJSIP_OPTIONS_METHOD) + { + PJ_LOG(3,(THIS_FILE, " error: received unexpected method %.*s", + msg->line.req.method.name.slen, + msg->line.req.method.name.ptr)); + test_complete = -600; + return PJ_TRUE; + } + + if (recv_count == 0) { + recv_count++; + //pj_gettimeofday(&recv_last); + recv_last = rdata->pkt_info.timestamp; + } else { + pj_time_val now; + unsigned msec_expected, msec_elapsed; + int max_received; + + //pj_gettimeofday(&now); + now = rdata->pkt_info.timestamp; + PJ_TIME_VAL_SUB(now, recv_last); + msec_elapsed = now.sec*1000 + now.msec; + + ++recv_count; + msec_expected = (1<<(recv_count-2))*pjsip_cfg()->tsx.t1; + + if (msg->line.req.method.id != PJSIP_INVITE_METHOD) { + if (msec_expected > pjsip_cfg()->tsx.t2) + msec_expected = pjsip_cfg()->tsx.t2; + max_received = 11; + } else { + max_received = 7; + } + + if (DIFF(msec_expected, msec_elapsed) > TEST1_ALLOWED_DIFF) { + PJ_LOG(3,(THIS_FILE, + " error: expecting retransmission no. %d in %d " + "ms, received in %d ms", + recv_count-1, msec_expected, msec_elapsed)); + test_complete = -610; + } + + + if (recv_count > max_received) { + PJ_LOG(3,(THIS_FILE, + " error: too many messages (%d) received", + recv_count)); + test_complete = -620; + } + + //pj_gettimeofday(&recv_last); + recv_last = rdata->pkt_info.timestamp; + } + return PJ_TRUE; + + } else + if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID) == 0) { + /* + * The TEST4_BRANCH_ID test simulates transport failure after several + * retransmissions. + */ + recv_count++; + + if (recv_count == TEST4_RETRANSMIT_CNT) { + /* Simulate transport failure. */ + pjsip_loop_set_failure(loop, 2, NULL); + + } else if (recv_count > TEST4_RETRANSMIT_CNT) { + PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", + recv_count)); + test_complete = -631; + } + + return PJ_TRUE; + + + } else + if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID) == 0) { + /* + * The TEST5_BRANCH_ID test simulates user terminating the transaction + * after several retransmissions. + */ + recv_count++; + + if (recv_count == TEST5_RETRANSMIT_CNT+1) { + pj_str_t key; + pjsip_transaction *tsx; + + pjsip_tsx_create_key( rdata->tp_info.pool, &key, PJSIP_ROLE_UAC, + &rdata->msg_info.msg->line.req.method, rdata); + tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE); + if (tsx) { + pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); + pj_mutex_unlock(tsx->mutex); + } else { + PJ_LOG(3,(THIS_FILE, " error: uac transaction not found!")); + test_complete = -633; + } + + } else if (recv_count > TEST5_RETRANSMIT_CNT+1) { + PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", + recv_count)); + test_complete = -634; + } + + return PJ_TRUE; + + } else + if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID) == 0) { + /* + * The TEST6_BRANCH_ID test successfull non-INVITE transaction. + */ + pj_status_t status; + + recv_count++; + + if (recv_count > 1) { + PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", + recv_count)); + test_complete = -635; + } + + status = pjsip_endpt_respond_stateless(endpt, rdata, 202, NULL, + NULL, NULL); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to send response", status); + test_complete = -636; + } + + return PJ_TRUE; + + + } else + if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST7_BRANCH_ID) == 0) { + /* + * The TEST7_BRANCH_ID test successfull non-INVITE transaction + * with provisional response. + */ + pj_status_t status; + pjsip_response_addr res_addr; + struct response *r; + pjsip_tx_data *tdata; + pj_time_val delay = { 2, 0 }; + + recv_count++; + + if (recv_count > 1) { + PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", + recv_count)); + test_complete = -640; + return PJ_TRUE; + } + + /* Respond with provisional response */ + status = pjsip_endpt_create_response(endpt, rdata, 100, NULL, &tdata); + pj_assert(status == PJ_SUCCESS); + + status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr); + pj_assert(status == PJ_SUCCESS); + + status = pjsip_endpt_send_response(endpt, &res_addr, tdata, + NULL, NULL); + pj_assert(status == PJ_SUCCESS); + + /* Create the final response. */ + status = pjsip_endpt_create_response(endpt, rdata, 202, NULL, &tdata); + pj_assert(status == PJ_SUCCESS); + + /* Schedule sending final response in couple of of secs. */ + r = PJ_POOL_ALLOC_T(tdata->pool, struct response); + r->res_addr = res_addr; + r->tdata = tdata; + if (r->res_addr.transport) + pjsip_transport_add_ref(r->res_addr.transport); + + timer.entry.cb = &send_response_callback; + timer.entry.user_data = r; + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); + + return PJ_TRUE; + + + } else + if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST8_BRANCH_ID) == 0) { + /* + * The TEST8_BRANCH_ID test failed INVITE transaction. + */ + pjsip_method *method; + pj_status_t status; + + method = &rdata->msg_info.msg->line.req.method; + + recv_count++; + + if (method->id == PJSIP_INVITE_METHOD) { + + if (recv_count > 1) { + PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", + recv_count)); + test_complete = -635; + } + + status = pjsip_endpt_respond_stateless(endpt, rdata, 301, NULL, + NULL, NULL); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to send response", status); + test_complete = -636; + } + + } else if (method->id == PJSIP_ACK_METHOD) { + + if (recv_count == 2) { + pj_str_t key; + pj_time_val delay = { 5, 0 }; + + /* Schedule timer to destroy transaction after 5 seconds. + * This is to make sure that transaction does not + * retransmit ACK. + */ + pjsip_tsx_create_key(rdata->tp_info.pool, &key, + PJSIP_ROLE_UAC, &pjsip_invite_method, + rdata); + + pj_strcpy(&timer.tsx_key, &key); + timer.entry.id = 301; + timer.entry.cb = &terminate_tsx_callback; + + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); + } + + if (recv_count > 2) { + PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", + recv_count)); + test_complete = -638; + } + + + } else { + PJ_LOG(3,(THIS_FILE," error: not expecting %s", + pjsip_rx_data_get_info(rdata))); + test_complete = -639; + + } + + + } else + if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST9_BRANCH_ID) == 0) { + /* + * The TEST9_BRANCH_ID test failed INVITE transaction with + * provisional response. + */ + pjsip_method *method; + pj_status_t status; + + method = &rdata->msg_info.msg->line.req.method; + + recv_count++; + + if (method->id == PJSIP_INVITE_METHOD) { + + pjsip_response_addr res_addr; + struct response *r; + pjsip_tx_data *tdata; + pj_time_val delay = { 2, 0 }; + + if (recv_count > 1) { + PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", + recv_count)); + test_complete = -650; + return PJ_TRUE; + } + + /* Respond with provisional response */ + status = pjsip_endpt_create_response(endpt, rdata, 100, NULL, + &tdata); + pj_assert(status == PJ_SUCCESS); + + status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr); + pj_assert(status == PJ_SUCCESS); + + status = pjsip_endpt_send_response(endpt, &res_addr, tdata, + NULL, NULL); + pj_assert(status == PJ_SUCCESS); + + /* Create the final response. */ + status = pjsip_endpt_create_response(endpt, rdata, 302, NULL, + &tdata); + pj_assert(status == PJ_SUCCESS); + + /* Schedule sending final response in couple of of secs. */ + r = PJ_POOL_ALLOC_T(tdata->pool, struct response); + r->res_addr = res_addr; + r->tdata = tdata; + if (r->res_addr.transport) + pjsip_transport_add_ref(r->res_addr.transport); + + timer.entry.cb = &send_response_callback; + timer.entry.user_data = r; + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); + + } else if (method->id == PJSIP_ACK_METHOD) { + + if (recv_count == 2) { + pj_str_t key; + pj_time_val delay = { 5, 0 }; + + /* Schedule timer to destroy transaction after 5 seconds. + * This is to make sure that transaction does not + * retransmit ACK. + */ + pjsip_tsx_create_key(rdata->tp_info.pool, &key, + PJSIP_ROLE_UAC, &pjsip_invite_method, + rdata); + + pj_strcpy(&timer.tsx_key, &key); + timer.entry.id = 302; + timer.entry.cb = &terminate_tsx_callback; + + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); + } + + if (recv_count > 2) { + PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", + recv_count)); + test_complete = -638; + } + + + } else { + PJ_LOG(3,(THIS_FILE," error: not expecting %s", + pjsip_rx_data_get_info(rdata))); + test_complete = -639; + + } + + return PJ_TRUE; + + } + + return PJ_FALSE; +} + +/* + * The generic test framework, used by most of the tests. + */ +static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, + char *branch_param, int test_time, + const pjsip_method *method) +{ + pjsip_tx_data *tdata; + pjsip_transaction *tsx; + pj_str_t target, from, tsx_key; + pjsip_via_hdr *via; + pj_time_val timeout; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, + " please standby, this will take at most %d seconds..", + test_time)); + + /* Reset test. */ + recv_count = 0; + test_complete = 0; + + /* Init headers. */ + target = pj_str(target_uri); + from = pj_str(from_uri); + + /* Create request. */ + status = pjsip_endpt_create_request( endpt, method, &target, + &from, &target, NULL, NULL, -1, + NULL, &tdata); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to create request", status); + return -100; + } + + /* Set the branch param for test 1. */ + via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); + via->branch_param = pj_str(branch_param); + + /* Add additional reference to tdata to prevent transaction from + * deleting it. + */ + pjsip_tx_data_add_ref(tdata); + + /* Create transaction. */ + status = pjsip_tsx_create_uac( &tsx_user, tdata, &tsx); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to create UAC transaction", status); + pjsip_tx_data_dec_ref(tdata); + return -110; + } + + /* Get transaction key. */ + pj_strdup(tdata->pool, &tsx_key, &tsx->transaction_key); + + /* Send the message. */ + status = pjsip_tsx_send_msg(tsx, NULL); + // Ignore send result. Some tests do deliberately triggers error + // when sending message. + if (status != PJ_SUCCESS) { + // app_perror(" Error: unable to send request", status); + pjsip_tx_data_dec_ref(tdata); + // return -120; + } + + + /* Set test completion time. */ + pj_gettimeofday(&timeout); + timeout.sec += test_time; + + /* Wait until test complete. */ + while (!test_complete) { + pj_time_val now, poll_delay = {0, 10}; + + pjsip_endpt_handle_events(endpt, &poll_delay); + + pj_gettimeofday(&now); + if (now.sec > timeout.sec) { + PJ_LOG(3,(THIS_FILE, " Error: test has timed out")); + pjsip_tx_data_dec_ref(tdata); + return -130; + } + } + + if (test_complete < 0) { + tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); + if (tsx) { + pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); + pj_mutex_unlock(tsx->mutex); + flush_events(1000); + } + pjsip_tx_data_dec_ref(tdata); + return test_complete; + + } else { + pj_time_val now; + + /* Allow transaction to destroy itself */ + flush_events(500); + + /* Wait until test completes */ + pj_gettimeofday(&now); + + if (PJ_TIME_VAL_LT(now, timeout)) { + pj_time_val interval; + interval = timeout; + PJ_TIME_VAL_SUB(interval, now); + flush_events(PJ_TIME_VAL_MSEC(interval)); + } + } + + /* Make sure transaction has been destroyed. */ + if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) { + PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed")); + pjsip_tx_data_dec_ref(tdata); + return -140; + } + + /* Check tdata reference counter. */ + if (pj_atomic_get(tdata->ref_cnt) != 1) { + PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %d", + pj_atomic_get(tdata->ref_cnt))); + pjsip_tx_data_dec_ref(tdata); + return -150; + } + + /* Destroy txdata */ + pjsip_tx_data_dec_ref(tdata); + + return PJ_SUCCESS; +} + +/***************************************************************************** + ** + ** TEST1_BRANCH_ID: UAC basic retransmission and timeout test. + ** + ** This will test the retransmission of the UAC transaction. Remote will not + ** answer the transaction, so the transaction should fail. The Via branch prm + ** TEST1_BRANCH_ID will be used for this test. + ** + ***************************************************************************** + */ +static int tsx_uac_retransmit_test(void) +{ + int status, enabled; + int i; + struct { + const pjsip_method *method; + unsigned delay; + } sub_test[] = + { + { &pjsip_invite_method, 0}, + { &pjsip_invite_method, TEST1_ALLOWED_DIFF*2}, + { &pjsip_options_method, 0}, + { &pjsip_options_method, TEST1_ALLOWED_DIFF*2} + }; + + PJ_LOG(3,(THIS_FILE, " test1: basic uac retransmit and timeout test")); + + + /* For this test. message printing shound be disabled because it makes + * incorrect timing. + */ + enabled = msg_logger_set_enabled(0); + + for (i=0; i<(int)PJ_ARRAY_SIZE(sub_test); ++i) { + + PJ_LOG(3,(THIS_FILE, + " variant %c: %s with %d ms network delay", + ('a' + i), + sub_test[i].method->name.ptr, + sub_test[i].delay)); + + /* Configure transport */ + pjsip_loop_set_failure(loop, 0, NULL); + pjsip_loop_set_recv_delay(loop, sub_test[i].delay, NULL); + + /* Do the test. */ + status = perform_tsx_test(-500, TARGET_URI, FROM_URI, + TEST1_BRANCH_ID, + 35, sub_test[i].method); + if (status != 0) + break; + } + + /* Restore transport. */ + pjsip_loop_set_recv_delay(loop, 0, NULL); + + /* Restore msg logger. */ + msg_logger_set_enabled(enabled); + + /* Done. */ + return status; +} + +/***************************************************************************** + ** + ** TEST2_BRANCH_ID: UAC resolve error test. + ** + ** Test the scenario where destination host is unresolvable. There are + ** two variants: + ** (a) resolver returns immediate error + ** (b) resolver returns error via the callback. + ** + ***************************************************************************** + */ +static int tsx_resolve_error_test(void) +{ + int status; + + PJ_LOG(3,(THIS_FILE, " test2: resolve error test")); + + /* + * Variant (a): immediate resolve error. + */ + PJ_LOG(3,(THIS_FILE, " variant a: immediate resolving error")); + + status = perform_tsx_test(-800, + "sip:bob@unresolved-host", + FROM_URI, TEST2_BRANCH_ID, 20, + &pjsip_options_method); + if (status != 0) + return status; + + /* + * Variant (b): error via callback. + */ + PJ_LOG(3,(THIS_FILE, " variant b: error via callback")); + + /* This only applies to "loop-dgram" transport */ + if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + /* Set loop transport to return delayed error. */ + pjsip_loop_set_failure(loop, 2, NULL); + pjsip_loop_set_send_callback_delay(loop, 10, NULL); + + status = perform_tsx_test(-800, TARGET_URI, FROM_URI, + TEST2_BRANCH_ID, 2, + &pjsip_options_method); + if (status != 0) + return status; + + /* Restore loop transport settings. */ + pjsip_loop_set_failure(loop, 0, NULL); + pjsip_loop_set_send_callback_delay(loop, 0, NULL); + } + + return status; +} + + +/***************************************************************************** + ** + ** TEST3_BRANCH_ID: UAC terminate while resolving test. + ** + ** Terminate the transaction while resolver is still running. + ** + ***************************************************************************** + */ +static int tsx_terminate_resolving_test(void) +{ + unsigned prev_delay; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " test3: terminate while resolving test")); + + /* Configure transport delay. */ + pjsip_loop_set_send_callback_delay(loop, 100, &prev_delay); + + /* Start the test. */ + status = perform_tsx_test(-900, TARGET_URI, FROM_URI, + TEST3_BRANCH_ID, 2, &pjsip_options_method); + + /* Restore delay. */ + pjsip_loop_set_send_callback_delay(loop, prev_delay, NULL); + + return status; +} + + +/***************************************************************************** + ** + ** TEST4_BRANCH_ID: Transport failed after several retransmissions + ** + ** There are two variants of this test: (a) failure occurs immediately when + ** transaction calls pjsip_transport_send() or (b) failure is reported via + ** transport callback. + ** + ***************************************************************************** + */ +static int tsx_retransmit_fail_test(void) +{ + int i; + unsigned delay[] = {0, 10}; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, + " test4: transport fails after several retransmissions test")); + + + for (i=0; i<(int)PJ_ARRAY_SIZE(delay); ++i) { + + PJ_LOG(3,(THIS_FILE, + " variant %c: transport delay %d ms", ('a'+i), delay[i])); + + /* Configure transport delay. */ + pjsip_loop_set_send_callback_delay(loop, delay[i], NULL); + + /* Restore transport failure mode. */ + pjsip_loop_set_failure(loop, 0, 0); + + /* Start the test. */ + status = perform_tsx_test(-1000, TARGET_URI, FROM_URI, + TEST4_BRANCH_ID, 6, &pjsip_options_method); + + if (status != 0) + break; + + } + + /* Restore delay. */ + pjsip_loop_set_send_callback_delay(loop, 0, NULL); + + /* Restore transport failure mode. */ + pjsip_loop_set_failure(loop, 0, 0); + + return status; +} + + +/***************************************************************************** + ** + ** TEST5_BRANCH_ID: Terminate transaction after several retransmissions + ** + ***************************************************************************** + */ +static int tsx_terminate_after_retransmit_test(void) +{ + int status; + + PJ_LOG(3,(THIS_FILE, " test5: terminate after retransmissions")); + + /* Do the test. */ + status = perform_tsx_test(-1100, TARGET_URI, FROM_URI, + TEST5_BRANCH_ID, + 6, &pjsip_options_method); + + /* Done. */ + return status; +} + + +/***************************************************************************** + ** + ** TEST6_BRANCH_ID: Successfull non-invite transaction + ** TEST7_BRANCH_ID: Successfull non-invite transaction with provisional + ** TEST8_BRANCH_ID: Failed invite transaction + ** TEST9_BRANCH_ID: Failed invite transaction with provisional + ** + ***************************************************************************** + */ +static int perform_generic_test( const char *title, + char *branch_id, + const pjsip_method *method) +{ + int i, status; + unsigned delay[] = { 1, 200 }; + + PJ_LOG(3,(THIS_FILE, " %s", title)); + + /* Do the test. */ + for (i=0; i<(int)PJ_ARRAY_SIZE(delay); ++i) { + + if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + PJ_LOG(3,(THIS_FILE, " variant %c: with %d ms transport delay", + ('a'+i), delay[i])); + + pjsip_loop_set_delay(loop, delay[i]); + } + + status = perform_tsx_test(-1200, TARGET_URI, FROM_URI, + branch_id, 10, method); + if (status != 0) + return status; + + if (test_param->type != PJSIP_TRANSPORT_LOOP_DGRAM) + break; + } + + pjsip_loop_set_delay(loop, 0); + + /* Done. */ + return status; +} + + +/***************************************************************************** + ** + ** UAC Transaction Test. + ** + ***************************************************************************** + */ +int tsx_uac_test(struct tsx_test_param *param) +{ + pj_sockaddr_in addr; + pj_status_t status; + + timer.tsx_key.ptr = timer.key_buf; + + test_param = param; + + /* Get transport flag */ + tp_flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)test_param->type); + + pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + + /* Check if loop transport is configured. */ + status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, + &addr, sizeof(addr), NULL, &loop); + if (status != PJ_SUCCESS) { + PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!")); + return -10; + } + + /* Register modules. */ + status = pjsip_endpt_register_module(endpt, &tsx_user); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to register module", status); + return -30; + } + status = pjsip_endpt_register_module(endpt, &msg_receiver); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to register module", status); + return -40; + } + + /* TEST1_BRANCH_ID: Basic retransmit and timeout test. */ + status = tsx_uac_retransmit_test(); + if (status != 0) + return status; + + /* TEST2_BRANCH_ID: Resolve error test. */ + status = tsx_resolve_error_test(); + if (status != 0) + return status; + + /* TEST3_BRANCH_ID: UAC terminate while resolving test. */ + status = tsx_terminate_resolving_test(); + if (status != 0) + return status; + + /* TEST4_BRANCH_ID: Transport failed after several retransmissions. + * Only applies to loop transport. + */ + if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + status = tsx_retransmit_fail_test(); + if (status != 0) + return status; + } + + /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions + * Only applicable to non-reliable transports. + */ + if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_terminate_after_retransmit_test(); + if (status != 0) + return status; + } + + /* TEST6_BRANCH_ID: Successfull non-invite transaction */ + status = perform_generic_test("test6: successfull non-invite transaction", + TEST6_BRANCH_ID, &pjsip_options_method); + if (status != 0) + return status; + + /* TEST7_BRANCH_ID: Successfull non-invite transaction */ + status = perform_generic_test("test7: successfull non-invite transaction " + "with provisional response", + TEST7_BRANCH_ID, &pjsip_options_method); + if (status != 0) + return status; + + /* TEST8_BRANCH_ID: Failed invite transaction */ + status = perform_generic_test("test8: failed invite transaction", + TEST8_BRANCH_ID, &pjsip_invite_method); + if (status != 0) + return status; + + /* TEST9_BRANCH_ID: Failed invite transaction with provisional response */ + status = perform_generic_test("test9: failed invite transaction with " + "provisional response", + TEST9_BRANCH_ID, &pjsip_invite_method); + if (status != 0) + return status; + + pjsip_transport_dec_ref(loop); + flush_events(500); + + /* Unregister modules. */ + status = pjsip_endpt_unregister_module(endpt, &tsx_user); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -31; + } + status = pjsip_endpt_unregister_module(endpt, &msg_receiver); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -41; + } + + return 0; +} + diff --git a/pjsip/src/test/tsx_uas_test.c b/pjsip/src/test/tsx_uas_test.c new file mode 100644 index 00000000..813e4e50 --- /dev/null +++ b/pjsip/src/test/tsx_uas_test.c @@ -0,0 +1,1656 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + +#include "test.h" +#include +#include + +#define THIS_FILE "tsx_uas_test.c" + + +/***************************************************************************** + ** + ** UAS tests. + ** + ** This file performs various tests for UAC transactions. Each test will have + ** a different Via branch param so that message receiver module and + ** transaction user module can identify which test is being carried out. + ** + ** TEST1_BRANCH_ID + ** Test that non-INVITE transaction returns 2xx response to the correct + ** transport and correctly terminates the transaction. + ** This also checks that transaction is destroyed immediately after + ** it sends final response when reliable transport is used. + ** + ** TEST2_BRANCH_ID + ** As above, for non-2xx final response. + ** + ** TEST3_BRANCH_ID + ** Transaction correctly progressing to PROCEEDING state when provisional + ** response is sent. + ** + ** TEST4_BRANCH_ID + ** Transaction retransmits last response (if any) without notifying + ** transaction user upon receiving request retransmissions on TRYING + ** state + ** + ** TEST5_BRANCH_ID + ** As above, in PROCEEDING state. + ** + ** TEST6_BRANCH_ID + ** As above, in COMPLETED state, with first sending provisional response. + ** (Only applicable for non-reliable transports). + ** + ** TEST7_BRANCH_ID + ** INVITE transaction MUST retransmit non-2xx final response. + ** + ** TEST8_BRANCH_ID + ** As above, for INVITE's 2xx final response (this is PJSIP specific). + ** + ** TEST9_BRANCH_ID + ** INVITE transaction MUST cease retransmission of final response when + ** ACK is received. (Note: PJSIP also retransmit 2xx final response + ** until it's terminated by user). + ** Transaction also MUST terminate in T4 seconds. + ** (Only applicable for non-reliable transports). + ** + ** TEST11_BRANCH_ID + ** Test scenario where transport fails before response is sent (i.e. + ** in TRYING state). + ** + ** TEST12_BRANCH_ID + ** As above, after provisional response is sent but before final + ** response is sent (i.e. in PROCEEDING state). + ** + ** TEST13_BRANCH_ID + ** As above, for INVITE, after final response has been sent but before + ** ACK is received (i.e. in CONNECTED state). + ** + ** TEST14_BRANCH_ID + ** When UAS failed to deliver the response with the selected transport, + ** it should try contacting the client with other transport or begin + ** RFC 3263 server resolution procedure. + ** This should be tested on: + ** a. TRYING state (when delivering first response). + ** b. PROCEEDING state (when failed to retransmit last response + ** upon receiving request retransmission). + ** c. COMPLETED state. + ** + **/ + +static char *TEST1_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test1"; +static char *TEST2_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test2"; +static char *TEST3_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test3"; +static char *TEST4_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test4"; +static char *TEST5_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test5"; +static char *TEST6_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test6"; +static char *TEST7_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test7"; +static char *TEST8_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test8"; +static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test9"; +static char *TEST10_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test10"; +static char *TEST11_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test11"; +static char *TEST12_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test12"; +//static char *TEST13_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test13"; + +#define TEST1_STATUS_CODE 200 +#define TEST2_STATUS_CODE 301 +#define TEST3_PROVISIONAL_CODE PJSIP_SC_QUEUED +#define TEST3_STATUS_CODE 202 +#define TEST4_STATUS_CODE 200 +#define TEST4_REQUEST_COUNT 2 +#define TEST5_PROVISIONAL_CODE 100 +#define TEST5_STATUS_CODE 200 +#define TEST5_REQUEST_COUNT 2 +#define TEST5_RESPONSE_COUNT 2 +#define TEST6_PROVISIONAL_CODE 100 +#define TEST6_STATUS_CODE 200 /* Must be final */ +#define TEST6_REQUEST_COUNT 2 +#define TEST6_RESPONSE_COUNT 3 +#define TEST7_STATUS_CODE 301 +#define TEST8_STATUS_CODE 302 +#define TEST9_STATUS_CODE 301 + + +#define TEST4_TITLE "test4: absorbing request retransmission" +#define TEST5_TITLE "test5: retransmit last response in PROCEEDING state" +#define TEST6_TITLE "test6: retransmit last response in COMPLETED state" + + +static char TARGET_URI[128]; +static char FROM_URI[128]; +static struct tsx_test_param *test_param; +static unsigned tp_flag; + + +#define TEST_TIMEOUT_ERROR -30 +#define MAX_ALLOWED_DIFF 150 + +static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e); +static pj_bool_t on_rx_message(pjsip_rx_data *rdata); + +/* UAC transaction user module. */ +static pjsip_module tsx_user = +{ + NULL, NULL, /* prev and next */ + { "Tsx-UAS-User", 12}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + NULL, /* on_rx_request() */ + NULL, /* on_rx_response() */ + NULL, /* on_tx_request() */ + NULL, /* on_tx_response() */ + &tsx_user_on_tsx_state, /* on_tsx_state() */ +}; + +/* Module to send request. */ +static pjsip_module msg_sender = +{ + NULL, NULL, /* prev and next */ + { "Msg-Sender", 10}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + &on_rx_message, /* on_rx_request() */ + &on_rx_message, /* on_rx_response() */ + NULL, /* on_tx_request() */ + NULL, /* on_tx_response() */ + NULL, /* on_tsx_state() */ +}; + +/* Static vars, which will be reset on each test. */ +static int recv_count; +static pj_time_val recv_last; +static pj_bool_t test_complete; + +/* Loop transport instance. */ +static pjsip_transport *loop; + +/* UAS transaction key. */ +static char key_buf[64]; +static pj_str_t tsx_key = { key_buf, 0 }; + + +/* General timer entry to be used by tests. */ +//static pj_timer_entry timer; + +/* Timer to send response via transaction. */ +struct response +{ + pj_str_t tsx_key; + pjsip_tx_data *tdata; +}; + +/* Timer callback to send response. */ +static void send_response_timer( pj_timer_heap_t *timer_heap, + struct pj_timer_entry *entry) +{ + pjsip_transaction *tsx; + struct response *r = (struct response*) entry->user_data; + pj_status_t status; + + tsx = pjsip_tsx_layer_find_tsx(&r->tsx_key, PJ_TRUE); + if (!tsx) { + PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction")); + pjsip_tx_data_dec_ref(r->tdata); + return; + } + + status = pjsip_tsx_send_msg(tsx, r->tdata); + if (status != PJ_SUCCESS) { + // Some tests do expect failure! + //PJ_LOG(3,(THIS_FILE," error: timer unable to send response")); + pj_mutex_unlock(tsx->mutex); + pjsip_tx_data_dec_ref(r->tdata); + return; + } + + pj_mutex_unlock(tsx->mutex); +} + +/* Utility to send response. */ +static void send_response( pjsip_rx_data *rdata, + pjsip_transaction *tsx, + int status_code ) +{ + pj_status_t status; + pjsip_tx_data *tdata; + + status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL, + &tdata); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create response", status); + test_complete = -196; + return; + } + + status = pjsip_tsx_send_msg(tsx, tdata); + if (status != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + // Some tests do expect failure! + //app_perror(" error: unable to send response", status); + //test_complete = -197; + return; + } +} + +/* Schedule timer to send response for the specified UAS transaction */ +static void schedule_send_response( pjsip_rx_data *rdata, + const pj_str_t *tsx_key, + int status_code, + int msec_delay ) +{ + pj_status_t status; + pjsip_tx_data *tdata; + pj_timer_entry *t; + struct response *r; + pj_time_val delay; + + status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL, + &tdata); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create response", status); + test_complete = -198; + return; + } + + r = PJ_POOL_ALLOC_T(tdata->pool, struct response); + pj_strdup(tdata->pool, &r->tsx_key, tsx_key); + r->tdata = tdata; + + delay.sec = 0; + delay.msec = msec_delay; + pj_time_val_normalize(&delay); + + t = PJ_POOL_ZALLOC_T(tdata->pool, pj_timer_entry); + t->user_data = r; + t->cb = &send_response_timer; + + status = pjsip_endpt_schedule_timer(endpt, t, &delay); + if (status != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + app_perror(" error: unable to schedule timer", status); + test_complete = -199; + return; + } +} + + +/* Find and terminate tsx with the specified key. */ +static void terminate_our_tsx(int status_code) +{ + pjsip_transaction *tsx; + + tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); + if (!tsx) { + PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction")); + return; + } + + pjsip_tsx_terminate(tsx, status_code); + pj_mutex_unlock(tsx->mutex); +} + +#if 0 /* Unused for now */ +/* Timer callback to terminate transaction. */ +static void terminate_tsx_timer( pj_timer_heap_t *timer_heap, + struct pj_timer_entry *entry) +{ + terminate_our_tsx(entry->id); +} + + +/* Schedule timer to terminate transaction. */ +static void schedule_terminate_tsx( pjsip_transaction *tsx, + int status_code, + int msec_delay ) +{ + pj_time_val delay; + + delay.sec = 0; + delay.msec = msec_delay; + pj_time_val_normalize(&delay); + + pj_assert(pj_strcmp(&tsx->transaction_key, &tsx_key)==0); + timer.user_data = NULL; + timer.id = status_code; + timer.cb = &terminate_tsx_timer; + pjsip_endpt_schedule_timer(endpt, &timer, &delay); +} +#endif + + +/* + * This is the handler to receive state changed notification from the + * transaction. It is used to verify that the transaction behaves according + * to the test scenario. + */ +static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) +{ + if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0 || + pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) + { + /* + * TEST1_BRANCH_ID tests that non-INVITE transaction transmits final + * response using correct transport and terminates transaction after + * T4 (PJSIP_T4_TIMEOUT, 5 seconds). + * + * TEST2_BRANCH_ID does similar test for non-2xx final response. + */ + int status_code = (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) ? + TEST1_STATUS_CODE : TEST2_STATUS_CODE; + + if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + test_complete = 1; + + /* Check that status code is status_code. */ + if (tsx->status_code != status_code) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -100; + } + + /* Previous state must be completed. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -101; + } + + } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { + + /* Previous state must be TRYING. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -102; + } + } + + } + else + if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) { + /* + * TEST3_BRANCH_ID tests sending provisional response. + */ + if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + test_complete = 1; + + /* Check that status code is status_code. */ + if (tsx->status_code != TEST3_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -110; + } + + /* Previous state must be completed. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -111; + } + + } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) { + + /* Previous state must be TRYING. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -112; + } + + /* Check that status code is status_code. */ + if (tsx->status_code != TEST3_PROVISIONAL_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -113; + } + + /* Check that event must be TX_MSG */ + if (e->body.tsx_state.type != PJSIP_EVENT_TX_MSG) { + PJ_LOG(3,(THIS_FILE, " error: incorrect event")); + test_complete = -114; + } + + } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { + + /* Previous state must be PROCEEDING. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -115; + } + + /* Check that status code is status_code. */ + if (tsx->status_code != TEST3_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -116; + } + + /* Check that event must be TX_MSG */ + if (e->body.tsx_state.type != PJSIP_EVENT_TX_MSG) { + PJ_LOG(3,(THIS_FILE, " error: incorrect event")); + test_complete = -117; + } + + } + + } else + if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) { + /* + * TEST4_BRANCH_ID tests receiving retransmissions in TRYING state. + */ + if (tsx->state == PJSIP_TSX_STATE_TRYING) { + /* Request is received. */ + } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + /* Check that status code is status_code. */ + if (tsx->status_code != TEST4_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE, + " error: incorrect status code %d " + "(expecting %d)", tsx->status_code, + TEST4_STATUS_CODE)); + test_complete = -120; + } + + /* Previous state. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -121; + } + + } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) + { + PJ_LOG(3,(THIS_FILE, " error: unexpected state %s (122)", + pjsip_tsx_state_str(tsx->state))); + test_complete = -122; + + } + + + } else + if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) { + /* + * TEST5_BRANCH_ID tests receiving retransmissions in PROCEEDING state + */ + if (tsx->state == PJSIP_TSX_STATE_TRYING) { + /* Request is received. */ + + } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + /* Check that status code is status_code. */ + if (tsx->status_code != TEST5_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -130; + } + + /* Previous state. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -131; + } + + } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) { + + /* Check status code. */ + if (tsx->status_code != TEST5_PROVISIONAL_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -132; + } + + } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) { + PJ_LOG(3,(THIS_FILE, " error: unexpected state %s (133)", + pjsip_tsx_state_str(tsx->state))); + test_complete = -133; + + } + + } else + if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) { + /* + * TEST6_BRANCH_ID tests receiving retransmissions in COMPLETED state + */ + if (tsx->state == PJSIP_TSX_STATE_TRYING) { + /* Request is received. */ + + } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + /* Check that status code is status_code. */ + if (tsx->status_code != TEST6_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code %d " + "(expecting %d)", tsx->status_code, + TEST6_STATUS_CODE)); + test_complete = -140; + } + + /* Previous state. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -141; + } + + } else if (tsx->state != PJSIP_TSX_STATE_PROCEEDING && + tsx->state != PJSIP_TSX_STATE_COMPLETED && + tsx->state != PJSIP_TSX_STATE_DESTROYED) + { + PJ_LOG(3,(THIS_FILE, " error: unexpected state %s (142)", + pjsip_tsx_state_str(tsx->state))); + test_complete = -142; + + } + + + } else + if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0 || + pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0) + { + /* + * TEST7_BRANCH_ID and TEST8_BRANCH_ID test retransmission of + * INVITE final response + */ + int code; + + if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID) == 0) + code = TEST7_STATUS_CODE; + else + code = TEST8_STATUS_CODE; + + if (tsx->state == PJSIP_TSX_STATE_TRYING) { + /* Request is received. */ + + } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + if (test_complete == 0) + test_complete = 1; + + /* Check status code. */ + if (tsx->status_code != PJSIP_SC_TSX_TIMEOUT) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -150; + } + + /* Previous state. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -151; + } + + /* Check the number of retransmissions */ + if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { + + if (tsx->retransmit_count != 0) { + PJ_LOG(3,(THIS_FILE, " error: should not retransmit")); + test_complete = -1510; + } + + } else { + + if (tsx->retransmit_count != 10) { + PJ_LOG(3,(THIS_FILE, + " error: incorrect retransmit count %d " + "(expecting 10)", + tsx->retransmit_count)); + test_complete = -1510; + } + + } + + } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { + + /* Check that status code is status_code. */ + if (tsx->status_code != code) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -152; + } + + /* Previous state. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -153; + } + + } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) { + + PJ_LOG(3,(THIS_FILE, " error: unexpected state (154)")); + test_complete = -154; + + } + + + } else + if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) { + /* + * TEST9_BRANCH_ID tests that retransmission of INVITE final response + * must cease when ACK is received. + */ + + if (tsx->state == PJSIP_TSX_STATE_TRYING) { + /* Request is received. */ + + } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + if (test_complete == 0) + test_complete = 1; + + /* Check status code. */ + if (tsx->status_code != TEST9_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -160; + } + + /* Previous state. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_CONFIRMED) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -161; + } + + } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { + + /* Check that status code is status_code. */ + if (tsx->status_code != TEST9_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -162; + } + + /* Previous state. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -163; + } + + + } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) { + + /* Check that status code is status_code. */ + if (tsx->status_code != TEST9_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -164; + } + + /* Previous state. */ + if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { + PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state")); + test_complete = -165; + } + + } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) { + + PJ_LOG(3,(THIS_FILE, " error: unexpected state (166)")); + test_complete = -166; + + } + + + } else + if (pj_strcmp2(&tsx->branch, TEST10_BRANCH_ID)==0 || + pj_strcmp2(&tsx->branch, TEST11_BRANCH_ID)==0 || + pj_strcmp2(&tsx->branch, TEST12_BRANCH_ID)==0) + { + if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { + + if (!test_complete) + test_complete = 1; + + if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) { + PJ_LOG(3,(THIS_FILE," error: incorrect status code")); + test_complete = -170; + } + } + } + +} + +/* Save transaction key to global variables. */ +static void save_key(pjsip_transaction *tsx) +{ + pj_str_t key; + + pj_strdup(tsx->pool, &key, &tsx->transaction_key); + pj_strcpy(&tsx_key, &key); +} + +#define DIFF(a,b) ((amsg_info.msg; + pj_str_t branch_param = rdata->msg_info.via->branch_param; + pj_status_t status; + + if (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0 || + pj_strcmp2(&branch_param, TEST2_BRANCH_ID) == 0) + { + /* + * TEST1_BRANCH_ID tests that non-INVITE transaction transmits 2xx + * final response using correct transport and terminates transaction + * after 32 seconds. + * + * TEST2_BRANCH_ID performs similar test for non-2xx final response. + */ + int status_code = (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0) ? + TEST1_STATUS_CODE : TEST2_STATUS_CODE; + + if (msg->type == PJSIP_REQUEST_MSG) { + /* On received request, create UAS and respond with final + * response. + */ + pjsip_transaction *tsx; + + status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create transaction", status); + test_complete = -110; + return PJ_TRUE; + } + pjsip_tsx_recv_msg(tsx, rdata); + + save_key(tsx); + send_response(rdata, tsx, status_code); + + } else { + /* Verify the response received. */ + + ++recv_count; + + /* Verify status code. */ + if (msg->line.status.code != status_code) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -113; + } + + /* Verify that no retransmissions is received. */ + if (recv_count > 1) { + PJ_LOG(3,(THIS_FILE, " error: retransmission received")); + test_complete = -114; + } + + } + return PJ_TRUE; + + } else if (pj_strcmp2(&branch_param, TEST3_BRANCH_ID) == 0) { + + /* TEST3_BRANCH_ID tests provisional response. */ + + if (msg->type == PJSIP_REQUEST_MSG) { + /* On received request, create UAS and respond with provisional + * response, then schedule timer to send final response. + */ + pjsip_transaction *tsx; + + status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create transaction", status); + test_complete = -116; + return PJ_TRUE; + } + pjsip_tsx_recv_msg(tsx, rdata); + + save_key(tsx); + + send_response(rdata, tsx, TEST3_PROVISIONAL_CODE); + schedule_send_response(rdata, &tsx->transaction_key, + TEST3_STATUS_CODE, 2000); + + } else { + /* Verify the response received. */ + + ++recv_count; + + if (recv_count == 1) { + /* Verify status code. */ + if (msg->line.status.code != TEST3_PROVISIONAL_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -123; + } + } else if (recv_count == 2) { + /* Verify status code. */ + if (msg->line.status.code != TEST3_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + test_complete = -124; + } + } else { + PJ_LOG(3,(THIS_FILE, " error: retransmission received")); + test_complete = -125; + } + + } + return PJ_TRUE; + + } else if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0 || + pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0 || + pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) + { + + /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state. */ + /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state. */ + /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state. */ + + if (msg->type == PJSIP_REQUEST_MSG) { + /* On received request, create UAS. */ + pjsip_transaction *tsx; + + PJ_LOG(4,(THIS_FILE, " received request (probably retransmission)")); + + status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create transaction", status); + test_complete = -130; + return PJ_TRUE; + } + + pjsip_tsx_recv_msg(tsx, rdata); + save_key(tsx); + + if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) { + + } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) { + send_response(rdata, tsx, TEST5_PROVISIONAL_CODE); + + } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) { + PJ_LOG(4,(THIS_FILE, " sending provisional response")); + send_response(rdata, tsx, TEST6_PROVISIONAL_CODE); + PJ_LOG(4,(THIS_FILE, " sending final response")); + send_response(rdata, tsx, TEST6_STATUS_CODE); + } + + } else { + /* Verify the response received. */ + + PJ_LOG(4,(THIS_FILE, " received response number %d", recv_count)); + + ++recv_count; + + if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) { + PJ_LOG(3,(THIS_FILE, " error: not expecting response!")); + test_complete = -132; + + } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) { + + if (rdata->msg_info.msg->line.status.code!=TEST5_PROVISIONAL_CODE) { + PJ_LOG(3,(THIS_FILE, " error: incorrect status code!")); + test_complete = -133; + + } + if (recv_count > TEST5_RESPONSE_COUNT) { + PJ_LOG(3,(THIS_FILE, " error: not expecting response!")); + test_complete = -134; + } + + } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) { + + int code = rdata->msg_info.msg->line.status.code; + + switch (recv_count) { + case 1: + if (code != TEST6_PROVISIONAL_CODE) { + PJ_LOG(3,(THIS_FILE, " error: invalid code!")); + test_complete = -135; + } + break; + case 2: + case 3: + if (code != TEST6_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE, " error: invalid code %d " + "(expecting %d)", code, TEST6_STATUS_CODE)); + test_complete = -136; + } + break; + default: + PJ_LOG(3,(THIS_FILE, " error: not expecting response")); + test_complete = -137; + break; + } + } + } + return PJ_TRUE; + + + } else if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0 || + pj_strcmp2(&branch_param, TEST8_BRANCH_ID) == 0) + { + + /* + * TEST7_BRANCH_ID and TEST8_BRANCH_ID test the retransmission + * of INVITE final response + */ + if (msg->type == PJSIP_REQUEST_MSG) { + + /* On received request, create UAS. */ + pjsip_transaction *tsx; + + status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create transaction", status); + test_complete = -140; + return PJ_TRUE; + } + + pjsip_tsx_recv_msg(tsx, rdata); + save_key(tsx); + + if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0) { + + send_response(rdata, tsx, TEST7_STATUS_CODE); + + } else { + + send_response(rdata, tsx, TEST8_STATUS_CODE); + + } + + } else { + int code; + + ++recv_count; + + if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0) + code = TEST7_STATUS_CODE; + else + code = TEST8_STATUS_CODE; + + if (recv_count==1) { + + if (rdata->msg_info.msg->line.status.code != code) { + PJ_LOG(3,(THIS_FILE," error: invalid status code")); + test_complete = -141; + } + + recv_last = rdata->pkt_info.timestamp; + + } else { + + pj_time_val now; + unsigned msec, msec_expected; + + now = rdata->pkt_info.timestamp; + + PJ_TIME_VAL_SUB(now, recv_last); + + msec = now.sec*1000 + now.msec; + msec_expected = (1 << (recv_count-2)) * pjsip_cfg()->tsx.t1; + if (msec_expected > pjsip_cfg()->tsx.t2) + msec_expected = pjsip_cfg()->tsx.t2; + + if (DIFF(msec, msec_expected) > MAX_ALLOWED_DIFF) { + PJ_LOG(3,(THIS_FILE, + " error: incorrect retransmission " + "time (%d ms expected, %d ms received", + msec_expected, msec)); + test_complete = -142; + } + + if (recv_count > 11) { + PJ_LOG(3,(THIS_FILE," error: too many responses (%d)", + recv_count)); + test_complete = -143; + } + + recv_last = rdata->pkt_info.timestamp; + } + + } + return PJ_TRUE; + + } else if (pj_strcmp2(&branch_param, TEST9_BRANCH_ID) == 0) { + + /* + * TEST9_BRANCH_ID tests that the retransmission of INVITE final + * response should cease when ACK is received. Transaction also MUST + * terminate in T4 seconds. + */ + if (msg->type == PJSIP_REQUEST_MSG) { + + /* On received request, create UAS. */ + pjsip_transaction *tsx; + + status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create transaction", status); + test_complete = -150; + return PJ_TRUE; + } + + pjsip_tsx_recv_msg(tsx, rdata); + save_key(tsx); + send_response(rdata, tsx, TEST9_STATUS_CODE); + + + } else { + + ++recv_count; + + if (rdata->msg_info.msg->line.status.code != TEST9_STATUS_CODE) { + PJ_LOG(3,(THIS_FILE," error: invalid status code")); + test_complete = -151; + } + + if (recv_count==1) { + + recv_last = rdata->pkt_info.timestamp; + + } else if (recv_count < 5) { + + /* Let UAS retransmit some messages before we send ACK. */ + pj_time_val now; + unsigned msec, msec_expected; + + now = rdata->pkt_info.timestamp; + + PJ_TIME_VAL_SUB(now, recv_last); + + msec = now.sec*1000 + now.msec; + msec_expected = (1 << (recv_count-2)) * pjsip_cfg()->tsx.t1; + if (msec_expected > pjsip_cfg()->tsx.t2) + msec_expected = pjsip_cfg()->tsx.t2; + + if (DIFF(msec, msec_expected) > MAX_ALLOWED_DIFF) { + PJ_LOG(3,(THIS_FILE, + " error: incorrect retransmission " + "time (%d ms expected, %d ms received", + msec_expected, msec)); + test_complete = -152; + } + + recv_last = rdata->pkt_info.timestamp; + + } else if (recv_count == 5) { + pjsip_tx_data *tdata; + pjsip_sip_uri *uri; + pjsip_via_hdr *via; + + status = pjsip_endpt_create_request_from_hdr( + endpt, &pjsip_ack_method, + rdata->msg_info.to->uri, + rdata->msg_info.from, + rdata->msg_info.to, + NULL, + rdata->msg_info.cid, + rdata->msg_info.cseq->cseq, + NULL, + &tdata); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create ACK", status); + test_complete = -153; + return PJ_TRUE; + } + + uri=(pjsip_sip_uri*)pjsip_uri_get_uri(tdata->msg->line.req.uri); + uri->transport_param = pj_str("loop-dgram"); + + via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); + via->branch_param = pj_str(TEST9_BRANCH_ID); + + status = pjsip_endpt_send_request_stateless(endpt, tdata, + NULL, NULL); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to send ACK", status); + test_complete = -154; + } + + } else { + PJ_LOG(3,(THIS_FILE," error: too many responses (%d)", + recv_count)); + test_complete = -155; + } + + } + return PJ_TRUE; + + } else if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0 || + pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0 || + pj_strcmp2(&branch_param, TEST12_BRANCH_ID) == 0) + { + int test_num, code1, code2; + + if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0) + test_num=10, code1 = 100, code2 = 0; + else if (pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0) + test_num=11, code1 = 100, code2 = 200; + else + test_num=12, code1 = 200, code2 = 0; + + if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) { + + /* On received response, create UAS. */ + pjsip_transaction *tsx; + + status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create transaction", status); + test_complete = -150; + return PJ_TRUE; + } + + pjsip_tsx_recv_msg(tsx, rdata); + save_key(tsx); + + schedule_send_response(rdata, &tsx_key, code1, 1000); + + if (code2) + schedule_send_response(rdata, &tsx_key, code2, 2000); + + } else { + + } + + return PJ_TRUE; + } + + return PJ_FALSE; +} + +/* + * The generic test framework, used by most of the tests. + */ +static int perform_test( char *target_uri, char *from_uri, + char *branch_param, int test_time, + const pjsip_method *method, + int request_cnt, int request_interval_msec, + int expecting_timeout) +{ + pjsip_tx_data *tdata; + pj_str_t target, from; + pjsip_via_hdr *via; + pj_time_val timeout, next_send; + int sent_cnt; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, + " please standby, this will take at most %d seconds..", + test_time)); + + /* Reset test. */ + recv_count = 0; + test_complete = 0; + tsx_key.slen = 0; + + /* Init headers. */ + target = pj_str(target_uri); + from = pj_str(from_uri); + + /* Create request. */ + status = pjsip_endpt_create_request( endpt, method, &target, + &from, &target, NULL, NULL, -1, + NULL, &tdata); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to create request", status); + return -10; + } + + /* Set the branch param for test 1. */ + via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); + via->branch_param = pj_str(branch_param); + + /* Schedule first send. */ + sent_cnt = 0; + pj_gettimeofday(&next_send); + pj_time_val_normalize(&next_send); + + /* Set test completion time. */ + pj_gettimeofday(&timeout); + timeout.sec += test_time; + + /* Wait until test complete. */ + while (!test_complete) { + pj_time_val now, poll_delay = {0, 10}; + + pjsip_endpt_handle_events(endpt, &poll_delay); + + pj_gettimeofday(&now); + + if (sent_cnt < request_cnt && PJ_TIME_VAL_GTE(now, next_send)) { + /* Add additional reference to tdata to prevent transaction from + * deleting it. + */ + pjsip_tx_data_add_ref(tdata); + + /* (Re)Send the request. */ + PJ_LOG(4,(THIS_FILE, " (re)sending request %d", sent_cnt)); + + status = pjsip_endpt_send_request_stateless(endpt, tdata, 0, 0); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to send request", status); + pjsip_tx_data_dec_ref(tdata); + return -20; + } + + /* Schedule next send, if any. */ + sent_cnt++; + if (sent_cnt < request_cnt) { + pj_gettimeofday(&next_send); + next_send.msec += request_interval_msec; + pj_time_val_normalize(&next_send); + } + } + + if (now.sec > timeout.sec) { + if (!expecting_timeout) + PJ_LOG(3,(THIS_FILE, " Error: test has timed out")); + pjsip_tx_data_dec_ref(tdata); + return TEST_TIMEOUT_ERROR; + } + } + + if (test_complete < 0) { + pjsip_transaction *tsx; + + tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); + if (tsx) { + pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); + pj_mutex_unlock(tsx->mutex); + flush_events(1000); + } + pjsip_tx_data_dec_ref(tdata); + return test_complete; + } + + /* Allow transaction to destroy itself */ + flush_events(500); + + /* Make sure transaction has been destroyed. */ + if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) { + PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed")); + pjsip_tx_data_dec_ref(tdata); + return -40; + } + + /* Check tdata reference counter. */ + if (pj_atomic_get(tdata->ref_cnt) != 1) { + PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %d", + pj_atomic_get(tdata->ref_cnt))); + pjsip_tx_data_dec_ref(tdata); + return -50; + } + + /* Destroy txdata */ + pjsip_tx_data_dec_ref(tdata); + + return PJ_SUCCESS; + +} + + +/***************************************************************************** + ** + ** TEST1_BRANCH_ID: Basic 2xx final response + ** TEST2_BRANCH_ID: Basic non-2xx final response + ** + ***************************************************************************** + */ +static int tsx_basic_final_response_test(void) +{ + unsigned duration; + int status; + + PJ_LOG(3,(THIS_FILE," test1: basic sending 2xx final response")); + + /* Test duration must be greater than 32 secs if unreliable transport + * is used. + */ + duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; + + status = perform_test(TARGET_URI, FROM_URI, TEST1_BRANCH_ID, + duration, &pjsip_options_method, 1, 0, 0); + if (status != 0) + return status; + + PJ_LOG(3,(THIS_FILE," test2: basic sending non-2xx final response")); + + status = perform_test(TARGET_URI, FROM_URI, TEST2_BRANCH_ID, + duration, &pjsip_options_method, 1, 0, 0); + if (status != 0) + return status; + + return 0; +} + + +/***************************************************************************** + ** + ** TEST3_BRANCH_ID: Sending provisional response + ** + ***************************************************************************** + */ +static int tsx_basic_provisional_response_test(void) +{ + unsigned duration; + int status; + + PJ_LOG(3,(THIS_FILE," test3: basic sending 2xx final response")); + + duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; + duration += 2; + + status = perform_test(TARGET_URI, FROM_URI, TEST3_BRANCH_ID, duration, + &pjsip_options_method, 1, 0, 0); + + return status; +} + + +/***************************************************************************** + ** + ** TEST4_BRANCH_ID: Absorbs retransmissions in TRYING state + ** TEST5_BRANCH_ID: Absorbs retransmissions in PROCEEDING state + ** TEST6_BRANCH_ID: Absorbs retransmissions in COMPLETED state + ** + ***************************************************************************** + */ +static int tsx_retransmit_last_response_test(const char *title, + char *branch_id, + int request_cnt, + int status_code) +{ + int status; + + PJ_LOG(3,(THIS_FILE," %s", title)); + + status = perform_test(TARGET_URI, FROM_URI, branch_id, 5, + &pjsip_options_method, + request_cnt, 1000, 1); + if (status && status != TEST_TIMEOUT_ERROR) + return status; + if (!status) { + PJ_LOG(3,(THIS_FILE, " error: expecting timeout")); + return -31; + } + + terminate_our_tsx(status_code); + flush_events(100); + + if (test_complete != 1) + return test_complete; + + flush_events(100); + return 0; +} + +/***************************************************************************** + ** + ** TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test + ** TEST8_BRANCH_ID: INVITE 2xx final response retransmission test + ** + ***************************************************************************** + */ +static int tsx_final_response_retransmission_test(void) +{ + int status; + + PJ_LOG(3,(THIS_FILE, + " test7: INVITE non-2xx final response retransmission")); + + status = perform_test(TARGET_URI, FROM_URI, TEST7_BRANCH_ID, + 33, /* Test duration must be greater than 32 secs */ + &pjsip_invite_method, 1, 0, 0); + if (status != 0) + return status; + + PJ_LOG(3,(THIS_FILE, + " test8: INVITE 2xx final response retransmission")); + + status = perform_test(TARGET_URI, FROM_URI, TEST8_BRANCH_ID, + 33, /* Test duration must be greater than 32 secs */ + &pjsip_invite_method, 1, 0, 0); + if (status != 0) + return status; + + return 0; +} + + +/***************************************************************************** + ** + ** TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must + ** cease when ACK is received + ** + ***************************************************************************** + */ +static int tsx_ack_test(void) +{ + int status; + + PJ_LOG(3,(THIS_FILE, + " test9: receiving ACK for non-2xx final response")); + + status = perform_test(TARGET_URI, FROM_URI, TEST9_BRANCH_ID, + 20, /* allow 5 retransmissions */ + &pjsip_invite_method, 1, 0, 0); + if (status != 0) + return status; + + + return 0; +} + + + +/***************************************************************************** + ** + ** TEST10_BRANCH_ID: test transport failure in TRYING state. + ** TEST11_BRANCH_ID: test transport failure in PROCEEDING state. + ** TEST12_BRANCH_ID: test transport failure in CONNECTED state. + ** TEST13_BRANCH_ID: test transport failure in CONFIRMED state. + ** + ***************************************************************************** + */ +static int tsx_transport_failure_test(void) +{ + struct test_desc + { + int transport_delay; + int fail_delay; + char *branch_id; + char *title; + } tests[] = + { + { 0, 10, TEST10_BRANCH_ID, "test10: failed transport in TRYING state (no delay)" }, + { 50, 10, TEST10_BRANCH_ID, "test10: failed transport in TRYING state (50 ms delay)" }, + { 0, 1500, TEST11_BRANCH_ID, "test11: failed transport in PROCEEDING state (no delay)" }, + { 50, 1500, TEST11_BRANCH_ID, "test11: failed transport in PROCEEDING state (50 ms delay)" }, + { 0, 2500, TEST12_BRANCH_ID, "test12: failed transport in COMPLETED state (no delay)" }, + { 50, 2500, TEST12_BRANCH_ID, "test12: failed transport in COMPLETED state (50 ms delay)" }, + }; + int i, status; + + for (i=0; i<(int)PJ_ARRAY_SIZE(tests); ++i) { + pj_time_val fail_time, end_test, now; + + PJ_LOG(3,(THIS_FILE, " %s", tests[i].title)); + pjsip_loop_set_failure(loop, 0, NULL); + pjsip_loop_set_delay(loop, tests[i].transport_delay); + + status = perform_test(TARGET_URI, FROM_URI, tests[i].branch_id, + 0, &pjsip_invite_method, 1, 0, 1); + if (status && status != TEST_TIMEOUT_ERROR) + return status; + if (!status) { + PJ_LOG(3,(THIS_FILE, " error: expecting timeout")); + return -40; + } + + pj_gettimeofday(&fail_time); + fail_time.msec += tests[i].fail_delay; + pj_time_val_normalize(&fail_time); + + do { + pj_time_val interval = { 0, 1 }; + pj_gettimeofday(&now); + pjsip_endpt_handle_events(endpt, &interval); + } while (PJ_TIME_VAL_LT(now, fail_time)); + + pjsip_loop_set_failure(loop, 1, NULL); + + end_test = now; + end_test.sec += 5; + + do { + pj_time_val interval = { 0, 1 }; + pj_gettimeofday(&now); + pjsip_endpt_handle_events(endpt, &interval); + } while (!test_complete && PJ_TIME_VAL_LT(now, end_test)); + + if (test_complete == 0) { + PJ_LOG(3,(THIS_FILE, " error: test has timed out")); + return -41; + } + + if (test_complete != 1) + return test_complete; + } + + return 0; +} + +/***************************************************************************** + ** + ** UAS Transaction Test. + ** + ***************************************************************************** + */ +int tsx_uas_test(struct tsx_test_param *param) +{ + pj_sockaddr_in addr; + pj_status_t status; + + test_param = param; + tp_flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)param->type); + + pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + + /* Check if loop transport is configured. */ + status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, + &addr, sizeof(addr), NULL, &loop); + if (status != PJ_SUCCESS) { + PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!")); + return -10; + } + /* Register modules. */ + status = pjsip_endpt_register_module(endpt, &tsx_user); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to register module", status); + return -3; + } + status = pjsip_endpt_register_module(endpt, &msg_sender); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to register module", status); + return -4; + } + + /* TEST1_BRANCH_ID: Basic 2xx final response. + * TEST2_BRANCH_ID: Basic non-2xx final response. + */ + status = tsx_basic_final_response_test(); + if (status != 0) + return status; + + /* TEST3_BRANCH_ID: with provisional response + */ + status = tsx_basic_provisional_response_test(); + if (status != 0) + return status; + + /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state + */ + status = tsx_retransmit_last_response_test(TEST4_TITLE, + TEST4_BRANCH_ID, + TEST4_REQUEST_COUNT, + TEST4_STATUS_CODE); + if (status != 0) + return status; + + /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state + */ + status = tsx_retransmit_last_response_test(TEST5_TITLE, + TEST5_BRANCH_ID, + TEST5_REQUEST_COUNT, + TEST5_STATUS_CODE); + if (status != 0) + return status; + + /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state + * This only applies to non-reliable transports, + * since UAS transaction is destroyed as soon + * as final response is sent for reliable transports. + */ + if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_retransmit_last_response_test(TEST6_TITLE, + TEST6_BRANCH_ID, + TEST6_REQUEST_COUNT, + TEST6_STATUS_CODE); + if (status != 0) + return status; + } + + /* TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test + * TEST8_BRANCH_ID: INVITE 2xx final response retransmission test + */ + status = tsx_final_response_retransmission_test(); + if (status != 0) + return status; + + /* TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must + * cease when ACK is received + * Only applicable for non-reliable transports. + */ + if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_ack_test(); + if (status != 0) + return status; + } + + + /* TEST10_BRANCH_ID: test transport failure in TRYING state. + * TEST11_BRANCH_ID: test transport failure in PROCEEDING state. + * TEST12_BRANCH_ID: test transport failure in CONNECTED state. + * TEST13_BRANCH_ID: test transport failure in CONFIRMED state. + */ + /* Only valid for loop-dgram */ + if (param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + status = tsx_transport_failure_test(); + if (status != 0) + return status; + } + + + /* Register modules. */ + status = pjsip_endpt_unregister_module(endpt, &tsx_user); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -8; + } + status = pjsip_endpt_unregister_module(endpt, &msg_sender); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -9; + } + + + if (loop) + pjsip_transport_dec_ref(loop); + + return 0; +} + diff --git a/pjsip/src/test/txdata_test.c b/pjsip/src/test/txdata_test.c new file mode 100644 index 00000000..9ced25e3 --- /dev/null +++ b/pjsip/src/test/txdata_test.c @@ -0,0 +1,847 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ + +#include "test.h" +#include +#include + + +#define THIS_FILE "txdata_test.c" + + +#define HFIND(msg,h,H) ((pjsip_##h##_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_##H, NULL)) + +#if defined(PJ_DEBUG) && PJ_DEBUG!=0 +# define LOOP 10000 +#else +# define LOOP 100000 +#endif + + +/* + * This tests various core message creation functions. + */ +static int core_txdata_test(void) +{ + pj_status_t status; + pj_str_t target, from, to, contact, body; + pjsip_rx_data dummy_rdata; + pjsip_tx_data *invite, *invite2, *cancel, *response, *ack; + + PJ_LOG(3,(THIS_FILE, " core transmit data test")); + + /* Create INVITE request. */ + target = pj_str("tel:+1"); + from = pj_str("tel:+0"); + to = pj_str("tel:+1"); + contact = pj_str("Bob "); + body = pj_str("Hello world!"); + + status = pjsip_endpt_create_request( endpt, &pjsip_invite_method, &target, + &from, &to, &contact, NULL, 10, &body, + &invite); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return -10; + } + + /* Buffer must be invalid. */ + if (pjsip_tx_data_is_valid(invite) != 0) { + PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); + return -14; + } + /* Reference counter must be set to 1. */ + if (pj_atomic_get(invite->ref_cnt) != 1) { + PJ_LOG(3,(THIS_FILE, " error: invalid reference counter")); + return -15; + } + /* Check message type. */ + if (invite->msg->type != PJSIP_REQUEST_MSG) + return -16; + /* Check method. */ + if (invite->msg->line.req.method.id != PJSIP_INVITE_METHOD) + return -17; + + /* Check that mandatory headers are present. */ + if (HFIND(invite->msg, from, FROM) == 0) + return -20; + if (HFIND(invite->msg, to, TO) == 0) + return -21; + if (HFIND(invite->msg, contact, CONTACT) == 0) + return -22; + if (HFIND(invite->msg, cid, CALL_ID) == 0) + return -23; + if (HFIND(invite->msg, cseq, CSEQ) == 0) + return -24; + do { + pjsip_via_hdr *via = HFIND(invite->msg, via, VIA); + if (via == NULL) + return -25; + /* Branch param must be empty. */ + if (via->branch_param.slen != 0) + return -26; + } while (0); + if (invite->msg->body == NULL) + return -28; + + /* Create another INVITE request from first request. */ + status = pjsip_endpt_create_request_from_hdr( endpt, &pjsip_invite_method, + invite->msg->line.req.uri, + HFIND(invite->msg,from,FROM), + HFIND(invite->msg,to,TO), + HFIND(invite->msg,contact,CONTACT), + HFIND(invite->msg,cid,CALL_ID), + 10, &body, &invite2); + if (status != PJ_SUCCESS) { + app_perror(" error: create second request failed", status); + return -30; + } + + /* Buffer must be invalid. */ + if (pjsip_tx_data_is_valid(invite2) != 0) { + PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); + return -34; + } + /* Reference counter must be set to 1. */ + if (pj_atomic_get(invite2->ref_cnt) != 1) { + PJ_LOG(3,(THIS_FILE, " error: invalid reference counter")); + return -35; + } + /* Check message type. */ + if (invite2->msg->type != PJSIP_REQUEST_MSG) + return -36; + /* Check method. */ + if (invite2->msg->line.req.method.id != PJSIP_INVITE_METHOD) + return -37; + + /* Check that mandatory headers are again present. */ + if (HFIND(invite2->msg, from, FROM) == 0) + return -40; + if (HFIND(invite2->msg, to, TO) == 0) + return -41; + if (HFIND(invite2->msg, contact, CONTACT) == 0) + return -42; + if (HFIND(invite2->msg, cid, CALL_ID) == 0) + return -43; + if (HFIND(invite2->msg, cseq, CSEQ) == 0) + return -44; + if (HFIND(invite2->msg, via, VIA) == 0) + return -45; + /* + if (HFIND(invite2->msg, ctype, CONTENT_TYPE) == 0) + return -46; + if (HFIND(invite2->msg, clen, CONTENT_LENGTH) == 0) + return -47; + */ + if (invite2->msg->body == NULL) + return -48; + + /* Done checking invite2. We can delete this. */ + if (pjsip_tx_data_dec_ref(invite2) != PJSIP_EBUFDESTROYED) { + PJ_LOG(3,(THIS_FILE, " error: request buffer not destroyed!")); + return -49; + } + + /* Initialize dummy rdata (to simulate receiving a request) + * We should never do this in real application, as there are many + * many more fields need to be initialized!! + */ + dummy_rdata.msg_info.cid = HFIND(invite->msg, cid, CALL_ID); + dummy_rdata.msg_info.clen = NULL; + dummy_rdata.msg_info.cseq = HFIND(invite->msg, cseq, CSEQ); + dummy_rdata.msg_info.ctype = NULL; + dummy_rdata.msg_info.from = HFIND(invite->msg, from, FROM); + dummy_rdata.msg_info.max_fwd = NULL; + dummy_rdata.msg_info.msg = invite->msg; + dummy_rdata.msg_info.record_route = NULL; + dummy_rdata.msg_info.require = NULL; + dummy_rdata.msg_info.route = NULL; + dummy_rdata.msg_info.to = HFIND(invite->msg, to, TO); + dummy_rdata.msg_info.via = HFIND(invite->msg, via, VIA); + + /* Create a response message for the request. */ + status = pjsip_endpt_create_response( endpt, &dummy_rdata, 301, NULL, + &response); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create response", status); + return -50; + } + + /* Buffer must be invalid. */ + if (pjsip_tx_data_is_valid(response) != 0) { + PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); + return -54; + } + /* Check reference counter. */ + if (pj_atomic_get(response->ref_cnt) != 1) { + PJ_LOG(3,(THIS_FILE, " error: invalid ref count in response")); + return -55; + } + /* Check message type. */ + if (response->msg->type != PJSIP_RESPONSE_MSG) + return -56; + /* Check correct status is set. */ + if (response->msg->line.status.code != 301) + return -57; + + /* Check that mandatory headers are again present. */ + if (HFIND(response->msg, from, FROM) == 0) + return -60; + if (HFIND(response->msg, to, TO) == 0) + return -61; + /* + if (HFIND(response->msg, contact, CONTACT) == 0) + return -62; + */ + if (HFIND(response->msg, cid, CALL_ID) == 0) + return -63; + if (HFIND(response->msg, cseq, CSEQ) == 0) + return -64; + if (HFIND(response->msg, via, VIA) == 0) + return -65; + + /* This response message will be used later when creating ACK */ + + /* Create CANCEL request for the original request. */ + status = pjsip_endpt_create_cancel( endpt, invite, &cancel); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create CANCEL request", status); + return -80; + } + + /* Buffer must be invalid. */ + if (pjsip_tx_data_is_valid(cancel) != 0) { + PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); + return -84; + } + /* Check reference counter. */ + if (pj_atomic_get(cancel->ref_cnt) != 1) { + PJ_LOG(3,(THIS_FILE, " error: invalid ref count in CANCEL request")); + return -85; + } + /* Check message type. */ + if (cancel->msg->type != PJSIP_REQUEST_MSG) + return -86; + /* Check method. */ + if (cancel->msg->line.req.method.id != PJSIP_CANCEL_METHOD) + return -87; + + /* Check that mandatory headers are again present. */ + if (HFIND(cancel->msg, from, FROM) == 0) + return -90; + if (HFIND(cancel->msg, to, TO) == 0) + return -91; + /* + if (HFIND(cancel->msg, contact, CONTACT) == 0) + return -92; + */ + if (HFIND(cancel->msg, cid, CALL_ID) == 0) + return -93; + if (HFIND(cancel->msg, cseq, CSEQ) == 0) + return -94; + if (HFIND(cancel->msg, via, VIA) == 0) + return -95; + + /* Done checking CANCEL request. */ + if (pjsip_tx_data_dec_ref(cancel) != PJSIP_EBUFDESTROYED) { + PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); + return -99; + } + + /* Modify dummy_rdata to simulate receiving response. */ + pj_bzero(&dummy_rdata, sizeof(dummy_rdata)); + dummy_rdata.msg_info.msg = response->msg; + dummy_rdata.msg_info.to = HFIND(response->msg, to, TO); + + /* Create ACK request */ + status = pjsip_endpt_create_ack( endpt, invite, &dummy_rdata, &ack ); + if (status != PJ_SUCCESS) { + PJ_LOG(3,(THIS_FILE, " error: unable to create ACK")); + return -100; + } + /* Buffer must be invalid. */ + if (pjsip_tx_data_is_valid(ack) != 0) { + PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); + return -104; + } + /* Check reference counter. */ + if (pj_atomic_get(ack->ref_cnt) != 1) { + PJ_LOG(3,(THIS_FILE, " error: invalid ref count in ACK request")); + return -105; + } + /* Check message type. */ + if (ack->msg->type != PJSIP_REQUEST_MSG) + return -106; + /* Check method. */ + if (ack->msg->line.req.method.id != PJSIP_ACK_METHOD) + return -107; + /* Check Request-URI is present. */ + if (ack->msg->line.req.uri == NULL) + return -108; + + /* Check that mandatory headers are again present. */ + if (HFIND(ack->msg, from, FROM) == 0) + return -110; + if (HFIND(ack->msg, to, TO) == 0) + return -111; + if (HFIND(ack->msg, cid, CALL_ID) == 0) + return -112; + if (HFIND(ack->msg, cseq, CSEQ) == 0) + return -113; + if (HFIND(ack->msg, via, VIA) == 0) + return -114; + if (ack->msg->body != NULL) + return -115; + + /* Done checking invite message. */ + if (pjsip_tx_data_dec_ref(invite) != PJSIP_EBUFDESTROYED) { + PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); + return -120; + } + + /* Done checking response message. */ + if (pjsip_tx_data_dec_ref(response) != PJSIP_EBUFDESTROYED) { + PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); + return -130; + } + + /* Done checking ack message. */ + if (pjsip_tx_data_dec_ref(ack) != PJSIP_EBUFDESTROYED) { + PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); + return -140; + } + + /* Done. */ + return 0; +} + + + +/* + * This test demonstrate the bug as reported in: + * http://bugzilla.pjproject.net/show_bug.cgi?id=49 + */ +#if INCLUDE_GCC_TEST +static int gcc_test() +{ + char msgbuf[512]; + pj_str_t target = pj_str("sip:alice@wonderland:5061;x-param=param%201" + "?X-Hdr-1=Header%201" + "&X-Empty-Hdr="); + pjsip_tx_data *tdata; + pjsip_parser_err_report err_list; + pjsip_msg *msg; + int len; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " header param in URI to create request")); + + /* Create request with header param in target URI. */ + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, + &target, &target, &target, NULL, -1, + NULL, &tdata); + if (status != 0) { + app_perror(" error: Unable to create request", status); + return -200; + } + + /* Print and parse the request. + * We'll check that header params are not present in + */ + len = pjsip_msg_print(tdata->msg, msgbuf, sizeof(msgbuf)); + if (len < 1) { + PJ_LOG(3,(THIS_FILE, " error: printing message")); + pjsip_tx_data_dec_ref(tdata); + return -250; + } + msgbuf[len] = '\0'; + + PJ_LOG(5,(THIS_FILE, "%d bytes request created:--begin-msg--\n" + "%s\n" + "--end-msg--", len, msgbuf)); + + /* Now parse the message. */ + pj_list_init(&err_list); + msg = pjsip_parse_msg( tdata->pool, msgbuf, len, &err_list); + if (msg == NULL) { + pjsip_parser_err_report *e; + + PJ_LOG(3,(THIS_FILE, " error: parsing message message")); + + e = err_list.next; + while (e != &err_list) { + PJ_LOG(3,(THIS_FILE, " %s in line %d col %d hname=%.*s", + pj_exception_id_name(e->except_code), + e->line, e->col+1, + (int)e->hname.slen, + e->hname.ptr)); + e = e->next; + } + + pjsip_tx_data_dec_ref(tdata); + return -255; + } + + pjsip_tx_data_dec_ref(tdata); + return 0; +} +#endif + + +/* This tests the request creating functions against the following + * requirements: + * - header params in URI creates header in the request. + * - method and headers params are correctly shown or hidden in + * request URI, From, To, and Contact header. + */ +static int txdata_test_uri_params(void) +{ + char msgbuf[512]; + pj_str_t target = pj_str("sip:alice@wonderland:5061;x-param=param%201" + "?X-Hdr-1=Header%201" + "&X-Empty-Hdr="); + pj_str_t pname = pj_str("x-param"); + pj_str_t hname = pj_str("X-Hdr-1"); + pj_str_t hemptyname = pj_str("X-Empty-Hdr"); + pjsip_from_hdr *from_hdr; + pjsip_to_hdr *to_hdr; + pjsip_contact_hdr *contact_hdr; + pjsip_generic_string_hdr *hdr; + pjsip_tx_data *tdata; + pjsip_sip_uri *uri; + pjsip_param *param; + pjsip_via_hdr *via; + pjsip_parser_err_report err_list; + pjsip_msg *msg; + int len; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " header param in URI to create request")); + + /* Create request with header param in target URI. */ + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, + &target, &target, &target, NULL, -1, + NULL, &tdata); + if (status != 0) { + app_perror(" error: Unable to create request", status); + return -200; + } + + /* Fill up the Via header to prevent syntax error on parsing */ + via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); + via->transport = pj_str("TCP"); + via->sent_by.host = pj_str("127.0.0.1"); + + /* Print and parse the request. + * We'll check that header params are not present in + */ + len = pjsip_msg_print(tdata->msg, msgbuf, sizeof(msgbuf)); + if (len < 1) { + PJ_LOG(3,(THIS_FILE, " error: printing message")); + pjsip_tx_data_dec_ref(tdata); + return -250; + } + msgbuf[len] = '\0'; + + PJ_LOG(5,(THIS_FILE, "%d bytes request created:--begin-msg--\n" + "%s\n" + "--end-msg--", len, msgbuf)); + + /* Now parse the message. */ + pj_list_init(&err_list); + msg = pjsip_parse_msg( tdata->pool, msgbuf, len, &err_list); + if (msg == NULL) { + pjsip_parser_err_report *e; + + PJ_LOG(3,(THIS_FILE, " error: parsing message message")); + + e = err_list.next; + while (e != &err_list) { + PJ_LOG(3,(THIS_FILE, " %s in line %d col %d hname=%.*s", + pj_exception_id_name(e->except_code), + e->line, e->col+1, + (int)e->hname.slen, + e->hname.ptr)); + e = e->next; + } + + pjsip_tx_data_dec_ref(tdata); + return -256; + } + + /* Check the existence of port, other_param, and header param. + * Port is now allowed in To and From header. + */ + /* Port in request URI. */ + uri = (pjsip_sip_uri*) pjsip_uri_get_uri(msg->line.req.uri); + if (uri->port != 5061) { + PJ_LOG(3,(THIS_FILE, " error: port not present in request URI")); + pjsip_tx_data_dec_ref(tdata); + return -260; + } + /* other_param in request_uri */ + param = pjsip_param_find(&uri->other_param, &pname); + if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { + PJ_LOG(3,(THIS_FILE, " error: x-param not present in request URI")); + pjsip_tx_data_dec_ref(tdata); + return -261; + } + /* header param in request uri. */ + if (!pj_list_empty(&uri->header_param)) { + PJ_LOG(3,(THIS_FILE, " error: hparam in request URI")); + pjsip_tx_data_dec_ref(tdata); + return -262; + } + + /* Port in From header. */ + from_hdr = (pjsip_from_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL); + uri = (pjsip_sip_uri*) pjsip_uri_get_uri(from_hdr->uri); + if (uri->port != 0) { + PJ_LOG(3,(THIS_FILE, " error: port most not exist in From header")); + pjsip_tx_data_dec_ref(tdata); + return -270; + } + /* other_param in From header */ + param = pjsip_param_find(&uri->other_param, &pname); + if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { + PJ_LOG(3,(THIS_FILE, " error: x-param not present in From header")); + pjsip_tx_data_dec_ref(tdata); + return -271; + } + /* header param in From header. */ + if (!pj_list_empty(&uri->header_param)) { + PJ_LOG(3,(THIS_FILE, " error: hparam in From header")); + pjsip_tx_data_dec_ref(tdata); + return -272; + } + + + /* Port in To header. */ + to_hdr = (pjsip_to_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL); + uri = (pjsip_sip_uri*) pjsip_uri_get_uri(to_hdr->uri); + if (uri->port != 0) { + PJ_LOG(3,(THIS_FILE, " error: port most not exist in To header")); + pjsip_tx_data_dec_ref(tdata); + return -280; + } + /* other_param in To header */ + param = pjsip_param_find(&uri->other_param, &pname); + if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { + PJ_LOG(3,(THIS_FILE, " error: x-param not present in To header")); + pjsip_tx_data_dec_ref(tdata); + return -281; + } + /* header param in From header. */ + if (!pj_list_empty(&uri->header_param)) { + PJ_LOG(3,(THIS_FILE, " error: hparam in To header")); + pjsip_tx_data_dec_ref(tdata); + return -282; + } + + + + /* Port in Contact header. */ + contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL); + uri = (pjsip_sip_uri*) pjsip_uri_get_uri(contact_hdr->uri); + if (uri->port != 5061) { + PJ_LOG(3,(THIS_FILE, " error: port not present in Contact header")); + pjsip_tx_data_dec_ref(tdata); + return -290; + } + /* other_param in Contact header */ + param = pjsip_param_find(&uri->other_param, &pname); + if (param == NULL || pj_strcmp2(¶m->value, "param 1") != 0) { + PJ_LOG(3,(THIS_FILE, " error: x-param not present in Contact header")); + pjsip_tx_data_dec_ref(tdata); + return -291; + } + /* header param in Contact header. */ + if (pj_list_empty(&uri->header_param)) { + PJ_LOG(3,(THIS_FILE, " error: hparam is missing in Contact header")); + pjsip_tx_data_dec_ref(tdata); + return -292; + } + /* Check for X-Hdr-1 */ + param = pjsip_param_find(&uri->header_param, &hname); + if (param == NULL || pj_strcmp2(¶m->value, "Header 1")!=0) { + PJ_LOG(3,(THIS_FILE, " error: hparam is missing in Contact header")); + pjsip_tx_data_dec_ref(tdata); + return -293; + } + /* Check for X-Empty-Hdr */ + param = pjsip_param_find(&uri->header_param, &hemptyname); + if (param == NULL || pj_strcmp2(¶m->value, "")!=0) { + PJ_LOG(3,(THIS_FILE, " error: hparam is missing in Contact header")); + pjsip_tx_data_dec_ref(tdata); + return -294; + } + + + /* Check that headers are present in the request. */ + hdr = (pjsip_generic_string_hdr*) + pjsip_msg_find_hdr_by_name(msg, &hname, NULL); + if (hdr == NULL || pj_strcmp2(&hdr->hvalue, "Header 1")!=0) { + PJ_LOG(3,(THIS_FILE, " error: header X-Hdr-1 not created")); + pjsip_tx_data_dec_ref(tdata); + return -300; + } + + hdr = (pjsip_generic_string_hdr*) + pjsip_msg_find_hdr_by_name(msg, &hemptyname, NULL); + if (hdr == NULL || pj_strcmp2(¶m->value, "")!=0) { + PJ_LOG(3,(THIS_FILE, " error: header X-Empty-Hdr not created")); + pjsip_tx_data_dec_ref(tdata); + return -330; + } + + pjsip_tx_data_dec_ref(tdata); + return 0; +} + + +/* + * create request benchmark + */ +static int create_request_bench(pj_timestamp *p_elapsed) +{ + enum { COUNT = 100 }; + unsigned i, j; + pjsip_tx_data *tdata[COUNT]; + pj_timestamp t1, t2, elapsed; + pj_status_t status; + + pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); + pj_str_t str_from = pj_str("\"Local User\" "); + pj_str_t str_to = pj_str("\"Remote User\" "); + pj_str_t str_contact = str_from; + + elapsed.u64 = 0; + + for (i=0; iu64 = elapsed.u64; + return PJ_SUCCESS; + +on_error: + for (i=0; i"); + pj_str_t str_to = pj_str("\"Remote User\" "); + pj_str_t str_contact = str_from; + + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &str_target, &str_from, &str_to, + &str_contact, NULL, -1, NULL, + &request); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return status; + } + + /* Create several Via headers */ + via = pjsip_via_hdr_create(request->pool); + via->sent_by.host = pj_str("192.168.0.7"); + via->sent_by.port = 5061; + via->transport = pj_str("udp"); + via->rport_param = 0; + via->branch_param = pj_str("012345678901234567890123456789"); + via->recvd_param = pj_str("192.168.0.7"); + pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*) pjsip_hdr_clone(request->pool, via)); + pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*) pjsip_hdr_clone(request->pool, via)); + pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); + + + /* Create "dummy" rdata from the tdata */ + pj_bzero(&rdata, sizeof(pjsip_rx_data)); + rdata.tp_info.pool = request->pool; + rdata.msg_info.msg = request->msg; + rdata.msg_info.from = (pjsip_from_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.to = (pjsip_to_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); + rdata.msg_info.cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); + rdata.msg_info.cid = (pjsip_cid_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.via = via; + + /* + * Now benchmark create_response + */ + elapsed.u64 = 0; + + for (i=0; iu64 = elapsed.u64; + pjsip_tx_data_dec_ref(request); + return PJ_SUCCESS; + +on_error: + for (i=0; ipjsip_endpt_create_request()"); + + + /* + * Benchmark create_response() + */ + PJ_LOG(3,(THIS_FILE, " benchmarking response creation:")); + for (i=0; ipjsip_endpt_create_response()"); + + + return 0; +} + diff --git a/pjsip/src/test/uri_test.c b/pjsip/src/test/uri_test.c new file mode 100644 index 00000000..d51c6fe5 --- /dev/null +++ b/pjsip/src/test/uri_test.c @@ -0,0 +1,1091 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 + */ +#include "test.h" +#include +#include + +#define THIS_FILE "uri_test.c" + + +#define ALPHANUM "abcdefghijklmnopqrstuvwxyz" \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + "0123456789" +#define MARK "-_.!~*'()" +#define USER_CHAR ALPHANUM MARK "&=+$,;?/" +#define PASS_CHAR ALPHANUM MARK "&=+$," +#define PARAM_CHAR ALPHANUM MARK "[]/:&+$" + +#define POOL_SIZE 8000 +#if defined(PJ_DEBUG) && PJ_DEBUG!=0 +# define LOOP_COUNT 10000 +#else +# define LOOP_COUNT 40000 +#endif +#define AVERAGE_URL_LEN 80 +#define THREAD_COUNT 4 + +static struct +{ + pj_highprec_t parse_len, print_len, cmp_len; + pj_timestamp parse_time, print_time, cmp_time; +} var; + + +/* URI creator functions. */ +static pjsip_uri *create_uri0( pj_pool_t *pool ); +static pjsip_uri *create_uri1( pj_pool_t *pool ); +static pjsip_uri *create_uri2( pj_pool_t *pool ); +static pjsip_uri *create_uri3( pj_pool_t *pool ); +static pjsip_uri *create_uri4( pj_pool_t *pool ); +static pjsip_uri *create_uri5( pj_pool_t *pool ); +static pjsip_uri *create_uri6( pj_pool_t *pool ); +static pjsip_uri *create_uri7( pj_pool_t *pool ); +static pjsip_uri *create_uri8( pj_pool_t *pool ); +static pjsip_uri *create_uri9( pj_pool_t *pool ); +static pjsip_uri *create_uri10( pj_pool_t *pool ); +static pjsip_uri *create_uri11( pj_pool_t *pool ); +static pjsip_uri *create_uri12( pj_pool_t *pool ); +static pjsip_uri *create_uri13( pj_pool_t *pool ); +static pjsip_uri *create_uri14( pj_pool_t *pool ); +static pjsip_uri *create_uri15( pj_pool_t *pool ); +static pjsip_uri *create_uri16( pj_pool_t *pool ); +static pjsip_uri *create_uri17( pj_pool_t *pool ); +static pjsip_uri *create_uri25( pj_pool_t *pool ); +static pjsip_uri *create_uri26( pj_pool_t *pool ); +static pjsip_uri *create_uri27( pj_pool_t *pool ); +static pjsip_uri *create_uri28( pj_pool_t *pool ); +static pjsip_uri *create_uri29( pj_pool_t *pool ); +static pjsip_uri *create_uri30( pj_pool_t *pool ); +static pjsip_uri *create_uri31( pj_pool_t *pool ); +static pjsip_uri *create_uri32( pj_pool_t *pool ); +static pjsip_uri *create_uri33( pj_pool_t *pool ); +static pjsip_uri *create_uri34( pj_pool_t *pool ); +static pjsip_uri *create_uri35( pj_pool_t *pool ); +static pjsip_uri *create_uri36( pj_pool_t *pool ); +static pjsip_uri *create_uri37( pj_pool_t *pool ); +static pjsip_uri *create_uri38( pj_pool_t *pool ); +static pjsip_uri *create_dummy( pj_pool_t *pool ); + +#define ERR_NOT_EQUAL -1001 +#define ERR_SYNTAX_ERR -1002 + +struct uri_test +{ + pj_status_t status; + char str[PJSIP_MAX_URL_SIZE]; + pjsip_uri *(*creator)(pj_pool_t *pool); + const char *printed; + pj_size_t len; +} uri_test_array[] = +{ + { + PJ_SUCCESS, + "sip:localhost", + &create_uri0 + }, + { + PJ_SUCCESS, + "sip:user@localhost", + &create_uri1 + }, + { + PJ_SUCCESS, + "sip:user:password@localhost:5060", + &create_uri2, }, + { + /* Port is specified should not match unspecified port. */ + ERR_NOT_EQUAL, + "sip:localhost:5060", + &create_uri3 + }, + { + /* All recognized parameters. */ + PJ_SUCCESS, + "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK", + &create_uri4 + }, + { + /* Params mixed with other params and header params. */ + PJ_SUCCESS, + "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry" + "?Subject=Hello%20There&Server=SIP%20Server", + &create_uri5 + }, + { + /* SIPS. */ + PJ_SUCCESS, + "sips:localhost", + &create_uri6, + }, + { + /* Name address */ + PJ_SUCCESS, + "", + &create_uri7 + }, + { + /* Name address with display name and SIPS scheme with some redundant + * whitespaced. + */ + PJ_SUCCESS, + " Power Administrator ", + &create_uri8 + }, + { + /* Name address. */ + PJ_SUCCESS, + " \"User\" ", + &create_uri9 + }, + { + /* Escaped sequence in display name (display=Strange User\"\\\"). */ + PJ_SUCCESS, + " \"Strange User\\\"\\\\\\\"\" ", + &create_uri10, + }, + { + /* Errorneous escaping in display name. */ + ERR_SYNTAX_ERR, + " \"Rogue User\\\" ", + &create_uri11, + }, + { + /* Dangling quote in display name, but that should be OK. */ + PJ_SUCCESS, + "Strange User\" ", + &create_uri12, + }, + { + /* Special characters in parameter value must be quoted. */ + PJ_SUCCESS, + "sip:localhost;pvalue=\"hello world\"", + &create_uri13, + }, + { + /* Excercise strange character sets allowed in display, user, password, + * host, and port. + */ + PJ_SUCCESS, + "This is -. !% *_+`'~ me ", + &create_uri14, + }, + { + /* Another excercise to the allowed character sets to the hostname. */ + PJ_SUCCESS, + "sip:" ALPHANUM "-_.com", + &create_uri15, + }, + { + /* Another excercise to the allowed character sets to the username + * and password. + */ + PJ_SUCCESS, + "sip:" USER_CHAR ":" PASS_CHAR "@host", + &create_uri16, + }, + { + /* Excercise to the pname and pvalue, and mixup of other-param + * between 'recognized' params. + */ + PJ_SUCCESS, + "sip:host;user=ip;" PARAM_CHAR "%21=" PARAM_CHAR "%21" + ";lr;other=1;transport=sctp;other2", + &create_uri17, + }, + { + /* 18: This should trigger syntax error. */ + ERR_SYNTAX_ERR, + "sip:", + &create_dummy, + }, + { + /* 19: Syntax error: whitespace after scheme. */ + ERR_SYNTAX_ERR, + "sip :host", + &create_dummy, + }, + { + /* 20: Syntax error: whitespace before hostname. */ + ERR_SYNTAX_ERR, + "sip: host", + &create_dummy, + }, + { + /* 21: Syntax error: invalid port. */ + ERR_SYNTAX_ERR, + "sip:user:password", + &create_dummy, + }, + { + /* 22: Syntax error: no host. */ + ERR_SYNTAX_ERR, + "sip:user@", + &create_dummy, + }, + { + /* 23: Syntax error: no user/host. */ + ERR_SYNTAX_ERR, + "sip:@", + &create_dummy, + }, + { + /* 24: Syntax error: empty string. */ + ERR_SYNTAX_ERR, + "", + &create_dummy, + }, + { + /* 25: Simple tel: URI with global context */ + PJ_SUCCESS, + "tel:+1-201-555-0123", + &create_uri25, + "tel:+1-201-555-0123" + }, + { + /* 26: Simple tel: URI with local context */ + PJ_SUCCESS, + "tel:7042;phone-context=example.com", + &create_uri26, + "tel:7042;phone-context=example.com" + }, + { + /* 27: Simple tel: URI with local context */ + PJ_SUCCESS, + "tel:863-1234;phone-context=+1-914-555", + &create_uri27, + "tel:863-1234;phone-context=+1-914-555" + }, + { + /* 28: Comparison between local and global number */ + ERR_NOT_EQUAL, + "tel:+1", + &create_uri28, + "tel:+1" + }, + { + /* 29: tel: with some visual chars and spaces */ + PJ_SUCCESS, + "tel:(44).1234-*#+Deaf", + &create_uri29, + "tel:(44).1234-*#+Deaf" + }, + { + /* 30: isub parameters */ + PJ_SUCCESS, + "tel:+1;isub=/:@&$,-_.!~*'()[]/:&$aA1%21+=", + &create_uri30, + "tel:+1;isub=/:@&$,-_.!~*'()[]/:&$aA1!+%3d" + }, + { + /* 31: extension number parsing and encoding */ + PJ_SUCCESS, + "tel:+1;ext=+123", + &create_uri31, + "tel:+1;ext=%2b123" + }, + { + /* 32: context parameter parsing and encoding */ + PJ_SUCCESS, + "tel:911;phone-context=+1-911", + &create_uri32, + "tel:911;phone-context=+1-911" + }, + { + /* 33: case-insensitive comparison */ + PJ_SUCCESS, + "tel:911;phone-context=emergency.example.com", + &create_uri33, + "tel:911;phone-context=emergency.example.com" + }, + { + /* 34: parameter only appears in one URL */ + ERR_NOT_EQUAL, + "tel:911;p1=p1;p2=p2", + &create_uri34, + "tel:911;p1=p1;p2=p2" + }, + { + /* 35: IPv6 in host and maddr parameter */ + PJ_SUCCESS, + "sip:user@[::1];maddr=[::01]", + &create_uri35, + "sip:user@[::1];maddr=[::01]" + }, + { + /* 36: IPv6 in host and maddr, without username */ + PJ_SUCCESS, + "sip:[::1];maddr=[::01]", + &create_uri36, + "sip:[::1];maddr=[::01]" + }, + { + /* 37: Non-ASCII UTF-8 in display name, with quote */ + PJ_SUCCESS, + "\"\xC0\x81\" ", + &create_uri37, + "\"\xC0\x81\" " + }, + { + /* 38: Non-ASCII UTF-8 in display name, without quote */ + PJ_SUCCESS, + "\xC0\x81 ", + &create_uri38, + "\"\xC0\x81\" " + } + +}; + +static pjsip_uri *create_uri0(pj_pool_t *pool) +{ + /* "sip:localhost" */ + pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); + + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri1(pj_pool_t *pool) +{ + /* "sip:user@localhost" */ + pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); + + pj_strdup2( pool, &url->user, "user"); + pj_strdup2( pool, &url->host, "localhost"); + + return (pjsip_uri*) url; +} + +static pjsip_uri *create_uri2(pj_pool_t *pool) +{ + /* "sip:user:password@localhost:5060" */ + pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); + + pj_strdup2( pool, &url->user, "user"); + pj_strdup2( pool, &url->passwd, "password"); + pj_strdup2( pool, &url->host, "localhost"); + url->port = 5060; + + return (pjsip_uri*) url; +} + +static pjsip_uri *create_uri3(pj_pool_t *pool) +{ + /* Like: "sip:localhost:5060", but without the port. */ + pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); + + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri4(pj_pool_t *pool) +{ + /* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */ + pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); + + pj_strdup2(pool, &url->host, "localhost"); + pj_strdup2(pool, &url->transport_param, "tcp"); + pj_strdup2(pool, &url->user_param, "ip"); + url->ttl_param = 255; + url->lr_param = 1; + pj_strdup2(pool, &url->maddr_param, "127.0.0.1"); + pj_strdup2(pool, &url->method_param, "ACK"); + + return (pjsip_uri*)url; +} + +#define param_add(list,pname,pvalue) \ + do { \ + pjsip_param *param; \ + param=PJ_POOL_ALLOC_T(pool, pjsip_param); \ + param->name = pj_str(pname); \ + param->value = pj_str(pvalue); \ + pj_list_insert_before(&list, param); \ + } while (0) + +static pjsip_uri *create_uri5(pj_pool_t *pool) +{ + /* "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry" + "?Subject=Hello%20There&Server=SIP%20Server" + */ + pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0); + + pj_strdup2(pool, &url->host, "localhost"); + pj_strdup2(pool, &url->user_param, "phone"); + + //pj_strdup2(pool, &url->other_param, ";pickup=hurry;message=I%20am%20sorry"); + param_add(url->other_param, "pickup", "hurry"); + param_add(url->other_param, "message", "I am sorry"); + + //pj_strdup2(pool, &url->header_param, "?Subject=Hello%20There&Server=SIP%20Server"); + param_add(url->header_param, "Subject", "Hello There"); + param_add(url->header_param, "Server", "SIP Server"); + return (pjsip_uri*)url; + +} + +static pjsip_uri *create_uri6(pj_pool_t *pool) +{ + /* "sips:localhost" */ + pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 1); + + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri7(pj_pool_t *pool) +{ + /* "" */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_sip_uri *url; + + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri8(pj_pool_t *pool) +{ + /* " Power Administrator " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_sip_uri *url; + + url = pjsip_sip_uri_create(pool, 1); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "Power Administrator"); + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri9(pj_pool_t *pool) +{ + /* " \"User\" " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_sip_uri *url; + + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "User"); + pj_strdup2(pool, &url->user, "user"); + pj_strdup2(pool, &url->host, "localhost"); + url->port = 5071; + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri10(pj_pool_t *pool) +{ + /* " \"Strange User\\\"\\\\\\\"\" " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_sip_uri *url; + + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "Strange User\\\"\\\\\\\""); + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri11(pj_pool_t *pool) +{ + /* " \"Rogue User\\\" " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_sip_uri *url; + + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "Rogue User\\"); + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri12(pj_pool_t *pool) +{ + /* "Strange User\" " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_sip_uri *url; + + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "Strange User\""); + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri13(pj_pool_t *pool) +{ + /* "sip:localhost;pvalue=\"hello world\"" */ + pjsip_sip_uri *url; + url = pjsip_sip_uri_create(pool, 0); + pj_strdup2(pool, &url->host, "localhost"); + //pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\""); + param_add(url->other_param, "pvalue", "\"hello world\""); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri14(pj_pool_t *pool) +{ + /* "This is -. !% *_+`'~ me " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_sip_uri *url; + + url = pjsip_sip_uri_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "This is -. !% *_+`'~ me"); + pj_strdup2(pool, &url->user, "a19A&=+$,;?/,"); + pj_strdup2(pool, &url->passwd, "@a&Zz=+$,"); + pj_strdup2(pool, &url->host, "my_proxy09.MY-domain.com"); + url->port = 9801; + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri15(pj_pool_t *pool) +{ + /* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */ + pjsip_sip_uri *url; + url = pjsip_sip_uri_create(pool, 0); + pj_strdup2(pool, &url->host, ALPHANUM "-_.com"); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri16(pj_pool_t *pool) +{ + /* "sip:" USER_CHAR ":" PASS_CHAR "@host" */ + pjsip_sip_uri *url; + url = pjsip_sip_uri_create(pool, 0); + pj_strdup2(pool, &url->user, USER_CHAR); + pj_strdup2(pool, &url->passwd, PASS_CHAR); + pj_strdup2(pool, &url->host, "host"); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri17(pj_pool_t *pool) +{ + /* "sip:host;user=ip;" PARAM_CHAR "%21=" PARAM_CHAR "%21;lr;other=1;transport=sctp;other2" */ + pjsip_sip_uri *url; + url = pjsip_sip_uri_create(pool, 0); + pj_strdup2(pool, &url->host, "host"); + pj_strdup2(pool, &url->user_param, "ip"); + pj_strdup2(pool, &url->transport_param, "sctp"); + param_add(url->other_param, PARAM_CHAR "!", PARAM_CHAR "!"); + param_add(url->other_param, "other", "1"); + param_add(url->other_param, "other2", ""); + url->lr_param = 1; + return (pjsip_uri*)url; +} + + +static pjsip_uri *create_uri25(pj_pool_t *pool) +{ + /* "tel:+1-201-555-0123" */ + pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); + + uri->number = pj_str("+1-201-555-0123"); + return (pjsip_uri*)uri; +} + +static pjsip_uri *create_uri26(pj_pool_t *pool) +{ + /* tel:7042;phone-context=example.com */ + pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); + + uri->number = pj_str("7042"); + uri->context = pj_str("example.com"); + return (pjsip_uri*)uri; +} + +static pjsip_uri *create_uri27(pj_pool_t *pool) +{ + /* "tel:863-1234;phone-context=+1-914-555" */ + pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); + + uri->number = pj_str("863-1234"); + uri->context = pj_str("+1-914-555"); + return (pjsip_uri*)uri; +} + +/* "tel:1" */ +static pjsip_uri *create_uri28(pj_pool_t *pool) +{ + pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); + + uri->number = pj_str("1"); + return (pjsip_uri*)uri; +} + +/* "tel:(44).1234-*#+Deaf" */ +static pjsip_uri *create_uri29(pj_pool_t *pool) +{ + pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); + + uri->number = pj_str("(44).1234-*#+Deaf"); + return (pjsip_uri*)uri; +} + +/* "tel:+1;isub=/:@&$,-_.!~*'()[]/:&$aA1%21+=" */ +static pjsip_uri *create_uri30(pj_pool_t *pool) +{ + pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); + + uri->number = pj_str("+1"); + uri->isub_param = pj_str("/:@&$,-_.!~*'()[]/:&$aA1!+="); + return (pjsip_uri*)uri; +} + +/* "tel:+1;ext=+123" */ +static pjsip_uri *create_uri31(pj_pool_t *pool) +{ + pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); + + uri->number = pj_str("+1"); + uri->ext_param = pj_str("+123"); + return (pjsip_uri*)uri; +} + +/* "tel:911;phone-context=+1-911" */ +static pjsip_uri *create_uri32(pj_pool_t *pool) +{ + pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); + + uri->number = pj_str("911"); + uri->context = pj_str("+1-911"); + return (pjsip_uri*)uri; +} + +/* "tel:911;phone-context=emergency.example.com" */ +static pjsip_uri *create_uri33(pj_pool_t *pool) +{ + pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); + + uri->number = pj_str("911"); + uri->context = pj_str("EMERGENCY.EXAMPLE.COM"); + return (pjsip_uri*)uri; +} + +/* "tel:911;p1=p1;p2=p2" */ +static pjsip_uri *create_uri34(pj_pool_t *pool) +{ + pjsip_tel_uri *uri = pjsip_tel_uri_create(pool); + pjsip_param *p; + + uri->number = pj_str("911"); + + p = PJ_POOL_ALLOC_T(pool, pjsip_param); + p->name = p->value = pj_str("p1"); + pj_list_insert_before(&uri->other_param, p); + + return (pjsip_uri*)uri; +} + +/* "sip:user@[::1];maddr=[::01]" */ +static pjsip_uri *create_uri35( pj_pool_t *pool ) +{ + pjsip_sip_uri *url; + url = pjsip_sip_uri_create(pool, 0); + url->user = pj_str("user"); + url->host = pj_str("::1"); + url->maddr_param = pj_str("::01"); + return (pjsip_uri*)url; +} + +/* "sip:[::1];maddr=[::01]" */ +static pjsip_uri *create_uri36( pj_pool_t *pool ) +{ + pjsip_sip_uri *url; + url = pjsip_sip_uri_create(pool, 0); + url->host = pj_str("::1"); + url->maddr_param = pj_str("::01"); + return (pjsip_uri*)url; + +} + +/* "\"\xC0\x81\" " */ +static pjsip_uri *create_uri37( pj_pool_t *pool ) +{ + pjsip_name_addr *name; + pjsip_sip_uri *url; + + name = pjsip_name_addr_create(pool); + name->display = pj_str("\xC0\x81"); + + url = pjsip_sip_uri_create(pool, 0); + url->host = pj_str("localhost"); + + name->uri = (pjsip_uri*)url; + + return (pjsip_uri*)name; + +} + +/* "\xC0\x81 " */ +static pjsip_uri *create_uri38( pj_pool_t *pool ) +{ + pjsip_name_addr *name; + pjsip_sip_uri *url; + + name = pjsip_name_addr_create(pool); + name->display = pj_str("\xC0\x81"); + + url = pjsip_sip_uri_create(pool, 0); + url->host = pj_str("localhost"); + + name->uri = (pjsip_uri*)url; + + return (pjsip_uri*)name; + +} + +static pjsip_uri *create_dummy(pj_pool_t *pool) +{ + PJ_UNUSED_ARG(pool); + return NULL; +} + +/*****************************************************************************/ + +/* + * Test one test entry. + */ +static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) +{ + pj_status_t status; + int len; + char *input; + pjsip_uri *parsed_uri, *ref_uri; + pj_str_t s1 = {NULL, 0}, s2 = {NULL, 0}; + pj_timestamp t1, t2; + + if (entry->len == 0) + entry->len = pj_ansi_strlen(entry->str); + +#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0 + input = pj_pool_alloc(pool, entry->len + 1); + pj_memcpy(input, entry->str, entry->len); + input[entry->len] = '\0'; +#else + input = entry->str; +#endif + + /* Parse URI text. */ + pj_get_timestamp(&t1); + var.parse_len = var.parse_len + entry->len; + parsed_uri = pjsip_parse_uri(pool, input, entry->len, 0); + if (!parsed_uri) { + /* Parsing failed. If the entry says that this is expected, then + * return OK. + */ + status = entry->status==ERR_SYNTAX_ERR ? PJ_SUCCESS : -10; + if (status != 0) { + PJ_LOG(3,(THIS_FILE, " uri parse error!\n" + " uri='%s'\n", + input)); + } + goto on_return; + } + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&var.parse_time, &t2); + + /* Create the reference URI. */ + ref_uri = entry->creator(pool); + + /* Print both URI. */ + s1.ptr = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); + s2.ptr = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); + + pj_get_timestamp(&t1); + len = pjsip_uri_print( PJSIP_URI_IN_OTHER, parsed_uri, s1.ptr, PJSIP_MAX_URL_SIZE); + if (len < 1) { + status = -20; + goto on_return; + } + s1.ptr[len] = '\0'; + s1.slen = len; + + var.print_len = var.print_len + len; + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&var.print_time, &t2); + + len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE); + if (len < 1) { + status = -30; + goto on_return; + } + s2.ptr[len] = '\0'; + s2.slen = len; + + /* Full comparison of parsed URI with reference URI. */ + pj_get_timestamp(&t1); + status = pjsip_uri_cmp(PJSIP_URI_IN_OTHER, parsed_uri, ref_uri); + if (status != 0) { + /* Not equal. See if this is the expected status. */ + status = entry->status==ERR_NOT_EQUAL ? PJ_SUCCESS : -40; + if (status != 0) { + PJ_LOG(3,(THIS_FILE, " uri comparison mismatch, status=%d:\n" + " uri1='%s'\n" + " uri2='%s'", + status, s1.ptr, s2.ptr)); + } + goto on_return; + + } else { + /* Equal. See if this is the expected status. */ + status = entry->status==PJ_SUCCESS ? PJ_SUCCESS : -50; + if (status != PJ_SUCCESS) { + goto on_return; + } + } + + var.cmp_len = var.cmp_len + len; + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&var.cmp_time, &t2); + + /* Compare text. */ + if (entry->printed) { + if (pj_strcmp2(&s1, entry->printed) != 0) { + /* Not equal. */ + PJ_LOG(3,(THIS_FILE, " uri print mismatch:\n" + " printed='%s'\n" + " expectd='%s'", + s1.ptr, entry->printed)); + status = -60; + } + } else { + if (pj_strcmp(&s1, &s2) != 0) { + /* Not equal. */ + PJ_LOG(3,(THIS_FILE, " uri print mismatch:\n" + " uri1='%s'\n" + " uri2='%s'", + s1.ptr, s2.ptr)); + status = -70; + } + } + +on_return: + return status; +} + + +static int simple_uri_test(void) +{ + unsigned i; + pj_pool_t *pool; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " simple test")); + for (i=0; i max) max = run[i].parse; + + PJ_LOG(3,("", " Maximum URI parse/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be parsed with " + "pjsip_parse_uri() per second " + "(tested with %d URI set, with average length of " + "%d chars)", + (int)PJ_ARRAY_SIZE(uri_test_array), avg_len); + + report_ival("uri-parse-per-sec", max, "URI/sec", desc); + + /* URI parsing bandwidth */ + report_ival("uri-parse-bandwidth-mb", avg_len*max/1000000, "MB/sec", + "URI parsing bandwidth in megabytes (number of megabytes " + "worth of URI that can be parsed per second)"); + + + /* Print maximum print/sec */ + for (i=0, max=0; i max) max = run[i].print; + + PJ_LOG(3,("", " Maximum URI print/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be printed with " + "pjsip_uri_print() per second " + "(tested with %d URI set, with average length of " + "%d chars)", + (int)PJ_ARRAY_SIZE(uri_test_array), avg_len); + + report_ival("uri-print-per-sec", max, "URI/sec", desc); + + /* Print maximum detect/sec */ + for (i=0, max=0; i max) max = run[i].cmp; + + PJ_LOG(3,("", " Maximum URI comparison/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be compared with " + "pjsip_uri_cmp() per second " + "(tested with %d URI set, with average length of " + "%d chars)", + (int)PJ_ARRAY_SIZE(uri_test_array), avg_len); + + report_ival("uri-cmp-per-sec", max, "URI/sec", desc); + +#endif /* INCLUDE_BENCHMARKS */ + + return PJ_SUCCESS; +} + diff --git a/third_party/build/g7221/libg7221codec.vcproj b/third_party/build/g7221/libg7221codec.vcproj index fed93a5a..78fa52e4 100644 --- a/third_party/build/g7221/libg7221codec.vcproj +++ b/third_party/build/g7221/libg7221codec.vcproj @@ -13,15 +13,17 @@ + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + @@ -1080,7 +2255,7 @@ /> - - + + + + + + + + + + + + + + + + + + @@ -1200,7 +2425,7 @@ /> - - - - + + + + + + + + + + + + - - + + + + + + @@ -1324,7 +2591,7 @@ /> - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1482,6 +1745,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1499,6 +1770,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1516,6 +1795,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1533,6 +1820,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1550,6 +1845,14 @@ Name="VCCLCompilerTool" /> + + + + + + @@ -1588,6 +1899,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1605,6 +1924,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1622,6 +1949,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1639,6 +1974,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1656,6 +1999,14 @@ Name="VCCLCompilerTool" /> + + + + + + @@ -1888,6 +2247,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1905,6 +2272,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1922,6 +2297,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1939,6 +2322,14 @@ Name="VCCLCompilerTool" /> + + + @@ -1956,6 +2347,14 @@ Name="VCCLCompilerTool" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/third_party/build/speex/libspeex.vcproj b/third_party/build/speex/libspeex.vcproj index fe504d94..34aa543c 100644 --- a/third_party/build/speex/libspeex.vcproj +++ b/third_party/build/speex/libspeex.vcproj @@ -4,6 +4,7 @@ Version="8.00" Name="libspeex" ProjectGUID="{4B059DBA-CD9C-4D0F-BE8C-FFB4EFD498E9}" + RootNamespace="libspeex" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +