diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index faaca2cb59..7a5293a7fa 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -1,25 +1,34 @@ -name: CI Linux +name: CI Ubuntu on: push: branches: - 'master' pull_request: types: [opened, synchronize, reopened] +env: + CI_ARGS: ${{ vars.CI_UBUNTU_ARGS }} + CI_MODE: ${{ vars.CI_MODE }} + MAKE_FAST: make -j 3 jobs: - build-ubuntu-default: - # checking pure lib source distribution with plain configure & make + default-build: + # checking pure lib source distribution with plain configure & make runs-on: ubuntu-latest + name: Default / build only steps: - uses: actions/checkout@v2 - name: configure run: ./configure - name: make - run: make + run: $MAKE_FAST + - name: get SSL info + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep SSL + - name: verify oepnssl is used + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep -E 'PJ_SSL_SOCK_IMP\s+:\s+1' - ubuntu-default-full-bundle-1: - # full bundle: enable all codecs + AEC + DTLS - # full bundle 1: running pjlib, pjlib-util, pjmedia, and pjsua tests + default-full-bundle-1: + # full bundle: enable all codecs + AEC + DTLS runs-on: ubuntu-latest + name: Default / pjmedia,pjsua steps: - uses: actions/checkout@v2 - name: install dependencies @@ -29,19 +38,33 @@ jobs: - name: configure run: CFLAGS="-g -fPIC" CXXFLAGS="-g -fPIC" LDFLAGS="-rdynamic" ./configure - name: make - run: make + run: $MAKE_FAST - name: swig bindings run: cd pjsip-apps/src/swig && make - name: set up Python 3.10 for pjsua test uses: actions/setup-python@v2 with: python-version: '3.10' - - name: unit tests - run: make pjlib-test-ci pjlib-util-test pjmedia-test pjsua-test + - name: capture pjsua capabilities + run: | + cat << EOF | pjsip-apps/bin/pjsua-`make infotarget` --log-level 3 > pjsua-caps + Cp + xx + vid dev list + vid codec list + q + EOF + cat pjsua-caps + - name: ensure AMR codec is installed + run: cat pjsua-caps | grep -E 'AMR/8000' + - name: pjmedia-test + run: make pjmedia-test + - name: pjsua-test + run: make pjsua-test - ubuntu-default-full-bundle-2: - # full bundle 2: running pjnath test + default-full-bundle-2: runs-on: ubuntu-latest + name: Default / pjlib,util,pjnath steps: - uses: actions/checkout@v2 - name: install dependencies @@ -51,13 +74,17 @@ jobs: - name: configure run: CFLAGS="-g" LDFLAGS="-rdynamic" ./configure - name: make - run: make - - name: unit tests + run: $MAKE_FAST + - name: pjlib-test + run: make pjlib-test + - name: pjlib-util-test + run: make pjlib-util-test + - name: pjnath-test run: make pjnath-test - ubuntu-default-full-bundle-3: - # full bundle 3: running pjsip test + default-full-bundle-3: runs-on: ubuntu-latest + name: Default / pjsip steps: - uses: actions/checkout@v2 - name: install dependencies @@ -67,13 +94,13 @@ jobs: - name: configure run: CFLAGS="-g" LDFLAGS="-rdynamic" ./configure - name: make - run: make - - name: unit tests + run: $MAKE_FAST + - name: pjsip-test run: make pjsip-test - build-ubuntu-no-tls: - # no TLS + no-tls: runs-on: ubuntu-latest + name: No SSL / pjlib,pjsip steps: - uses: actions/checkout@v2 - name: install dependencies @@ -81,16 +108,20 @@ jobs: - name: configure run: CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure --disable-ssl - name: make - run: make + run: $MAKE_FAST - name: swig bindings run: cd pjsip-apps/src/swig && make + - name: pjlib-test + run: make pjlib-test + - name: pjsip-test + run: make pjsip-test # build-ubuntu-openssl # TLS: with OpenSSL (same as build-ubuntu-default) - build-ubuntu-gnu-tls: - # TLS: with GnuTLS + gnu-tls: runs-on: ubuntu-latest + name: GnuTLS / pjlib,pjnath,pjsip steps: - uses: actions/checkout@v2 - name: install dependencies @@ -98,95 +129,149 @@ jobs: - name: configure run: CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure --with-gnutls=/usr/ - name: make - run: make + run: $MAKE_FAST - name: swig bindings run: cd pjsip-apps/src/swig && make + - name: get SSL info + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep SSL + - name: verify gnu tls is used + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep -E 'PJ_SSL_SOCK_IMP\s+:\s+2' + - name: pjlib-test + run: make pjlib-test + - name: pjnath-test + run: make pjnath-test + - name: pjsip-test + run: make pjsip-test - ubuntu-video-openh264-1: - # video: video enabled with vpx and openh264 - # video 1: running pjlib, pjlib-util, pjmedia, and pjsua tests + vid-openh264-1: runs-on: ubuntu-latest + name: OpenH264+VPX / pjmedia,pjsua steps: - uses: actions/checkout@v2 - name: install dependencies - run: sudo apt-get install -y swig nasm sip-tester libvpx-dev libopencore-amrnb-dev + run: sudo apt-get install -y swig nasm sip-tester libvpx-dev libopencore-amrnb-dev libsdl2-dev - name: get openh264 - run: git clone --single-branch --branch openh264v2.1.0 https://github.com/cisco/openh264.git + run: git clone --depth 1 --single-branch --branch openh264v2.1.0 https://github.com/cisco/openh264.git - name: build openh264 - run: cd openh264 && make && sudo make install && sudo ldconfig + run: cd openh264 && $MAKE_FAST && sudo make install && sudo ldconfig - name: config site run: cd pjlib/include/pj && cp config_site_test.h config_site.h && echo "#define PJMEDIA_HAS_VIDEO 1" >> config_site.h - name: configure run: CFLAGS="-g -fPIC -DHAS_VID_CODEC_TEST=0" CXXFLAGS="-g -fPIC" LDFLAGS="-rdynamic" ./configure - name: make - run: make + run: $MAKE_FAST - name: swig bindings run: cd pjsip-apps/src/swig && make - name: set up Python 3.10 for pjsua test uses: actions/setup-python@v4 with: python-version: '3.10' - - name: unit tests - run: make pjlib-test-ci pjlib-util-test pjmedia-test pjsua-test + - name: capture pjsua capabilities + run: | + cat << EOF | pjsip-apps/bin/pjsua-`make infotarget` --log-level 3 > pjsua-caps + Cp + xx + vid dev list + vid codec list + q + EOF + cat pjsua-caps + - name: ensure AMR codec is installed + run: cat pjsua-caps | grep -E 'AMR/8000' + - name: ensure H264 codec is installed + run: cat pjsua-caps | grep -E 'H264/' + - name: ensure VP8 codec is installed + run: cat pjsua-caps | grep -E 'VP8/' + # SDL error: no available vid dev + #- name: ensure SDL is installed + # run: cat pjsua-caps | grep -E '\[SDL\]\[render\]' + - name: pjmedia-test + run: make pjmedia-test + - name: pjsua-test + run: make pjsua-test - ubuntu-video-openh264-2: - # video 2: running pjnath test + vid-openh264-2: runs-on: ubuntu-latest + name: OpenH264+VPX / pjlib,util,pjnath steps: - uses: actions/checkout@v2 - name: install dependencies - run: sudo apt-get install -y nasm libvpx-dev libopencore-amrnb-dev + run: sudo apt-get install -y nasm libvpx-dev libopencore-amrnb-dev libsdl2-dev - name: get openh264 - run: git clone --single-branch --branch openh264v2.1.0 https://github.com/cisco/openh264.git + run: git clone --depth 1 --single-branch --branch openh264v2.1.0 https://github.com/cisco/openh264.git - name: build openh264 - run: cd openh264 && make && sudo make install && sudo ldconfig + run: cd openh264 && $MAKE_FAST && sudo make install && sudo ldconfig - name: config site run: cd pjlib/include/pj && cp config_site_test.h config_site.h && echo "#define PJMEDIA_HAS_VIDEO 1" >> config_site.h - name: configure run: CFLAGS="-g" LDFLAGS="-rdynamic" ./configure - name: make - run: make - - name: unit tests + run: $MAKE_FAST + - name: pjlib-test + run: make pjlib-test + - name: pjlib-util-test + run: make pjlib-util-test + - name: pjnath-test run: make pjnath-test - ubuntu-video-openh264-3: - # video: 3: running pjsip test + vid-openh264-3: runs-on: ubuntu-latest + name: OpenH264+VPX / pjsip steps: - uses: actions/checkout@v2 - name: install dependencies - run: sudo apt-get install -y nasm libvpx-dev libopencore-amrnb-dev + run: sudo apt-get install -y nasm libvpx-dev libopencore-amrnb-dev libsdl2-dev - name: get openh264 - run: git clone --single-branch --branch openh264v2.1.0 https://github.com/cisco/openh264.git + run: git clone --depth 1 --single-branch --branch openh264v2.1.0 https://github.com/cisco/openh264.git - name: build openh264 - run: cd openh264 && make && sudo make install && sudo ldconfig + run: cd openh264 && $MAKE_FAST && sudo make install && sudo ldconfig - name: config site run: cd pjlib/include/pj && cp config_site_test.h config_site.h && echo "#define PJMEDIA_HAS_VIDEO 1" >> config_site.h - name: configure run: CFLAGS="-g" LDFLAGS="-rdynamic" ./configure - name: make - run: make - - name: unit tests + run: $MAKE_FAST + - name: pjsip-test run: make pjsip-test - build-ubuntu-video-ffmpeg: - # video enabled with vpx and ffmpeg and x264 + vid-ffmpeg: runs-on: ubuntu-latest + name: FFMPEG+x264 / pjmedia steps: - uses: actions/checkout@v2 - name: install dependencies - run: sudo apt-get install -y swig nasm libx264-dev libvpx-dev + run: sudo apt-get install -y swig nasm libx264-dev libvpx-dev libsdl2-dev - name: get ffmpeg - run: git clone --single-branch --branch release/4.2 https://github.com/FFmpeg/FFmpeg.git + run: git clone --depth 1 --single-branch --branch release/4.2 https://github.com/FFmpeg/FFmpeg.git - name: configure ffmpeg run: cd FFmpeg && ./configure --enable-shared --disable-static --enable-gpl --enable-libx264 - name: build ffmpeg - run: cd FFmpeg && make -j10 && sudo make install + run: cd FFmpeg && $MAKE_FAST && sudo make install - name: config site run: echo -e "#define PJMEDIA_HAS_VIDEO 1\n" > pjlib/include/pj/config_site.h - name: configure run: CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure - name: make - run: make + run: $MAKE_FAST - name: swig bindings run: cd pjsip-apps/src/swig && make + - name: capture pjsua capabilities + run: | + export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH + cat << EOF | pjsip-apps/bin/pjsua-`make infotarget` --log-level 3 > pjsua-caps + Cp + xx + vid dev list + vid codec list + q + EOF + cat pjsua-caps + - name: ensure H264 codec is installed + run: cat pjsua-caps | grep -E 'H264/' + - name: ensure VP8 codec is installed + run: cat pjsua-caps | grep -E 'VP8/' + # SDL error: no available vid dev + #- name: ensure SDL is installed + # run: cat pjsua-caps | grep -E '\[SDL\]\[render\]' + - name: pjmedia-test + run: export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH && make pjmedia-test diff --git a/.github/workflows/ci-mac.yml b/.github/workflows/ci-mac.yml index d664932558..a550773842 100644 --- a/.github/workflows/ci-mac.yml +++ b/.github/workflows/ci-mac.yml @@ -1,67 +1,74 @@ -name: CI Mac +name: CI MacOS on: push: branches: - 'master' pull_request: types: [opened, synchronize, reopened] +env: + CI_ARGS: ${{ vars.CI_MAC_ARGS }} + CI_MODE: ${{ vars.CI_MODE }} + MAKE_FAST: make -j 2 jobs: - build-mac-default: - # checking pure lib source distribution with plain configure & make + default-build: + # checking pure lib source distribution with plain configure & make runs-on: macos-latest + name: Default / build only steps: - uses: actions/checkout@v2 - name: configure run: ./configure - name: make - run: make + run: $MAKE_FAST - mac-default-full-bundle-1: - # full bundle: enable all codecs + AEC + DTLS - # full bundle 1: running pjlib, pjlib-util, pjmedia, and pjsua tests + default-pjlib-util-pjmedia-pjnath: + # full bundle: enable all codecs + AEC + DTLS runs-on: macos-latest + name: Default / pjmedia,pjnath steps: - uses: actions/checkout@v2 - name: install dependencies - run: brew install openssl opencore-amr swig sipp + run: brew install openssl opencore-amr - name: config site run: cd pjlib/include/pj && cp config_site_test.h config_site.h - name: configure run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb) -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" CXXFLAGS="-g -fPIC" ./configure - name: make - run: make - - name: set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - name: swig bindings - run: cd pjsip-apps/src/swig && make + run: $MAKE_FAST - name: disable firewall run: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off - - name: unit tests - run: make pjlib-test-ci pjmedia-test pjlib-util-test pjsua-test + - name: pjmedia-test + run: make pjmedia-test + - name: pjnath-test + run: make pjnath-test - mac-default-full-bundle-2: - # full bundle 2: running pjnath test + default-pjsua-test: runs-on: macos-latest + name: Default / pjsua-test steps: - uses: actions/checkout@v2 - name: install dependencies - run: brew install openssl opencore-amr + run: brew install openssl opencore-amr swig sipp + - name: set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' - name: config site run: cd pjlib/include/pj && cp config_site_test.h config_site.h - name: configure - run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb)" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" ./configure + run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb) -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" CXXFLAGS="-g -fPIC" ./configure - name: make - run: make + run: $MAKE_FAST - name: disable firewall run: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off - - name: unit tests - run: make pjnath-test + - name: swig bindings + run: cd pjsip-apps/src/swig && make + - name: pjsua-test + run: make pjsua-test - mac-default-full-bundle-3: - # full bundle 3: running pjsip test + default-pjsip-test: runs-on: macos-latest + name: Default / pjlib,util,pjsip-test steps: - uses: actions/checkout@v2 - name: install dependencies @@ -71,55 +78,123 @@ jobs: - name: configure run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb)" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" ./configure - name: make - run: make + run: $MAKE_FAST - name: disable firewall run: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off - - name: unit tests + - name: pjlib-test + run: make pjlib-test + - name: pjlib-util-test + run: make pjlib-util-test + - name: pjsip-test run: make pjsip-test - # build-ubuntu-no-tls: - # no TLS (same as build-mac-default) - - build-mac-openssl: - # TLS: with OpenSSL + openssl-1: runs-on: macos-latest + name: OpenSSL / pjlib,util,pjnath,pjmedia steps: - uses: actions/checkout@v2 - name: install dependencies run: brew install openssl swig - name: configure run: CFLAGS="$(pkg-config --cflags openssl) -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib" CXXFLAGS="-fPIC" ./configure + - name: config site + run: cd pjlib/include/pj && cp config_site_test.h config_site.h - name: make - run: make + run: $MAKE_FAST - name: set up Python uses: actions/setup-python@v4 with: python-version: '3.10' - name: swig bindings run: cd pjsip-apps/src/swig && make + - name: disable firewall + run: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off + - name: get SSL info + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep SSL + - name: verify openssl is used + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep -E 'PJ_SSL_SOCK_IMP\s+:\s+1' + - name: pjlib-test + run: make pjlib-test + - name: pjlib-util-test + run: make pjlib-util-test + - name: pjmedia-test + run: make pjmedia-test + - name: pjnath-test + run: make pjnath-test + + openssl-2: + runs-on: macos-latest + name: OpenSSL / pjsip + steps: + - uses: actions/checkout@v2 + - name: install dependencies + run: brew install openssl + - name: configure + run: CFLAGS="$(pkg-config --cflags openssl) -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib" CXXFLAGS="-fPIC" ./configure + - name: config site + run: cd pjlib/include/pj && cp config_site_test.h config_site.h + - name: make + run: $MAKE_FAST + - name: disable firewall + run: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off + - name: get SSL info + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep SSL + - name: verify openssl is used + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep -E 'PJ_SSL_SOCK_IMP\s+:\s+1' + - name: pjsip-test + run: make pjsip-test - build-mac-gnu-tls: - # TLS: with GnuTLS + gnu-tls-1: runs-on: macos-latest + name: GnuTLS / pjlib,util,pjmedia,pjnath steps: - uses: actions/checkout@v2 - name: install dependencies - run: brew install swig + run: brew install gnutls swig - name: configure - run: CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure --with-gnutls=/usr/local/ + run: CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure --with-gnutls=`brew --prefix gnutls` - name: make - run: make + run: $MAKE_FAST - name: set up Python uses: actions/setup-python@v4 with: python-version: '3.10' - name: swig bindings run: cd pjsip-apps/src/swig && make + - name: get SSL info + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep SSL + - name: verify gnu tls is used + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep -E 'PJ_SSL_SOCK_IMP\s+:\s+2' + - name: pjlib-test + run: make pjlib-test + - name: pjlib-util-test + run: make pjlib-util-test + - name: pjmedia-test + run: make pjmedia-test + - name: pjnath-test + run: make pjnath-test + + gnu-tls-2: + runs-on: macos-latest + name: GnuTLS / pjsip-test + steps: + - uses: actions/checkout@v2 + - name: install dependencies + run: brew install gnutls swig + - name: configure + run: CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure --with-gnutls=`brew --prefix gnutls` + - name: make + run: $MAKE_FAST + - name: get SSL info + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep SSL + - name: verify gnu tls is used + run: pjlib/bin/pjlib-test-`make infotarget` --config --list | grep -E 'PJ_SSL_SOCK_IMP\s+:\s+2' + - name: pjsip-test + run: make pjsip-test - mac-video-openh264-1: - # video: video enabled with vpx and openh264 - # video 1: running pjlib, pjlib-util, pjmedia, and pjsua tests + video-openh264-1: runs-on: macos-latest + name: Openh264+VPX / pjmedia,pjsua steps: - uses: actions/checkout@v2 - name: install dependencies @@ -129,7 +204,7 @@ jobs: - name: configure run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb) -DHAS_VID_CODEC_TEST=0 -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" CXXFLAGS="-g -fPIC" ./configure - name: make - run: make + run: $MAKE_FAST - name: set up Python uses: actions/setup-python@v4 with: @@ -138,12 +213,14 @@ jobs: run: cd pjsip-apps/src/swig && make - name: disable firewall run: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off - - name: unit tests - run: make pjlib-test-ci pjmedia-test pjlib-util-test pjsua-test + - name: pjmedia-test + run: make pjmedia-test + - name: pjsua-test + run: make pjsua-test - mac-video-openh264-2: - # video 2: running pjnath test + video-openh264-2: runs-on: macos-latest + name: Openh264+VPX / util,pjnath steps: - uses: actions/checkout@v2 - name: install dependencies @@ -153,15 +230,17 @@ jobs: - name: configure run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb)" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" ./configure - name: make - run: make + run: $MAKE_FAST - name: disable firewall run: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off - - name: unit tests + - name: pjlib-util-test + run: make pjlib-util-test + - name: pjnath-test run: make pjnath-test - mac-video-openh264-3: - # video 3: running pjsip test + video-openh264-3: runs-on: macos-latest + name: Openh264+VPX / pjlib,pjsip steps: - uses: actions/checkout@v2 - name: install dependencies @@ -171,41 +250,45 @@ jobs: - name: configure run: CFLAGS="-g $(pkg-config --cflags openssl) $(pkg-config --cflags opencore-amrnb)" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib $(pkg-config --libs-only-L opencore-amrnb)" ./configure - name: make - run: make + run: $MAKE_FAST - name: disable firewall run: sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off - - name: unit tests + - name: pjlib-test + run: make pjlib-test + - name: pjsip-test run: make pjsip-test - build-mac-video-ffmpeg: - # video enabled with vpx and ffmpeg and x264 + video-ffmpeg: runs-on: macos-latest + name: FFMPEG+VPX+x264 / pjmedia steps: - uses: actions/checkout@v2 - name: install dependencies run: brew install openssl x264 libvpx nasm swig - name: get ffmpeg - run: git clone --single-branch --branch release/7.0 https://github.com/FFmpeg/FFmpeg.git + run: git clone --depth 1 --single-branch --branch release/7.0 https://github.com/FFmpeg/FFmpeg.git - name: configure ffmpeg run: cd FFmpeg && LDFLAGS="-Wl,-ld_classic" ./configure --enable-shared --disable-static --enable-gpl --enable-libx264 - name: build ffmpeg - run: cd FFmpeg && make -j10 && sudo make install + run: cd FFmpeg && $MAKE_FAST && sudo make install - name: config site run: echo -e "#define PJMEDIA_HAS_VIDEO 1\n" > pjlib/include/pj/config_site.h - name: configure run: CFLAGS="$(pkg-config --cflags openssl) -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib" CXXFLAGS="-fPIC" ./configure - name: make - run: make + run: $MAKE_FAST - name: set up Python uses: actions/setup-python@v4 with: python-version: '3.10' - name: swig bindings run: cd pjsip-apps/src/swig && make + - name: pjmedia-test + run: make pjmedia-test - build-mac-video-vid-toolbox: - # video enabled with vpx and video toolbox + video-vid-toolbox: runs-on: macos-latest + name: VPX+VidToolbox / pjmedia steps: - uses: actions/checkout@v2 - name: install dependencies @@ -215,10 +298,12 @@ jobs: - name: configure run: CFLAGS="$(pkg-config --cflags openssl) -fPIC" LDFLAGS="$(pkg-config --libs-only-L openssl) $(pkg-config --libs-only-L openssl)/lib" CXXFLAGS="-fPIC" ./configure - name: make - run: make + run: $MAKE_FAST - name: set up Python uses: actions/setup-python@v4 with: python-version: '3.10' - name: swig bindings run: cd pjsip-apps/src/swig && make + - name: pjmedia-test + run: make pjmedia-test diff --git a/.github/workflows/ci-win.yml b/.github/workflows/ci-win.yml index bff96d083c..6a76d386bc 100644 --- a/.github/workflows/ci-win.yml +++ b/.github/workflows/ci-win.yml @@ -6,8 +6,9 @@ on: pull_request: types: [opened, synchronize, reopened] jobs: - build-windows-default: + default: runs-on: windows-latest + name: Default / build only steps: - uses: actions/checkout@master - name: get swig @@ -40,8 +41,9 @@ jobs: msbuild swig_java_pjsua2.vcxproj /p:PlatformToolset=v143 /p:Configuration=Debug /p:Platform=win32 /p:UseEnv=true shell: cmd - windows-with-openssl-unit-test-1: + openssl-1: runs-on: windows-latest + name: OpenSSL / pjlib,util,pjmedia steps: - uses: actions/checkout@master - name: get openssl @@ -75,17 +77,31 @@ jobs: set LIB=%LIB%;%OPENSSL_DIR%\lib msbuild pjproject-vs14.sln /p:PlatformToolset=v143 /p:Configuration=Release /p:Platform=win32 /p:UseEnv=true shell: cmd - - name: unit tests + - name: pjlib-test run: | $env:OPENSSL_DIR = Get-Content .\openssl_dir.txt $env:PATH+=";$env:OPENSSL_DIR\bin" - cd pjlib/bin; ./pjlib-test-i386-Win32-vc14-Release.exe --ci-mode - cd ../../pjlib-util/bin; ./pjlib-util-test-i386-Win32-vc14-Release.exe - cd ../../pjmedia/bin/; ./pjmedia-test-i386-Win32-vc14-Release.exe + cd pjlib/bin + ./pjlib-test-i386-Win32-vc14-Release.exe ${{ vars.CI_WIN_ARGS }} ${{ vars.CI_MODE }} + shell: powershell + - name: pjlib-util-test + run: | + $env:OPENSSL_DIR = Get-Content .\openssl_dir.txt + $env:PATH+=";$env:OPENSSL_DIR\bin" + cd pjlib-util/bin + ./pjlib-util-test-i386-Win32-vc14-Release.exe ${{ vars.CI_WIN_ARGS }} + shell: powershell + - name: pjmedia-test + run: | + $env:OPENSSL_DIR = Get-Content .\openssl_dir.txt + $env:PATH+=";$env:OPENSSL_DIR\bin" + cd pjmedia/bin + ./pjmedia-test-i386-Win32-vc14-Release.exe ${{ vars.CI_WIN_ARGS }} shell: powershell - windows-with-openssl-unit-test-2: + openssl-2: runs-on: windows-latest + name: OpenSSL / pjsip,pjsua steps: - uses: actions/checkout@master - name: get openssl @@ -103,6 +119,14 @@ jobs: dir "%OPENSSL_DIR%\include" dir "%OPENSSL_DIR%\lib" shell: cmd + - name: install SIPp + run: | + Invoke-WebRequest -Uri "https://github.com/pjsip/third_party_libs/raw/main/sipp-3.2-win.zip" -OutFile ".\sipp.zip" + Expand-Archive -LiteralPath .\sipp.zip -DestinationPath . + cd sipp + Add-Content ..\sipp_dir.txt $pwd.Path + cd .. + shell: powershell - name: config site run: cd pjlib/include/pj; cp config_site_test.h config_site.h; Add-Content config_site.h "#define PJ_HAS_SSL_SOCK 1" @@ -132,16 +156,70 @@ jobs: uses: actions/setup-python@v4 with: python-version: '3.10' - - name: unit tests + - name: pjsip-test + run: | + $env:OPENSSL_DIR = Get-Content .\openssl_dir.txt + $env:PATH+=";$env:OPENSSL_DIR\bin" + cd pjsip/bin + ./pjsip-test-i386-Win32-vc14-Release.exe ${{ vars.CI_WIN_ARGS }} + shell: powershell + - name: python pjsua tests run: | $env:OPENSSL_DIR = Get-Content .\openssl_dir.txt + $env:SIPP_DIR = Get-Content .\sipp_dir.txt $env:PATH+=";$env:OPENSSL_DIR\bin" - cd tests/pjsua; python runall.py - cd ../../pjsip/bin; ./pjsip-test-i386-Win32-vc14-Release.exe + $env:PATH+=";$env:SIPP_DIR" + cd tests/pjsua + echo python runall.py shell: powershell - build-windows-gnu-tls: + openssl-3: runs-on: windows-latest + name: OpenSSL / pjnath + steps: + - uses: actions/checkout@master + - name: get openssl + run: Invoke-WebRequest -Uri "https://github.com/pjsip/third_party_libs/raw/main/openssl-1.1.1s-win.zip" -OutFile ".\openssl.zip" + shell: powershell + - name: expand openssl + run: | + Expand-Archive -LiteralPath .\openssl.zip -DestinationPath .; + cd openssl_build + Add-Content ..\openssl_dir.txt $pwd.Path + shell: powershell + - name: check openssl folder + run: | + set /P OPENSSL_DIR= /dev/null || true $(RM) $(addprefix $(DESTDIR)$(libdir)/,$(notdir $(APP_LIBXX_FILES))) rmdir $(DESTDIR)$(libdir) 2> /dev/null || true + +infotarget: + @echo $(TARGET_NAME) diff --git a/pjlib-util/src/pjlib-util-test/main.c b/pjlib-util/src/pjlib-util-test/main.c index a5413f162c..7c4ec7a049 100644 --- a/pjlib-util/src/pjlib-util-test/main.c +++ b/pjlib-util/src/pjlib-util-test/main.c @@ -18,6 +18,8 @@ */ #include "test.h" #include +#include + #if defined(PJ_SUNOS) && PJ_SUNOS!=0 @@ -34,19 +36,19 @@ static void init_signals() #elif (PJ_LINUX || PJ_DARWINOS) && defined(PJ_HAS_EXECINFO_H) && PJ_HAS_EXECINFO_H != 0 -#include +#include #include -#include -#include -#include +#include +#include +#include static void print_stack(int sig) { - void *array[16]; - size_t size; - - size = backtrace(array, 16); - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); + void *array[16]; + size_t size; + + size = backtrace(array, 16); + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, STDERR_FILENO); exit(1); } @@ -64,6 +66,22 @@ static void init_signals(void) #define boost() +static void usage() +{ + puts("Usage:"); + puts(" pjlib-util-test [OPTION] [test_to_run] [..]"); + puts(""); + puts("where OPTIONS:"); + puts(""); + puts(" -h, --help Show this help screen"); + + ut_usage(); + + puts(" -i Ask ENTER before quitting"); + puts(" -n Do not trap signals"); +} + + int main(int argc, char *argv[]) { int rc; @@ -72,22 +90,25 @@ int main(int argc, char *argv[]) boost(); - while (argc > 1) { - char *arg = argv[--argc]; - - if (*arg=='-' && *(arg+1)=='i') { - interractive = 1; - - } else if (*arg=='-' && *(arg+1)=='n') { - no_trap = 1; - } + if (pj_argparse_get_bool(&argc, argv, "-h") || + pj_argparse_get_bool(&argc, argv, "--help")) + { + usage(); + return 0; } + ut_app_init0(&test_app.ut_app); + + interractive = pj_argparse_get_bool(&argc, argv, "-i"); + no_trap = pj_argparse_get_bool(&argc, argv, "-n"); + if (ut_parse_args(&test_app.ut_app, &argc, argv)) + return 1; + if (!no_trap) { init_signals(); } - rc = test_main(); + rc = test_main(argc, argv); if (interractive) { char s[10]; diff --git a/pjlib-util/src/pjlib-util-test/resolver_test.c b/pjlib-util/src/pjlib-util-test/resolver_test.c index 40a6ad3260..2d23906ea1 100644 --- a/pjlib-util/src/pjlib-util-test/resolver_test.c +++ b/pjlib-util/src/pjlib-util-test/resolver_test.c @@ -21,7 +21,7 @@ #include "test.h" -#define THIS_FILE "srv_resolver_test.c" +#define THIS_FILE "resolver_test.c" //////////////////////////////////////////////////////////////////////////// /* @@ -61,6 +61,7 @@ static struct server_t } g_server[2]; static pj_pool_t *pool; +static pj_mutex_t *mutex; static pj_dns_resolver *resolver; static pj_bool_t thread_quit; static pj_timer_heap_t *timer_heap; @@ -81,6 +82,16 @@ struct label_tab } a[MAX_LABEL]; }; +static void lock() +{ + pj_mutex_lock(mutex); +} + +static void unlock() +{ + pj_mutex_unlock(mutex); +} + static void write16(pj_uint8_t *p, pj_uint16_t val) { p[0] = (pj_uint8_t)(val >> 8); @@ -170,7 +181,7 @@ static int print_rr(pj_uint8_t *pkt, int size, pj_uint8_t *pos, if (size < 8) return -1; - pj_assert(rr->dnsclass == 1); + PJ_TEST_EQ(rr->dnsclass, 1, NULL, return -1); write16(p+0, (pj_uint16_t)rr->type); /* type */ write16(p+2, (pj_uint16_t)rr->dnsclass); /* class */ @@ -369,14 +380,17 @@ static int server_thread(void *p) } PJ_LOG(5,(THIS_FILE, "Server %ld processing packet", srv - &g_server[0])); - srv->pkt_count++; + lock(); rc = pj_dns_parse_packet(pool, pkt, (unsigned)pkt_len, &req); + unlock(); if (rc != PJ_SUCCESS) { app_perror("server error parsing packet", rc); continue; } + srv->pkt_count++; + /* Verify packet */ if (req->hdr.qdcount != 1) { PJ_LOG(5,(THIS_FILE, "server receive multiple queries in a packet")); @@ -418,7 +432,7 @@ static int poll_worker_thread(void *p) PJ_UNUSED_ARG(p); while (!thread_quit) { - pj_time_val delay = {0, 100}; + pj_time_val delay = {0, 10}; pj_timer_heap_poll(timer_heap, NULL); pj_ioqueue_poll(ioqueue, &delay); } @@ -430,7 +444,6 @@ static void destroy(void); static int init(pj_bool_t use_ipv6) { - pj_status_t status; pj_str_t nameservers[2]; pj_uint16_t ports[2]; int i; @@ -442,60 +455,57 @@ static int init(pj_bool_t use_ipv6) nameservers[0] = pj_str("127.0.0.1"); nameservers[1] = pj_str("127.0.0.1"); } - ports[0] = 5553; - ports[1] = 5554; - - g_server[0].port = ports[0]; - g_server[1].port = ports[1]; pool = pj_pool_create(mem, NULL, 2000, 2000, NULL); - status = pj_sem_create(pool, NULL, 0, 2, &sem); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_mutex_create_simple(pool, "resolver_test", &mutex), + NULL, return -3); + PJ_TEST_SUCCESS(pj_sem_create(pool, NULL, 0, 2, &sem), NULL, return -5); thread_quit = PJ_FALSE; for (i=0; i<2; ++i) { pj_sockaddr addr; + int namelen; - status = pj_sock_socket((use_ipv6? pj_AF_INET6() : pj_AF_INET()), - pj_SOCK_DGRAM(), 0, &g_server[i].sock); - if (status != PJ_SUCCESS) - return -10; + PJ_TEST_SUCCESS(pj_sock_socket( + (use_ipv6? pj_AF_INET6() : pj_AF_INET()), + pj_SOCK_DGRAM(), 0, &g_server[i].sock), + NULL, return -10); pj_sockaddr_init((use_ipv6? pj_AF_INET6() : pj_AF_INET()), - &addr, NULL, (pj_uint16_t)g_server[i].port); - - status = pj_sock_bind(g_server[i].sock, &addr, pj_sockaddr_get_len(&addr)); - if (status != PJ_SUCCESS) - return -20; - - status = pj_thread_create(pool, NULL, &server_thread, &g_server[i], - 0, 0, &g_server[i].thread); - if (status != PJ_SUCCESS) - return -30; + &addr, NULL, 0); + + PJ_TEST_SUCCESS(pj_sock_bind(g_server[i].sock, &addr, + pj_sockaddr_get_len(&addr)), + NULL, return -20); + + namelen = sizeof(addr); + PJ_TEST_SUCCESS(pj_sock_getsockname(g_server[i].sock, &addr, + &namelen), + NULL, return -25); + g_server[i].port = ports[i] = pj_sockaddr_get_port(&addr); + + PJ_TEST_SUCCESS(pj_thread_create(pool, NULL, &server_thread, + &g_server[i], + 0, 0, &g_server[i].thread), + NULL, return -30); } - status = pj_timer_heap_create(pool, 16, &timer_heap); - pj_assert(status == PJ_SUCCESS); - - status = pj_ioqueue_create(pool, 16, &ioqueue); - pj_assert(status == PJ_SUCCESS); - - status = pj_dns_resolver_create(mem, NULL, 0, timer_heap, ioqueue, &resolver); - if (status != PJ_SUCCESS) - return -40; + PJ_TEST_SUCCESS(pj_timer_heap_create(pool, 16, &timer_heap), NULL, return -31); + PJ_TEST_SUCCESS(pj_ioqueue_create(pool, 16, &ioqueue), NULL, return -32); + PJ_TEST_SUCCESS(pj_dns_resolver_create(mem, NULL, 0, timer_heap, ioqueue, &resolver), + NULL, return -40); pj_dns_resolver_get_settings(resolver, &set); - set.good_ns_ttl = 20; - set.bad_ns_ttl = 20; + set.good_ns_ttl = 10; + set.bad_ns_ttl = 10; pj_dns_resolver_set_settings(resolver, &set); - status = pj_dns_resolver_set_ns(resolver, 2, nameservers, ports); - pj_assert(status == PJ_SUCCESS); - - status = pj_thread_create(pool, NULL, &poll_worker_thread, NULL, 0, 0, &poll_thread); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_dns_resolver_set_ns(resolver, 2, nameservers, ports), + NULL, return -41); + PJ_TEST_SUCCESS(pj_thread_create(pool, NULL, &poll_worker_thread, NULL, 0, 0, &poll_thread), + NULL, return -42); return 0; } @@ -503,6 +513,9 @@ static int init(pj_bool_t use_ipv6) static void destroy(void) { + /* note: need to set global vars back to zero since test can be + * repeated for IPv6 + */ int i; thread_quit = PJ_TRUE; @@ -513,13 +526,24 @@ static void destroy(void) } pj_thread_join(poll_thread); + poll_thread = NULL; + thread_quit = PJ_FALSE; pj_dns_resolver_destroy(resolver, PJ_FALSE); + resolver = NULL; pj_ioqueue_destroy(ioqueue); + ioqueue = NULL; pj_timer_heap_destroy(timer_heap); + timer_heap = NULL; pj_sem_destroy(sem); + sem = NULL; + pj_mutex_destroy(mutex); + mutex = NULL; pj_pool_release(pool); + pool = NULL; + + pj_bzero(g_server, sizeof(g_server)); } @@ -529,7 +553,6 @@ static int a_parser_test(void) { pj_dns_parsed_packet pkt; pj_dns_a_record rec; - pj_status_t rc; PJ_LOG(3,(THIS_FILE, " DNS A record parser tests")); @@ -570,12 +593,11 @@ static int a_parser_test(void) pkt.ans[2].rdata.a.ip_addr.s_addr = 0x0203; - rc = pj_dns_parse_a_response(&pkt, &rec); - pj_assert(rc == PJ_SUCCESS); - pj_assert(pj_strcmp2(&rec.name, "ahost")==0); - pj_assert(rec.alias.slen == 0); - pj_assert(rec.addr_count == 1); - pj_assert(rec.addr[0].s_addr == 0x01020304); + PJ_TEST_SUCCESS(pj_dns_parse_a_response(&pkt, &rec), NULL, return -100) + PJ_TEST_EQ(pj_strcmp2(&rec.name, "ahost"), 0, NULL, return -110); + PJ_TEST_EQ(rec.alias.slen, 0, NULL, return -112); + PJ_TEST_EQ(rec.addr_count, 1, NULL, return -114); + PJ_TEST_EQ(rec.addr[0].s_addr, 0x01020304, NULL, return -116); /* Answer with the target corresponds to a CNAME entry, but not * as the first record, and with additions of some CNAME and A @@ -617,12 +639,11 @@ static int a_parser_test(void) pkt.ans[3].ttl = 1; pkt.ans[3].rdata.a.ip_addr.s_addr = 0x03030303; - rc = pj_dns_parse_a_response(&pkt, &rec); - pj_assert(rc == PJ_SUCCESS); - pj_assert(pj_strcmp2(&rec.name, "ahost")==0); - pj_assert(pj_strcmp2(&rec.alias, "ahostalias")==0); - pj_assert(rec.addr_count == 1); - pj_assert(rec.addr[0].s_addr == 0x02020202); + PJ_TEST_SUCCESS(pj_dns_parse_a_response(&pkt, &rec), NULL, return -120); + PJ_TEST_EQ(pj_strcmp2(&rec.name, "ahost"), 0, NULL, return -122); + PJ_TEST_EQ(pj_strcmp2(&rec.alias, "ahostalias"), 0, NULL, return -124); + PJ_TEST_EQ(rec.addr_count, 1, NULL, return -126); + PJ_TEST_EQ(rec.addr[0].s_addr, 0x02020202, NULL, return -128); /* * No query section. @@ -631,8 +652,8 @@ static int a_parser_test(void) pkt.hdr.qdcount = 0; pkt.hdr.anscount = 0; - rc = pj_dns_parse_a_response(&pkt, &rec); - pj_assert(rc == PJLIB_UTIL_EDNSINANSWER); + PJ_TEST_EQ(pj_dns_parse_a_response(&pkt, &rec), PJLIB_UTIL_EDNSINANSWER, + NULL, return -130); /* * No answer section. @@ -645,8 +666,8 @@ static int a_parser_test(void) pkt.q[0].name = pj_str("ahost"); pkt.hdr.anscount = 0; - rc = pj_dns_parse_a_response(&pkt, &rec); - pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC); + PJ_TEST_EQ(pj_dns_parse_a_response(&pkt, &rec), PJLIB_UTIL_EDNSNOANSWERREC, + NULL, return -140); /* * Answer doesn't match query. @@ -666,8 +687,8 @@ static int a_parser_test(void) pkt.ans[0].ttl = 1; pkt.ans[0].rdata.a.ip_addr.s_addr = 0x02020202; - rc = pj_dns_parse_a_response(&pkt, &rec); - pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC); + PJ_TEST_EQ(pj_dns_parse_a_response(&pkt, &rec), PJLIB_UTIL_EDNSNOANSWERREC, + NULL, return -150); /* @@ -688,8 +709,8 @@ static int a_parser_test(void) pkt.ans[0].ttl = 1; pkt.ans[0].rdata.cname.name = pj_str("ahostalias"); - rc = pj_dns_parse_a_response(&pkt, &rec); - pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC); + PJ_TEST_EQ(pj_dns_parse_a_response(&pkt, &rec), PJLIB_UTIL_EDNSNOANSWERREC, + NULL, return -160); /* @@ -717,9 +738,8 @@ static int a_parser_test(void) pkt.ans[1].ttl = 1; pkt.ans[1].rdata.a.ip_addr.s_addr = 0x01020304; - rc = pj_dns_parse_a_response(&pkt, &rec); - pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC); - PJ_UNUSED_ARG(rc); + PJ_TEST_EQ(pj_dns_parse_a_response(&pkt, &rec), PJLIB_UTIL_EDNSNOANSWERREC, + NULL, return -170); return 0; } @@ -731,7 +751,6 @@ static int addr_parser_test(void) { pj_dns_parsed_packet pkt; pj_dns_addr_record rec; - pj_status_t rc; PJ_LOG(3,(THIS_FILE, " DNS A/AAAA record parser tests")); @@ -779,13 +798,14 @@ static int addr_parser_test(void) s6_addr32(pkt.ans[3].rdata.aaaa.ip_addr, 0) = 0x01020304; - rc = pj_dns_parse_addr_response(&pkt, &rec); - pj_assert(rc == PJ_SUCCESS); - pj_assert(pj_strcmp2(&rec.name, "ahost")==0); - pj_assert(rec.alias.slen == 0); - pj_assert(rec.addr_count == 2); - pj_assert(rec.addr[0].af==pj_AF_INET() && rec.addr[0].ip.v4.s_addr == 0x01020304); - pj_assert(rec.addr[1].af==pj_AF_INET6() && s6_addr32(rec.addr[1].ip.v6, 0) == 0x01020304); + PJ_TEST_SUCCESS(pj_dns_parse_addr_response(&pkt, &rec), NULL, return -200); + PJ_TEST_EQ(pj_strcmp2(&rec.name, "ahost"), 0, NULL, return -210); + PJ_TEST_EQ(rec.alias.slen, 0, NULL, return -212); + PJ_TEST_EQ(rec.addr_count, 2, NULL, return -214); + PJ_TEST_EQ(rec.addr[0].af, pj_AF_INET(), NULL, return -220); + PJ_TEST_EQ(rec.addr[0].ip.v4.s_addr, 0x01020304, NULL, return -222); + PJ_TEST_EQ(rec.addr[1].af, pj_AF_INET6(), NULL, return -230); + PJ_TEST_EQ(s6_addr32(rec.addr[1].ip.v6, 0), 0x01020304, NULL, return -232); /* Answer with the target corresponds to a CNAME entry, but not * as the first record, and with additions of some CNAME and A @@ -827,12 +847,11 @@ static int addr_parser_test(void) pkt.ans[3].ttl = 1; pkt.ans[3].rdata.a.ip_addr.s_addr = 0x03030303; - rc = pj_dns_parse_addr_response(&pkt, &rec); - pj_assert(rc == PJ_SUCCESS); - pj_assert(pj_strcmp2(&rec.name, "ahost")==0); - pj_assert(pj_strcmp2(&rec.alias, "ahostalias")==0); - pj_assert(rec.addr_count == 1); - pj_assert(rec.addr[0].ip.v4.s_addr == 0x02020202); + PJ_TEST_SUCCESS(pj_dns_parse_addr_response(&pkt, &rec), NULL, return -240); + PJ_TEST_EQ(pj_strcmp2(&rec.name, "ahost"), 0, NULL, return -242); + PJ_TEST_EQ(pj_strcmp2(&rec.alias, "ahostalias"), 0, NULL, return -244); + PJ_TEST_EQ(rec.addr_count, 1, NULL, return -246); + PJ_TEST_EQ(rec.addr[0].ip.v4.s_addr, 0x02020202, NULL, return -248); /* * No query section. @@ -841,8 +860,8 @@ static int addr_parser_test(void) pkt.hdr.qdcount = 0; pkt.hdr.anscount = 0; - rc = pj_dns_parse_addr_response(&pkt, &rec); - pj_assert(rc == PJLIB_UTIL_EDNSINANSWER); + PJ_TEST_EQ(pj_dns_parse_addr_response(&pkt, &rec), + PJLIB_UTIL_EDNSINANSWER, NULL, return -245); /* * No answer section. @@ -855,8 +874,8 @@ static int addr_parser_test(void) pkt.q[0].name = pj_str("ahost"); pkt.hdr.anscount = 0; - rc = pj_dns_parse_addr_response(&pkt, &rec); - pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC); + PJ_TEST_EQ(pj_dns_parse_addr_response(&pkt, &rec), + PJLIB_UTIL_EDNSNOANSWERREC, NULL, return -250); /* * Answer doesn't match query. @@ -876,8 +895,8 @@ static int addr_parser_test(void) pkt.ans[0].ttl = 1; pkt.ans[0].rdata.a.ip_addr.s_addr = 0x02020202; - rc = pj_dns_parse_addr_response(&pkt, &rec); - pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC); + PJ_TEST_EQ(pj_dns_parse_addr_response(&pkt, &rec), + PJLIB_UTIL_EDNSNOANSWERREC, NULL, return -260); /* @@ -898,8 +917,8 @@ static int addr_parser_test(void) pkt.ans[0].ttl = 1; pkt.ans[0].rdata.cname.name = pj_str("ahostalias"); - rc = pj_dns_parse_addr_response(&pkt, &rec); - pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC); + PJ_TEST_EQ(pj_dns_parse_addr_response(&pkt, &rec), + PJLIB_UTIL_EDNSNOANSWERREC, NULL, return -270); /* @@ -927,9 +946,8 @@ static int addr_parser_test(void) pkt.ans[1].ttl = 1; pkt.ans[1].rdata.a.ip_addr.s_addr = 0x01020304; - rc = pj_dns_parse_addr_response(&pkt, &rec); - pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC); - PJ_UNUSED_ARG(rc); + PJ_TEST_EQ(pj_dns_parse_addr_response(&pkt, &rec), + PJLIB_UTIL_EDNSNOANSWERREC, NULL, return -280); return 0; } @@ -960,7 +978,6 @@ static int simple_test(void) { pj_str_t name = pj_str("helloworld"); pj_dns_parsed_packet *r; - pj_status_t status; PJ_LOG(3,(THIS_FILE, " simple successful test")); @@ -995,18 +1012,18 @@ static int simple_test(void) r->ans[0].name = name; r->ans[0].rdata.a.ip_addr.s_addr = IP_ADDR0; - status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0, - &dns_callback, NULL, NULL); - if (status != PJ_SUCCESS) - return -1000; + PJ_TEST_SUCCESS(pj_dns_resolver_start_query( + resolver, &name, PJ_DNS_TYPE_A, 0, + &dns_callback, NULL, NULL), + NULL, return -300); pj_sem_wait(sem); - pj_thread_sleep(1000); + pj_thread_sleep(set.qretr_delay * 1.2); /* Both servers must get packet */ - pj_assert(g_server[0].pkt_count == 1); - pj_assert(g_server[1].pkt_count == 1); + PJ_TEST_EQ(g_server[0].pkt_count, 1, NULL, return -310); + PJ_TEST_EQ(g_server[1].pkt_count, 1, NULL, return -320); return 0; } @@ -1024,8 +1041,8 @@ static void dns_callback_1b(void *user_data, pj_sem_post(sem); - PJ_ASSERT_ON_FAIL(status==PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_RCODE_NXDOMAIN), - return); + PJ_TEST_EQ(status, PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_RCODE_NXDOMAIN), + NULL, return); } @@ -1035,7 +1052,7 @@ static void dns_callback_1b(void *user_data, static int dns_test(void) { pj_str_t name = pj_str("name00"); - pj_status_t status; + enum { D = 2 }; PJ_LOG(3,(THIS_FILE, " simple error response test")); @@ -1045,10 +1062,10 @@ static int dns_test(void) g_server[0].action = PJ_DNS_RCODE_NXDOMAIN; g_server[1].action = PJ_DNS_RCODE_NXDOMAIN; - status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0, - &dns_callback_1b, NULL, NULL); - if (status != PJ_SUCCESS) - return -1000; + PJ_TEST_SUCCESS(pj_dns_resolver_start_query( + resolver, &name, PJ_DNS_TYPE_A, 0, + &dns_callback_1b, NULL, NULL), + NULL, return -400); pj_sem_wait(sem); pj_thread_sleep(1000); @@ -1056,12 +1073,13 @@ static int dns_test(void) /* Now only one of the servers should get packet, since both servers are * in STATE_ACTIVE state */ - pj_assert(g_server[0].pkt_count + g_server[1].pkt_count == 1); + PJ_TEST_EQ(g_server[0].pkt_count + g_server[1].pkt_count, 1, + NULL, return -410); /* Wait to allow active period to complete and get into probing state */ PJ_LOG(3,(THIS_FILE, " waiting for active NS to expire (%d sec)", set.good_ns_ttl)); - pj_thread_sleep(set.good_ns_ttl * 1000); + pj_thread_sleep((set.good_ns_ttl+D) * 1000); /* * Fail-over test @@ -1074,15 +1092,16 @@ static int dns_test(void) g_server[1].pkt_count = 0; name = pj_str("name01"); - status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0, - &dns_callback_1b, NULL, NULL); - if (status != PJ_SUCCESS) - return -1000; + PJ_TEST_SUCCESS(pj_dns_resolver_start_query( + resolver, &name, PJ_DNS_TYPE_A, 0, + &dns_callback_1b, NULL, NULL), + NULL, return -420); pj_sem_wait(sem); /* Both servers must get packet as both are in probing state */ - pj_assert(g_server[0].pkt_count >= 1 && g_server[1].pkt_count == 1); + PJ_TEST_GTE(g_server[0].pkt_count, 1, NULL, return -430); + PJ_TEST_EQ(g_server[1].pkt_count, 1, NULL, return -435); /* * Check that both servers still receive requests, since they are @@ -1096,22 +1115,23 @@ static int dns_test(void) g_server[1].pkt_count = 0; name = pj_str("name02"); - status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0, - &dns_callback_1b, NULL, NULL); - if (status != PJ_SUCCESS) - return -1000; + PJ_TEST_SUCCESS(pj_dns_resolver_start_query( + resolver, &name, PJ_DNS_TYPE_A, 0, + &dns_callback_1b, NULL, NULL), + NULL, return -440); pj_sem_wait(sem); pj_thread_sleep(1000); /* Both servers must get packet as both are in probing & active state */ - pj_assert(g_server[0].pkt_count >= 1 && g_server[1].pkt_count == 1); + PJ_TEST_GTE(g_server[0].pkt_count, 1, NULL, return -450); + PJ_TEST_EQ(g_server[1].pkt_count, 1, NULL, return -454); /* Wait to allow probing period to complete, server 0 will be in bad state */ PJ_LOG(3,(THIS_FILE, " waiting for probing state to end (%d sec)", set.qretr_delay * (set.qretr_count+2) / 1000)); - pj_thread_sleep(set.qretr_delay * (set.qretr_count + 2)); + pj_thread_sleep(1000 + set.qretr_delay * (set.qretr_count + 2)); /* @@ -1125,22 +1145,22 @@ static int dns_test(void) g_server[1].pkt_count = 0; name = pj_str("name03"); - status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0, - &dns_callback_1b, NULL, NULL); - if (status != PJ_SUCCESS) - return -1000; + PJ_TEST_SUCCESS(pj_dns_resolver_start_query( + resolver, &name, PJ_DNS_TYPE_A, 0, + &dns_callback_1b, NULL, NULL), + NULL, return -460); pj_sem_wait(sem); pj_thread_sleep(1000); /* Only server 1 get the request */ - pj_assert(g_server[0].pkt_count == 0); - pj_assert(g_server[1].pkt_count == 1); + PJ_TEST_EQ(g_server[0].pkt_count, 0, NULL, return -470); + PJ_TEST_EQ(g_server[1].pkt_count, 1, NULL, return -474); /* Wait to allow active & bad period to complete, both will be in probing state */ PJ_LOG(3,(THIS_FILE, " waiting for active NS to expire (%d sec)", set.good_ns_ttl)); - pj_thread_sleep(set.good_ns_ttl * 1000); + pj_thread_sleep((set.good_ns_ttl+D) * 1000); /* * Now fail server 1 to switch to server 0 @@ -1152,10 +1172,10 @@ static int dns_test(void) g_server[1].pkt_count = 0; name = pj_str("name04"); - status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0, - &dns_callback_1b, NULL, NULL); - if (status != PJ_SUCCESS) - return -1000; + PJ_TEST_SUCCESS(pj_dns_resolver_start_query( + resolver, &name, PJ_DNS_TYPE_A, 0, + &dns_callback_1b, NULL, NULL), + NULL, return -480); pj_sem_wait(sem); @@ -1175,18 +1195,17 @@ static int dns_test(void) g_server[1].pkt_count = 0; name = pj_str("name05"); - status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0, - &dns_callback_1b, NULL, NULL); - if (status != PJ_SUCCESS) - return -1000; + PJ_TEST_SUCCESS(pj_dns_resolver_start_query( + resolver, &name, PJ_DNS_TYPE_A, 0, + &dns_callback_1b, NULL, NULL), + NULL, return -484); pj_sem_wait(sem); pj_thread_sleep(1000); /* Only good NS should get request */ - pj_assert(g_server[0].pkt_count == 1); - pj_assert(g_server[1].pkt_count == 0); - + PJ_TEST_EQ(g_server[0].pkt_count, 1, NULL, return -486); + PJ_TEST_EQ(g_server[1].pkt_count, 0, NULL, return -488); return 0; } @@ -1203,6 +1222,7 @@ static void action1_1(const pj_dns_parsed_packet *pkt, pj_dns_parsed_packet *res; char *target = "sip.somedomain.com"; + lock(); res = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_packet); if (res->q == NULL) { @@ -1212,6 +1232,7 @@ static void action1_1(const pj_dns_parsed_packet *pkt, res->ans = (pj_dns_parsed_rr*) pj_pool_calloc(pool, 4, sizeof(pj_dns_parsed_rr)); } + unlock(); res->hdr.qdcount = 1; res->q[0].type = pkt->q[0].type; @@ -1371,7 +1392,6 @@ static void srv_cb_1d(void *user_data, static int srv_resolver_test(void) { - pj_status_t status; pj_str_t domain = pj_str("somedomain.com"); pj_str_t res_name = pj_str("_sip._udp."); @@ -1388,15 +1408,16 @@ static int srv_resolver_test(void) g_server[0].pkt_count = 0; g_server[1].pkt_count = 0; - status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver, PJ_TRUE, - NULL, &srv_cb_1, NULL); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, 5061, pool, resolver, PJ_TRUE, + NULL, &srv_cb_1, NULL), + NULL, return -500); pj_sem_wait(sem); /* Because of previous tests, only NS 1 should get the request */ - pj_assert(g_server[0].pkt_count == 2); /* 2 because of SRV and A resolution */ - pj_assert(g_server[1].pkt_count == 0); + PJ_TEST_EQ(g_server[0].pkt_count, 2, NULL, return -510); /* 2 because of SRV and A resolution */ + PJ_TEST_EQ(g_server[1].pkt_count, 0, NULL, return -512); /* Wait until cache expires */ @@ -1415,10 +1436,11 @@ static int srv_resolver_test(void) g_server[0].pkt_count = 0; g_server[1].pkt_count = 0; - status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver, - PJ_DNS_SRV_RESOLVE_AAAA, - NULL, &srv_cb_1c, NULL); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, 5061, pool, resolver, + PJ_DNS_SRV_RESOLVE_AAAA, + NULL, &srv_cb_1c, NULL), + NULL, return -520); pj_sem_wait(sem); pj_thread_sleep(1000); @@ -1434,10 +1456,11 @@ static int srv_resolver_test(void) g_server[0].pkt_count = 0; g_server[1].pkt_count = 0; - status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver, - PJ_DNS_SRV_RESOLVE_AAAA_ONLY, - NULL, &srv_cb_1d, NULL); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, 5061, pool, resolver, + PJ_DNS_SRV_RESOLVE_AAAA_ONLY, + NULL, &srv_cb_1d, NULL), + NULL, return -530); pj_sem_wait(sem); pj_thread_sleep(1000); @@ -1448,21 +1471,23 @@ static int srv_resolver_test(void) g_server[0].pkt_count = 0; g_server[1].pkt_count = 0; - status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver, PJ_TRUE, - NULL, &srv_cb_1, NULL); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, 5061, pool, resolver, PJ_TRUE, + NULL, &srv_cb_1, NULL), + NULL, return -540); - status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver, PJ_TRUE, - NULL, &srv_cb_1, NULL); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, 5061, pool, resolver, PJ_TRUE, + NULL, &srv_cb_1, NULL), + NULL, return -550); pj_sem_wait(sem); pj_sem_wait(sem); /* Only server one should get a query */ - pj_assert(g_server[0].pkt_count == 2); /* 2 because of SRV and A resolution */ - pj_assert(g_server[1].pkt_count == 0); + PJ_TEST_EQ(g_server[0].pkt_count, 2, NULL, return -554); /* 2 because of SRV and A resolution */ + PJ_TEST_EQ(g_server[1].pkt_count, 0, NULL, return -556); /* Since TTL is one, subsequent queries should fail */ PJ_LOG(3,(THIS_FILE, " srv_resolve(): cache expires scenario")); @@ -1472,14 +1497,15 @@ static int srv_resolver_test(void) g_server[0].action = PJ_DNS_RCODE_NXDOMAIN; g_server[1].action = PJ_DNS_RCODE_NXDOMAIN; - status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver, PJ_TRUE, - NULL, &srv_cb_1b, NULL); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, 5061, pool, resolver, PJ_TRUE, + NULL, &srv_cb_1b, NULL), + NULL, return -560); pj_sem_wait(sem); pj_thread_sleep(1000); - return status; + return 0; } @@ -1494,11 +1520,13 @@ static void action2_1(const pj_dns_parsed_packet *pkt, { pj_dns_parsed_packet *res; + lock(); res = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_packet); res->q = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_query); res->ans = (pj_dns_parsed_rr*) pj_pool_calloc(pool, 4, sizeof(pj_dns_parsed_rr)); + unlock(); res->hdr.qdcount = 1; res->q[0].type = pkt->q[0].type; @@ -1642,7 +1670,6 @@ static void srv_cb_2b(void *user_data, static int srv_resolver_fallback_test(void) { - pj_status_t status; pj_str_t domain = pj_str(TARGET); pj_str_t res_name = pj_str("_sip._udp."); int cb_err = 0; @@ -1655,43 +1682,31 @@ static int srv_resolver_fallback_test(void) g_server[1].action = ACTION_CB; g_server[1].action_cb = &action2_1; - status = pj_dns_srv_resolve(&domain, &res_name, PORT2, pool, resolver, PJ_TRUE, - &cb_err, &srv_cb_2, NULL); - if (status != PJ_SUCCESS) { - app_perror(" srv_resolve error", status); - return -10; - } + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, PORT2, pool, resolver, PJ_TRUE, + &cb_err, &srv_cb_2, NULL), + NULL, return -600); pj_sem_wait(sem); - if (cb_err != 0) { - PJ_LOG(3,("test", " srv_resolve cb error, code=%d", cb_err)); - return -20; - } + PJ_TEST_EQ(cb_err, 0, "srv_resolve cb error", return -605); /* Subsequent query should just get the response from the cache */ PJ_LOG(3,(THIS_FILE, " srv_resolve(): cache test")); g_server[0].pkt_count = 0; g_server[1].pkt_count = 0; - status = pj_dns_srv_resolve(&domain, &res_name, PORT2, pool, resolver, PJ_TRUE, - &cb_err, &srv_cb_2, NULL); - if (status != PJ_SUCCESS) { - app_perror(" srv_resolve error", status); - return -30; - } + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, PORT2, pool, resolver, PJ_TRUE, + &cb_err, &srv_cb_2, NULL), + NULL, return -610); pj_sem_wait(sem); - if (cb_err != 0) { - PJ_LOG(3,("test", " srv_resolve cb error, code=%d", cb_err)); - return -40; - } + PJ_TEST_EQ(cb_err, 0, "srv_resolve cb error", return -615); - if (g_server[0].pkt_count != 0 || g_server[1].pkt_count != 0) { - PJ_LOG(3,("test", " srv_resolve() not from cache")); - return -50; - } + PJ_TEST_EQ(g_server[0].pkt_count, 0, "must be from cache", return -620); + PJ_TEST_EQ(g_server[1].pkt_count, 0, "must be from cache", return -625); /* Clear cache */ pj_thread_sleep(1000); @@ -1704,20 +1719,15 @@ static int srv_resolver_fallback_test(void) g_server[1].action = ACTION_CB; g_server[1].action_cb = &action2_1; - status = pj_dns_srv_resolve(&domain, &res_name, PORT2, pool, resolver, - PJ_DNS_SRV_FALLBACK_A | PJ_DNS_SRV_FALLBACK_AAAA, - &cb_err, &srv_cb_2a, NULL); - if (status != PJ_SUCCESS) { - app_perror(" srv_resolve error", status); - return -60; - } + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, PORT2, pool, resolver, + PJ_DNS_SRV_FALLBACK_A | PJ_DNS_SRV_FALLBACK_AAAA, + &cb_err, &srv_cb_2a, NULL), + NULL, return -630); pj_sem_wait(sem); - if (cb_err != 0) { - PJ_LOG(3,("test", " srv_resolve cb error, code=%d", cb_err)); - return -70; - } + PJ_TEST_EQ(cb_err, 0, "srv_resolve cb error", return -635); /* Clear cache */ pj_thread_sleep(1000); @@ -1730,20 +1740,15 @@ static int srv_resolver_fallback_test(void) g_server[1].action = ACTION_CB; g_server[1].action_cb = &action2_1; - status = pj_dns_srv_resolve(&domain, &res_name, PORT2, pool, resolver, - PJ_DNS_SRV_FALLBACK_AAAA, - &cb_err, &srv_cb_2b, NULL); - if (status != PJ_SUCCESS) { - app_perror(" srv_resolve error", status); - return -80; - } + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, PORT2, pool, resolver, + PJ_DNS_SRV_FALLBACK_AAAA, + &cb_err, &srv_cb_2b, NULL), + NULL, return -640); pj_sem_wait(sem); - if (cb_err != 0) { - PJ_LOG(3,("test", " srv_resolve cb error, code=%d", cb_err)); - return -90; - } + PJ_TEST_EQ(cb_err, 0, "srv_resolve cb error", return -645); /* Clear cache */ pj_thread_sleep(1000); @@ -1766,11 +1771,13 @@ static void action3_1(const pj_dns_parsed_packet *pkt, pj_dns_parsed_packet *res; unsigned i; + lock(); res = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_packet); if (res->q == NULL) { res->q = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_query); } + unlock(); res->hdr.qdcount = 1; res->q[0].type = pkt->q[0].type; @@ -1782,8 +1789,10 @@ static void action3_1(const pj_dns_parsed_packet *pkt, pj_assert(pj_strcmp2(&pkt->q[0].name, "_sip._udp." DOMAIN3)==0); res->hdr.anscount = SRV_COUNT3; + lock(); res->ans = (pj_dns_parsed_rr*) pj_pool_calloc(pool, SRV_COUNT3, sizeof(pj_dns_parsed_rr)); + unlock(); for (i=0; ians[i].rdata.srv.weight = 2; res->ans[i].rdata.srv.port = (pj_uint16_t)(PORT3+i); + lock(); target = (char*)pj_pool_alloc(pool, 16); + unlock(); pj_ansi_snprintf(target, 16, "sip%02d." DOMAIN3, i); res->ans[i].rdata.srv.target = pj_str(target); } @@ -1806,8 +1817,10 @@ static void action3_1(const pj_dns_parsed_packet *pkt, //pj_assert(pj_strcmp2(&res->q[0].name, "sip." DOMAIN3)==0); res->hdr.anscount = A_COUNT3; + lock(); res->ans = (pj_dns_parsed_rr*) pj_pool_calloc(pool, A_COUNT3, sizeof(pj_dns_parsed_rr)); + unlock(); for (i=0; ians[i].type = PJ_DNS_TYPE_A; @@ -1856,7 +1869,6 @@ static void srv_cb_3(void *user_data, static int srv_resolver_many_test(void) { - pj_status_t status; pj_str_t domain = pj_str(DOMAIN3); pj_str_t res_name = pj_str("_sip._udp."); int cb_err = 0; @@ -1872,19 +1884,14 @@ static int srv_resolver_many_test(void) g_server[0].pkt_count = 0; g_server[1].pkt_count = 0; - status = pj_dns_srv_resolve(&domain, &res_name, 1, pool, resolver, PJ_TRUE, - &cb_err, &srv_cb_3, NULL); - if (status != PJ_SUCCESS) { - app_perror(" srv_resolve error", status); - return -10; - } + PJ_TEST_SUCCESS(pj_dns_srv_resolve( + &domain, &res_name, 1, pool, resolver, PJ_TRUE, + &cb_err, &srv_cb_3, NULL), + NULL, return -700); pj_sem_wait(sem); - if (cb_err != 0) { - PJ_LOG(3,("test", " srv_resolve cb error, code=%d", cb_err)); - return -20; - } + PJ_TEST_EQ(cb_err, 0, "srv_resolve cb error", return -710); return 0; } @@ -1897,34 +1904,42 @@ int resolver_test(void) { int rc; + PJ_LOG(3,(THIS_FILE, "init")); rc = init(PJ_FALSE); if (rc != 0) goto on_error; + PJ_LOG(3,(THIS_FILE, "a_parser_test")); rc = a_parser_test(); if (rc != 0) goto on_error; + PJ_LOG(3,(THIS_FILE, "addr_parser_test")); rc = addr_parser_test(); if (rc != 0) goto on_error; + PJ_LOG(3,(THIS_FILE, "simple_test")); rc = simple_test(); if (rc != 0) goto on_error; + PJ_LOG(3,(THIS_FILE, "dns_test")); rc = dns_test(); if (rc != 0) goto on_error; + PJ_LOG(3,(THIS_FILE, "srv_resolver_test")); rc = srv_resolver_test(); if (rc != 0) goto on_error; + PJ_LOG(3,(THIS_FILE, "srv_resolver_fallback_test")); rc = srv_resolver_fallback_test(); if (rc != 0) goto on_error; + PJ_LOG(3,(THIS_FILE, "srv_resolver_many_test")); rc = srv_resolver_many_test(); if (rc != 0) goto on_error; diff --git a/pjlib-util/src/pjlib-util-test/test.c b/pjlib-util/src/pjlib-util-test/test.c index f83e4f6946..cc519c949e 100644 --- a/pjlib-util/src/pjlib-util-test/test.c +++ b/pjlib-util/src/pjlib-util-test/test.c @@ -20,6 +20,14 @@ #include #include +#define THIS_FILE "test.c" + +pj_pool_factory *mem; +struct test_app_t test_app = { + .param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | + PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_INDENT, +}; + void app_perror(const char *msg, pj_status_t rc) { char errbuf[256]; @@ -30,80 +38,67 @@ void app_perror(const char *msg, pj_status_t rc) PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf)); } -#define DO_TEST(test) do { \ - PJ_LOG(3, ("test", "Running %s...", #test)); \ - rc = test; \ - PJ_LOG(3, ("test", \ - "%s(%d)", \ - (char*)(rc ? "..ERROR" : "..success"), rc)); \ - if (rc!=0) goto on_return; \ - } while (0) - - -pj_pool_factory *mem; - -int param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | - PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_INDENT; - -static int test_inner(void) +static int test_inner(int argc, char *argv[]) { pj_caching_pool caching_pool; - int rc = 0; mem = &caching_pool.factory; pj_log_set_level(3); - pj_log_set_decor(param_log_decor); - - rc = pj_init(); - if (rc != 0) { - app_perror("pj_init() error!!", rc); - return rc; - } - - rc = pjlib_util_init(); - pj_assert(rc == 0); + pj_log_set_decor(test_app.param_log_decor); - pj_dump_config(); + PJ_TEST_SUCCESS(pj_init(), NULL, { return 1; }) + PJ_TEST_SUCCESS(pjlib_util_init(), NULL, { return 2; }); pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 ); + + if (ut_app_init1(&test_app.ut_app, mem) != PJ_SUCCESS) + return 1; + + if (test_app.ut_app.prm_config) + pj_dump_config(); #if INCLUDE_XML_TEST - DO_TEST(xml_test()); + UT_ADD_TEST(&test_app.ut_app, xml_test, 0); #endif #if INCLUDE_JSON_TEST - DO_TEST(json_test()); + UT_ADD_TEST(&test_app.ut_app, json_test, 0); #endif #if INCLUDE_ENCRYPTION_TEST - DO_TEST(encryption_test()); + UT_ADD_TEST(&test_app.ut_app, encryption_test, 0); # if WITH_BENCHMARK - DO_TEST(encryption_benchmark()); + UT_ADD_TEST(&test_app.ut_app, encryption_benchmark, 0); # endif #endif #if INCLUDE_STUN_TEST - DO_TEST(stun_test()); + UT_ADD_TEST(&test_app.ut_app, stun_test, 0); #endif #if INCLUDE_RESOLVER_TEST - DO_TEST(resolver_test()); + UT_ADD_TEST(&test_app.ut_app, resolver_test, 0); #endif #if INCLUDE_HTTP_CLIENT_TEST - DO_TEST(http_client_test()); + UT_ADD_TEST(&test_app.ut_app, http_client_test, 0); #endif -on_return: - return rc; + if (ut_run_tests(&test_app.ut_app, "pjlib-util tests", argc, argv)) { + ut_app_destroy(&test_app.ut_app); + return 1; + } + + ut_app_destroy(&test_app.ut_app); + return 0; } -int test_main(void) +int test_main(int argc, char *argv[]) { PJ_USE_EXCEPTION; PJ_TRY { - return test_inner(); + return test_inner(argc, argv); } PJ_CATCH_ANY { int id = PJ_GET_EXCEPTION(); diff --git a/pjlib-util/src/pjlib-util-test/test.h b/pjlib-util/src/pjlib-util-test/test.h index 9469e1f74f..d076b1eca8 100644 --- a/pjlib-util/src/pjlib-util-test/test.h +++ b/pjlib-util/src/pjlib-util-test/test.h @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #if defined(PJ_EXCLUDE_BENCHMARK_TESTS) && (PJ_EXCLUDE_BENCHMARK_TESTS==1) # define WITH_BENCHMARK 0 @@ -36,10 +37,19 @@ extern int json_test(void); extern int encryption_test(); extern int encryption_benchmark(); extern int stun_test(); -extern int test_main(void); +extern int test_main(int argc, char *argv[]); extern int resolver_test(void); extern int http_client_test(); extern void app_perror(const char *title, pj_status_t rc); extern pj_pool_factory *mem; +#define UT_MAX_TESTS 20 +#include "../../../pjlib/src/pjlib-test/test_util.h" + +struct test_app_t +{ + ut_app_t ut_app; + int param_log_decor; +}; +extern struct test_app_t test_app; diff --git a/pjlib/build/pjlib.vcproj b/pjlib/build/pjlib.vcproj index 3fb4575bde..bc4e2b2c75 100644 --- a/pjlib/build/pjlib.vcproj +++ b/pjlib/build/pjlib.vcproj @@ -12638,15 +12638,15 @@ Filter="h;hpp;hxx;hm;inl" > Header Files + + Header Files + Header Files @@ -448,8 +451,5 @@ Header Files - - Header Files - \ No newline at end of file diff --git a/pjlib/include/pj/config_site_test.h b/pjlib/include/pj/config_site_test.h index 8fb2599d66..6d81842d8e 100644 --- a/pjlib/include/pj/config_site_test.h +++ b/pjlib/include/pj/config_site_test.h @@ -1,3 +1,8 @@ +/* Temp workaround for MacOS rwmutex deadlock */ +#if defined(PJ_DARWINOS) && PJ_DARWINOS + #define PJ_EMULATE_RWMUTEX 1 +#endif + #define PJMEDIA_SRTP_HAS_DTLS 1 #define PJMEDIA_HAS_WEBRTC_AEC 1 #define PJMEDIA_CODEC_L16_HAS_8KHZ_MONO 1 diff --git a/pjlib/src/pj/unittest.c b/pjlib/src/pj/unittest.c index 428051b520..3536db9949 100644 --- a/pjlib/src/pj/unittest.c +++ b/pjlib/src/pj/unittest.c @@ -114,14 +114,35 @@ PJ_DEF(void) pj_test_suite_add_case(pj_test_suite *suite, pj_test_case *tc) pj_list_push_back(&suite->tests, tc); } +/* Own PRNG using Linear congruential generator because rand() yields + * difference sequence on different machines even with the same seed. + */ +static pj_uint32_t rand_int(pj_uint32_t seed) +{ +#define M ((pj_uint32_t)(1<<31)) +#define A ((pj_uint32_t)1103515245) +#define C ((pj_uint32_t)12345) + + return (pj_uint32_t)(((A*seed) + C) % M); + +#undef M +#undef A +#undef C +} + /* Shuffle */ PJ_DEF(void) pj_test_suite_shuffle(pj_test_suite *suite, int seed) { pj_test_case src, *tc; + pj_uint32_t rand; unsigned total, movable; - if (seed >= 0) - pj_srand(seed); + /* although pj_rand() is not used here, still call pj_srand() to make + * RNG used by other parts of the program repeatable. This should be + * the only call to pj_srand() in the whole program. + */ + pj_srand(seed); + rand = (pj_uint32_t)((seed >= 0) ? seed : pj_rand()); /* Move tests to new list */ pj_list_init(&src); @@ -147,10 +168,11 @@ PJ_DEF(void) pj_test_suite_shuffle(pj_test_suite *suite, int seed) /* Shuffle non KEEP_LAST tests */ while (movable > 0) { - int step = pj_rand() % total; - if (step < 0) - continue; - + unsigned step; + + rand = rand_int(rand); + step = rand % total; + for (tc=src.next; step>0; tc=tc->next, --step) ; diff --git a/pjlib/src/pjlib-test/activesock.c b/pjlib/src/pjlib-test/activesock.c index 29f8117667..98ce4f9688 100644 --- a/pjlib/src/pjlib-test/activesock.c +++ b/pjlib/src/pjlib-test/activesock.c @@ -31,6 +31,7 @@ #define THIS_FILE "activesock.c" +#define ERR(r__) { ret=r__; goto on_return; } /******************************************************************* * Simple UDP echo server. @@ -142,7 +143,8 @@ static void udp_echo_srv_destroy(struct udp_echo_srv *srv) * UDP ping pong test (send packet back and forth between two UDP echo * servers. */ -static int udp_ping_pong_test(void) +/* was udp_ping_pong_test(void) */ +static int activesock_test0(void) { pj_ioqueue_t *ioqueue = NULL; pj_pool_t *pool = NULL; @@ -153,27 +155,13 @@ static int udp_ping_pong_test(void) pj_status_t status; pool = pj_pool_create(mem, "pingpong", 512, 512, NULL); - if (!pool) - return -10; + PJ_TEST_NOT_NULL(pool, NULL, return -10); - status = pj_ioqueue_create(pool, 4, &ioqueue); - if (status != PJ_SUCCESS) { - ret = -20; - udp_echo_err("pj_ioqueue_create()", status); - goto on_return; - } - - status = udp_echo_srv_create(pool, ioqueue, PJ_TRUE, &srv1); - if (status != PJ_SUCCESS) { - ret = -30; - goto on_return; - } - - status = udp_echo_srv_create(pool, ioqueue, PJ_TRUE, &srv2); - if (status != PJ_SUCCESS) { - ret = -40; - goto on_return; - } + PJ_TEST_SUCCESS(pj_ioqueue_create(pool, 4, &ioqueue), NULL, ERR(-20)) + PJ_TEST_SUCCESS(udp_echo_srv_create(pool, ioqueue, PJ_TRUE, &srv1), + NULL, ERR(-30)); + PJ_TEST_SUCCESS(udp_echo_srv_create(pool, ioqueue, PJ_TRUE, &srv2), + NULL, ERR(-40)); /* initiate the first send */ for (count=0; count<1000; ++count) { @@ -193,11 +181,8 @@ static int udp_ping_pong_test(void) status = pj_activesock_sendto(srv1->asock, &srv1->send_key, &data, &sent, 0, &addr, sizeof(addr)); - if (status != PJ_SUCCESS && status != PJ_EPENDING) { - ret = -50; - udp_echo_err("sendto()", status); - goto on_return; - } + PJ_TEST_TRUE(status==PJ_SUCCESS || status==PJ_EPENDING, + "pj_activesock_sendto()", ERR(-50)); need_send = PJ_FALSE; } @@ -215,20 +200,10 @@ static int udp_ping_pong_test(void) #endif } - if (srv1->rx_err_cnt+srv1->tx_err_cnt != 0 || - srv2->rx_err_cnt+srv2->tx_err_cnt != 0) - { - /* Got error */ - ret = -60; - goto on_return; - } - - if (last_rx1 == srv1->rx_cnt && last_rx2 == srv2->rx_cnt) { - /* Packet lost */ - ret = -70; - udp_echo_err("packets have been lost", PJ_ETIMEDOUT); - goto on_return; - } + PJ_TEST_EQ(srv1->rx_err_cnt+srv1->tx_err_cnt, 0, NULL, ERR(-60)); + PJ_TEST_EQ(srv2->rx_err_cnt+srv2->tx_err_cnt, 0, NULL, ERR(-62)); + PJ_TEST_TRUE(last_rx1 != srv1->rx_cnt || last_rx2 != srv2->rx_cnt, + "timeout/packets have been lost", ERR(-70)); } ret = 0; @@ -331,7 +306,8 @@ static pj_bool_t tcp_on_data_sent(pj_activesock_t *asock, return PJ_TRUE; } -static int tcp_perf_test(void) +/* was tcp_perf_test() */ +static int activesock_test1(void) { enum { COUNT=10000 }; pj_pool_t *pool = NULL; @@ -341,48 +317,33 @@ static int tcp_perf_test(void) pj_activesock_cb cb; struct tcp_state *state1, *state2; unsigned i; - pj_status_t status; - - pool = pj_pool_create(mem, "tcpperf", 256, 256, NULL); + int ret = 0; + pj_status_t status = PJ_SUCCESS; - status = app_socketpair(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock1, - &sock2); - if (status != PJ_SUCCESS) { - status = -100; - goto on_return; - } + pool = pj_pool_create(mem, "activesock_test1", 256, 256, NULL); + PJ_TEST_NOT_NULL(pool, NULL, return -10); - status = pj_ioqueue_create(pool, 4, &ioqueue); - if (status != PJ_SUCCESS) { - status = -110; - goto on_return; - } + PJ_TEST_SUCCESS( app_socketpair(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock1, + &sock2), + NULL, ERR(-100)); + PJ_TEST_SUCCESS(pj_ioqueue_create(pool, 4, &ioqueue), + NULL, ERR(-110)); pj_bzero(&cb, sizeof(cb)); cb.on_data_read = &tcp_on_data_read; cb.on_data_sent = &tcp_on_data_sent; state1 = PJ_POOL_ZALLOC_T(pool, struct tcp_state); - status = pj_activesock_create(pool, sock1, pj_SOCK_STREAM(), NULL, ioqueue, - &cb, state1, &asock1); - if (status != PJ_SUCCESS) { - status = -120; - goto on_return; - } + PJ_TEST_SUCCESS(pj_activesock_create(pool, sock1, pj_SOCK_STREAM(), + NULL, ioqueue, &cb, state1, &asock1), + NULL, ERR(-120)); state2 = PJ_POOL_ZALLOC_T(pool, struct tcp_state); - status = pj_activesock_create(pool, sock2, pj_SOCK_STREAM(), NULL, ioqueue, - &cb, state2, &asock2); - if (status != PJ_SUCCESS) { - status = -130; - goto on_return; - } - - status = pj_activesock_start_read(asock1, pool, 1000, 0); - if (status != PJ_SUCCESS) { - status = -140; - goto on_return; - } + PJ_TEST_SUCCESS(pj_activesock_create(pool, sock2, pj_SOCK_STREAM(), NULL, + ioqueue, &cb, state2, &asock2), + NULL, ERR(-130)); + PJ_TEST_SUCCESS(pj_activesock_start_read(asock1, pool, 1000, 0), + NULL, ERR(-140)); /* Send packet as quickly as possible */ for (i=0; ierr && !state2->err; ++i) { @@ -420,16 +381,10 @@ static int tcp_perf_test(void) */ pj_symbianos_poll(-1, 0); #endif - if (status != PJ_SUCCESS) { - PJ_LOG(1,("", " err: send status=%d", status)); - status = -180; - break; - } else if (status == PJ_SUCCESS) { - if (len != sizeof(*pkt)) { - PJ_LOG(1,("", " err: shouldn't report partial sent")); - status = -190; - break; - } + PJ_TEST_SUCCESS(status, "send error", ERR(-180)); + if (status == PJ_SUCCESS) { + PJ_TEST_EQ(len, sizeof(*pkt), + "shouldn't report partial sent", ERR(-190)); } } @@ -458,23 +413,13 @@ static int tcp_perf_test(void) if (status == PJ_EPENDING) status = PJ_SUCCESS; - if (status != 0) - goto on_return; - - if (state1->err) { - status = -183; - goto on_return; - } - if (state2->err) { - status = -186; - goto on_return; - } - if (state1->next_recv_seq != COUNT) { - PJ_LOG(3,("", " err: only %u packets received, expecting %u", - state1->next_recv_seq, COUNT)); - status = -195; - goto on_return; - } + /* this should not happen. non-success should have been dealt with */ + PJ_TEST_SUCCESS(status, NULL, ERR(-182)); + + PJ_TEST_EQ(state1->err, 0, NULL, ERR(-183)); + PJ_TEST_EQ(state2->err, 0, NULL, ERR(-186)); + PJ_TEST_EQ(state1->next_recv_seq, COUNT, + "not all packets are received", ERR(-195)); on_return: if (asock2) @@ -486,24 +431,17 @@ static int tcp_perf_test(void) if (pool) pj_pool_release(pool); - return status; + return ret; } - - int activesock_test(void) { - int ret; - - PJ_LOG(3,("", "..udp ping/pong test")); - ret = udp_ping_pong_test(); - if (ret != 0) - return ret; + int rc; + if ((rc=activesock_test0()) != 0) + return rc; - PJ_LOG(3,("", "..tcp perf test")); - ret = tcp_perf_test(); - if (ret != 0) - return ret; + if ((rc=activesock_test1()) != 0) + return rc; return 0; } diff --git a/pjlib/src/pjlib-test/atomic.c b/pjlib/src/pjlib-test/atomic.c index 8bd0a5a222..83f99178c1 100644 --- a/pjlib/src/pjlib-test/atomic.c +++ b/pjlib/src/pjlib-test/atomic.c @@ -44,58 +44,48 @@ #if INCLUDE_ATOMIC_TEST +#define THIS_FILE "atomic.c" +#define ERR(r__) { rc=r__; goto on_return; } + int atomic_test(void) { pj_pool_t *pool; pj_atomic_t *atomic_var; - pj_status_t rc; - - pool = pj_pool_create(mem, NULL, 4096, 0, NULL); - if (!pool) - return -10; + int rc=0; + PJ_TEST_NOT_NULL( (pool=pj_pool_create(mem, NULL, 4096, 0, NULL)), + NULL, ERR(-10)); /* create() */ - rc = pj_atomic_create(pool, 111, &atomic_var); - if (rc != 0) { - return -20; - } + PJ_TEST_SUCCESS( pj_atomic_create(pool, 111, &atomic_var), NULL, ERR(-20)); /* get: check the value. */ - if (pj_atomic_get(atomic_var) != 111) - return -30; + PJ_TEST_EQ( pj_atomic_get(atomic_var), 111, NULL, ERR(-30)); /* increment. */ pj_atomic_inc(atomic_var); - if (pj_atomic_get(atomic_var) != 112) - return -40; + PJ_TEST_EQ( pj_atomic_get(atomic_var), 112, NULL, ERR(-40)); /* decrement. */ pj_atomic_dec(atomic_var); - if (pj_atomic_get(atomic_var) != 111) - return -50; + PJ_TEST_EQ( pj_atomic_get(atomic_var), 111, NULL, ERR(-50)); /* set */ pj_atomic_set(atomic_var, 211); - if (pj_atomic_get(atomic_var) != 211) - return -60; + PJ_TEST_EQ( pj_atomic_get(atomic_var), 211, NULL, ERR(-60)); /* add */ pj_atomic_add(atomic_var, 10); - if (pj_atomic_get(atomic_var) != 221) - return -60; + PJ_TEST_EQ( pj_atomic_get(atomic_var), 221, NULL, ERR(-60)); /* check the value again. */ - if (pj_atomic_get(atomic_var) != 221) - return -70; + PJ_TEST_EQ( pj_atomic_get(atomic_var), 221, NULL, ERR(-70)); /* destroy */ - rc = pj_atomic_destroy(atomic_var); - if (rc != 0) - return -80; + PJ_TEST_SUCCESS( pj_atomic_destroy(atomic_var), NULL, ERR(-80)); +on_return: pj_pool_release(pool); - - return 0; + return rc; } diff --git a/pjlib/src/pjlib-test/fifobuf.c b/pjlib/src/pjlib-test/fifobuf.c index d300452ce7..b6fd486867 100644 --- a/pjlib/src/pjlib-test/fifobuf.c +++ b/pjlib/src/pjlib-test/fifobuf.c @@ -85,8 +85,6 @@ static int fifobuf_rolling_test() PJ_TEST_EQ(pj_fifobuf_capacity(&fifo), SIZE-SZ, NULL, return -300); PJ_TEST_EQ(pj_fifobuf_available_size(&fifo), SIZE-SZ, NULL, return -310); - pj_srand(0); - /* Repeat the test */ for (rep=0; rep= start_time. */ @@ -118,11 +101,8 @@ static int file_test_internal(void) /* * Re-open the file and read data. */ - status = pj_file_open(NULL, FILENAME, PJ_O_RDONLY, &fd); - if (status != PJ_SUCCESS) { - app_perror("...file_open() error", status); - return -100; - } + PJ_TEST_SUCCESS(pj_file_open(NULL, FILENAME, PJ_O_RDONLY, &fd), + NULL, return -100); size = 0; while (size < (pj_ssize_t)sizeof(readbuf)) { @@ -133,6 +113,7 @@ static int file_test_internal(void) PJ_LOG(3,("", "...error reading file after %ld bytes " "(error follows)", size)); app_perror("...error", status); + pj_file_close(fd); return -110; } if (read == 0) { @@ -142,68 +123,41 @@ static int file_test_internal(void) size += read; } - if (size != sizeof(buffer)) - return -120; + PJ_TEST_EQ(size, sizeof(buffer), NULL, + {pj_file_close(fd); return -120; }); /* if (!pj_file_eof(fd, PJ_O_RDONLY)) return -130; */ - if (pj_memcmp(readbuf, buffer, size) != 0) - return -140; + PJ_TEST_EQ(pj_memcmp(readbuf, buffer, size), 0, NULL, + {pj_file_close(fd); return -140; }); /* Seek test. */ - status = pj_file_setpos(fd, 4, PJ_SEEK_SET); - if (status != PJ_SUCCESS) { - app_perror("...file_setpos() error", status); - return -141; - } + PJ_TEST_SUCCESS(pj_file_setpos(fd, 4, PJ_SEEK_SET), NULL, + {pj_file_close(fd); return -141; }); /* getpos test. */ - status = pj_file_getpos(fd, &pos); - if (status != PJ_SUCCESS) { - app_perror("...file_getpos() error", status); - return -142; - } - if (pos != 4) - return -143; + PJ_TEST_SUCCESS(pj_file_getpos(fd, &pos), NULL, + {pj_file_close(fd); return -142; }); + PJ_TEST_EQ(pos, 4, NULL, {pj_file_close(fd); return -143; }); - status = pj_file_close(fd); - if (status != PJ_SUCCESS) { - app_perror("...file_close() error", status); - return -150; - } + PJ_TEST_SUCCESS(pj_file_close(fd), NULL, return -150); /* * Rename test. */ - status = pj_file_move(FILENAME, NEWNAME); - if (status != PJ_SUCCESS) { - app_perror("...file_move() error", status); - return -160; - } - - if (pj_file_exists(FILENAME)) - return -170; - if (!pj_file_exists(NEWNAME)) - return -180; - - if (pj_file_size(NEWNAME) != sizeof(buffer)) - return -190; + PJ_TEST_SUCCESS(pj_file_move(FILENAME, NEWNAME), NULL, return -160); + PJ_TEST_EQ(pj_file_exists(FILENAME), 0, NULL, return -170); + PJ_TEST_TRUE(pj_file_exists(NEWNAME), NULL, return -180); + PJ_TEST_EQ(pj_file_size(NEWNAME), sizeof(buffer), NULL, return -190); /* Delete test. */ - status = pj_file_delete(NEWNAME); - if (status != PJ_SUCCESS) { - app_perror("...file_delete() error", status); - return -200; - } - - if (pj_file_exists(NEWNAME)) - return -210; + PJ_TEST_SUCCESS(pj_file_delete(NEWNAME), NULL, return -200); + PJ_TEST_EQ(pj_file_exists(NEWNAME), 0, NULL, return -210); - PJ_LOG(3,("", "...success")); - return PJ_SUCCESS; + return 0; } diff --git a/pjlib/src/pjlib-test/hash_test.c b/pjlib/src/pjlib-test/hash_test.c index fb59331309..05c093e87c 100644 --- a/pjlib/src/pjlib-test/hash_test.c +++ b/pjlib/src/pjlib-test/hash_test.c @@ -25,6 +25,8 @@ #if INCLUDE_HASH_TEST #define HASH_COUNT 31 +#define THIS_FILE "hash_test.c" + static int hash_test_with_key(pj_pool_t *pool, unsigned char key) { @@ -33,51 +35,28 @@ static int hash_test_with_key(pj_pool_t *pool, unsigned char key) pj_hash_iterator_t it_buf, *it; unsigned *entry; - ht = pj_hash_create(pool, HASH_COUNT); - if (!ht) - return -10; + PJ_TEST_NOT_NULL( (ht=pj_hash_create(pool, HASH_COUNT)), NULL, return -10); pj_hash_set(pool, ht, &key, sizeof(key), 0, &value); - entry = (unsigned*) pj_hash_get(ht, &key, sizeof(key), NULL); - if (!entry) - return -20; - - if (*entry != value) - return -30; - - if (pj_hash_count(ht) != 1) - return -30; - - it = pj_hash_first(ht, &it_buf); - if (it == NULL) - return -40; - - entry = (unsigned*) pj_hash_this(ht, it); - if (!entry) - return -50; - - if (*entry != value) - return -60; - - it = pj_hash_next(ht, it); - if (it != NULL) - return -70; + PJ_TEST_NOT_NULL((entry=(unsigned*)pj_hash_get(ht,&key,sizeof(key),NULL)), + NULL, return -20); + PJ_TEST_EQ( *entry, value, NULL, return -25); + PJ_TEST_EQ(pj_hash_count(ht), 1, NULL, return -30); + PJ_TEST_NOT_NULL((it=pj_hash_first(ht, &it_buf)), NULL, return -40); + PJ_TEST_NOT_NULL((entry=(unsigned*)pj_hash_this(ht, it)), NULL, + return -50); + PJ_TEST_EQ(*entry, value, NULL, return -60); + PJ_TEST_EQ(pj_hash_next(ht, it), NULL, NULL, return -70); /* Erase item */ pj_hash_set(NULL, ht, &key, sizeof(key), 0, NULL); - if (pj_hash_get(ht, &key, sizeof(key), NULL) != NULL) - return -80; - - if (pj_hash_count(ht) != 0) - return -90; - - it = pj_hash_first(ht, &it_buf); - if (it != NULL) - return -100; - + PJ_TEST_EQ(pj_hash_get(ht, &key, sizeof(key), NULL), NULL, NULL, + return -80); + PJ_TEST_EQ(pj_hash_count(ht), 0, NULL, return -90); + PJ_TEST_EQ(pj_hash_first(ht, &it_buf), NULL, NULL, return -100); return 0; } @@ -92,9 +71,7 @@ static int hash_collision_test(pj_pool_t *pool) unsigned char *values; unsigned i; - ht = pj_hash_create(pool, HASH_COUNT); - if (!ht) - return -200; + PJ_TEST_NOT_NULL((ht=pj_hash_create(pool, HASH_COUNT)), NULL, return -200); values = (unsigned char*) pj_pool_alloc(pool, COUNT); @@ -103,16 +80,13 @@ static int hash_collision_test(pj_pool_t *pool) pj_hash_set(pool, ht, &i, sizeof(i), 0, &values[i]); } - if (pj_hash_count(ht) != COUNT) - return -210; + PJ_TEST_EQ(pj_hash_count(ht), COUNT, NULL, return -210); for (i=0; iid = i; arg->ioqueue = ioqueue; - rc = pj_thread_create( pool, NULL, - &worker_thread, - arg, - PJ_THREAD_DEFAULT_STACK_SIZE, - PJ_THREAD_SUSPENDED, &thread[i] ); - if (rc != PJ_SUCCESS) { - app_perror("...error: unable to create thread", rc); - return -80; - } + PJ_TEST_SUCCESS( pj_thread_create( pool, NULL, + &worker_thread, + arg, + PJ_THREAD_DEFAULT_STACK_SIZE, + PJ_THREAD_SUSPENDED, &thread[i] ), + NULL, return -80); } /* Mark start time. */ - rc = pj_get_timestamp(&start); - if (rc != PJ_SUCCESS) - return -90; + PJ_TEST_SUCCESS( pj_get_timestamp(&start), NULL, return -90); /* Start the thread. */ TRACE_((THIS_FILE, " resuming all threads..")); for (i=0; i #define THIS_FILE "test_udp" -#define PORT 51233 #define LOOP 2 ///#define LOOP 2 #define BUF_MIN_SIZE 32 @@ -130,6 +129,7 @@ static int compliance_test(const pj_ioqueue_cfg *cfg) pj_sock_t ssock=-1, csock=-1; pj_sockaddr_in addr, dst_addr; int addrlen; + unsigned short port; pj_pool_t *pool = NULL; char *send_buf, *recv_buf; pj_ioqueue_t *ioque = NULL; @@ -169,11 +169,16 @@ static int compliance_test(const pj_ioqueue_cfg *cfg) TRACE_("bind socket..."); pj_bzero(&addr, sizeof(addr)); addr.sin_family = pj_AF_INET(); - addr.sin_port = pj_htons(PORT); if (pj_sock_bind(ssock, &addr, sizeof(addr))) { status=-10; goto on_error; } + // Get address + addrlen = sizeof(addr); + PJ_TEST_SUCCESS(pj_sock_getsockname(ssock, &addr, &addrlen), NULL, + {status=-15; goto on_error;}); + port = pj_sockaddr_get_port(&addr); + // Create I/O Queue. TRACE_("create ioqueue..."); rc = pj_ioqueue_create2(pool, PJ_IOQUEUE_MAX_HANDLES, cfg, &ioque); @@ -242,7 +247,7 @@ static int compliance_test(const pj_ioqueue_cfg *cfg) // Set destination address to send the packet. TRACE_("set destination address..."); temp = pj_str("127.0.0.1"); - if ((rc=pj_sockaddr_in_init(&dst_addr, &temp, PORT)) != 0) { + if ((rc=pj_sockaddr_in_init(&dst_addr, &temp, port)) != 0) { app_perror("...error: unable to resolve 127.0.0.1", rc); status=-290; goto on_error; } @@ -373,7 +378,6 @@ static void on_read_complete(pj_ioqueue_key_t *key, */ static int unregister_test(const pj_ioqueue_cfg *cfg) { - enum { RPORT = 50000, SPORT = 50001 }; pj_pool_t *pool; pj_ioqueue_t *ioqueue; pj_sock_t ssock; @@ -403,14 +407,14 @@ static int unregister_test(const pj_ioqueue_cfg *cfg) } /* Create sender socket */ - status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, SPORT, &ssock); + status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, -1, &ssock); if (status != PJ_SUCCESS) { app_perror("Error initializing socket", status); return -120; } /* Create receiver socket. */ - status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, RPORT, &rsock); + status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, -1, &rsock); if (status != PJ_SUCCESS) { app_perror("Error initializing socket", status); return -130; @@ -543,7 +547,7 @@ static int unregister_test(const pj_ioqueue_cfg *cfg) * Second stage of the test. Register another socket. Then unregister using * the previous key. */ - status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, RPORT, &rsock2); + status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, -1, &rsock2); if (status != PJ_SUCCESS) { app_perror("Error initializing socket (2)", status); return -330; @@ -791,16 +795,16 @@ static int parallel_recv_test(const pj_ioqueue_cfg *cfg) pool = pj_pool_create(mem, "test", 4000, 4000, NULL); if (!pool) { app_perror("Unable to create pool", PJ_ENOMEM); - return -100; + return -1100; } - CHECK(-110, app_socketpair(pj_AF_INET(), pj_SOCK_STREAM(), 0, + CHECK(-1110, app_socketpair(pj_AF_INET(), pj_SOCK_STREAM(), 0, &ssock, &csock)); - CHECK(-120, pj_ioqueue_create2(pool, 2, cfg, &ioqueue)); + CHECK(-1120, pj_ioqueue_create2(pool, 2, cfg, &ioqueue)); pj_bzero(&cb, sizeof(cb)); cb.on_read_complete = &on_read_complete2; - CHECK(-130, pj_ioqueue_register_sock(pool, ioqueue, ssock, &recv_packet_count, + CHECK(-1130, pj_ioqueue_register_sock(pool, ioqueue, ssock, &recv_packet_count, &cb, &skey)); /* spawn parallel recv()s */ @@ -809,7 +813,7 @@ static int parallel_recv_test(const pj_ioqueue_cfg *cfg) pj_ioqueue_op_key_init(&recv_ops[i], sizeof(pj_ioqueue_op_key_t)); recv_ops[i].user_data = &recv_datas[i]; recv_datas[i].len = sizeof(packet_t); - CHECK(-140, pj_ioqueue_recv(skey, &recv_ops[i], &recv_datas[i].buffer, + CHECK(-1140, pj_ioqueue_recv(skey, &recv_ops[i], &recv_datas[i].buffer, &recv_datas[i].len, 0)); } @@ -821,7 +825,7 @@ static int parallel_recv_test(const pj_ioqueue_cfg *cfg) arg->id = i; arg->timeout = TIMEOUT_SECS; - CHECK(-150, pj_thread_create(pool, "parallel_thread", + CHECK(-1150, pj_thread_create(pool, "parallel_thread", parallel_worker_thread, arg, 0, 0,&threads[i])); } @@ -843,7 +847,7 @@ static int parallel_recv_test(const pj_ioqueue_cfg *cfg) TRACE__((THIS_FILE, "......(was async sent)")); } else if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "......send error")); - retcode = -160; + retcode = -1160; goto on_return; } } @@ -856,8 +860,8 @@ static int parallel_recv_test(const pj_ioqueue_cfg *cfg) /* Wait until all threads quits */ for (i=0; i ASYNC_CNT+async_send) { PJ_LOG(3,(THIS_FILE, "....info: total wakeup count is %d " @@ -926,6 +930,7 @@ static int bench_test(const pj_ioqueue_cfg *cfg, int bufsize, { pj_sock_t ssock=-1, csock=-1; pj_sockaddr_in addr; + unsigned short port; pj_pool_t *pool = NULL; pj_sock_t *inactive_sock=NULL; pj_ioqueue_op_key_t *inactive_read_op; @@ -960,9 +965,14 @@ static int bench_test(const pj_ioqueue_cfg *cfg, int bufsize, // Bind server socket. pj_bzero(&addr, sizeof(addr)); addr.sin_family = pj_AF_INET(); - addr.sin_port = pj_htons(PORT); - if (pj_sock_bind(ssock, &addr, sizeof(addr))) - goto on_error; + PJ_TEST_SUCCESS(pj_sock_bind(ssock, &addr, sizeof(addr)), NULL, + goto on_error); + + // Get bound port + i = sizeof(addr); + PJ_TEST_SUCCESS(pj_sock_getsockname(ssock, &addr, &i), NULL, + goto on_error); + port = pj_sockaddr_get_port(&addr); pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES); @@ -1034,7 +1044,7 @@ static int bench_test(const pj_ioqueue_cfg *cfg, int bufsize, } // Set destination address to send the packet. - pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT); + pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), port); // Test loop. t_elapsed.u64 = 0; @@ -1241,7 +1251,7 @@ int udp_ioqueue_test() #endif }; pj_bool_t concurs[] = { PJ_TRUE, PJ_FALSE }; - int i, rc, err = 0; + int i, rc; for (i=0; i<(int)PJ_ARRAY_SIZE(epoll_flags); ++i) { pj_ioqueue_cfg cfg; @@ -1253,8 +1263,8 @@ int udp_ioqueue_test() pj_ioqueue_name(), cfg.epoll_flags)); rc = udp_ioqueue_test_imp(&cfg); - if (rc != 0 && err==0) - err = rc; + if (rc) return rc; + } for (i=0; i<(int)PJ_ARRAY_SIZE(concurs); ++i) { @@ -1267,8 +1277,7 @@ int udp_ioqueue_test() pj_ioqueue_name(), cfg.default_concurrency)); rc = udp_ioqueue_test_imp(&cfg); - if (rc != 0 && err==0) - err = rc; + if (rc) return rc; } #if PJ_HAS_THREADS @@ -1282,13 +1291,12 @@ int udp_ioqueue_test() pj_ioqueue_name(), cfg.epoll_flags)); rc = parallel_recv_test(&cfg); - if (rc != 0 && err==0) - err = rc; + if (rc) return rc; } #endif - return err; + return 0; } #else diff --git a/pjlib/src/pjlib-test/ioq_unreg.c b/pjlib/src/pjlib-test/ioq_unreg.c index 0894a3bb12..bed1e3b2b4 100644 --- a/pjlib/src/pjlib-test/ioq_unreg.c +++ b/pjlib/src/pjlib-test/ioq_unreg.c @@ -168,7 +168,7 @@ static int perform_unreg_test(pj_ioqueue_t *ioqueue, * will return from the poll early. */ if (other_socket) { - status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, 56127, &osd.sock); + status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, -1, &osd.sock); if (status != PJ_SUCCESS) { app_perror("Error creating other socket", status); return -12; diff --git a/pjlib/src/pjlib-test/main.c b/pjlib/src/pjlib-test/main.c index 43c29b00da..68cd44a6ef 100644 --- a/pjlib/src/pjlib-test/main.c +++ b/pjlib/src/pjlib-test/main.c @@ -21,14 +21,9 @@ #include #include #include +#include #include -extern int param_echo_sock_type; -extern const char *param_echo_server; -extern int param_echo_port; -extern pj_bool_t param_ci_mode; - - //#if defined(PJ_WIN32) && PJ_WIN32!=0 #if 0 #include @@ -82,55 +77,99 @@ static void init_signals(void) #define init_signals() #endif +static void usage() +{ + puts("Usage:"); + puts(" pjlib-test [OPTION] [test_to_run] [..]"); + puts(""); + puts("where OPTIONS:"); + puts(""); + puts(" -h, --help Show this help screen"); + + ut_usage(); + + puts(" --skip-e Skip essential tests"); + puts(" --ci-mode Running in slow CI mode"); + puts(" -i Ask ENTER before quitting"); + puts(" -n Do not trap signals"); + puts(" -p PORT Use port PORT for echo port"); + puts(" -s SERVER Use SERVER as ech oserver"); + puts(" -t ucp,tcp Set echo socket type to UDP or TCP"); +} + + int main(int argc, char *argv[]) { - int iarg=1, rc; + int rc; int interractive = 0; int no_trap = 0; boost(); + ut_app_init0(&test_app.ut_app); + + /* + * Parse arguments + */ + if (pj_argparse_get_bool(&argc, argv, "-h") || + pj_argparse_get_bool(&argc, argv, "--help")) + { + usage(); + return 0; + } + interractive = pj_argparse_get_bool(&argc, argv, "-i"); + no_trap = pj_argparse_get_bool(&argc, argv, "-n"); + if (pj_argparse_get_int(&argc, argv, "-p", &test_app.param_echo_port)) { + usage(); + return 1; + } + if (pj_argparse_get_str(&argc, argv, "-s", + (char**)&test_app.param_echo_server)) + { + usage(); + return 1; + } - while (iarg < argc) { - char *arg = argv[iarg++]; - - if (*arg=='-' && *(arg+1)=='i') { - interractive = 1; - - } else if (*arg=='-' && *(arg+1)=='n') { - no_trap = 1; - } else if (*arg=='-' && *(arg+1)=='p') { - pj_str_t port = pj_str(argv[iarg++]); - - param_echo_port = pj_strtoul(&port); - - } else if (*arg=='-' && *(arg+1)=='s') { - param_echo_server = argv[iarg++]; - - } else if (*arg=='-' && *(arg+1)=='t') { - pj_str_t type = pj_str(argv[iarg++]); - - if (pj_stricmp2(&type, "tcp")==0) - param_echo_sock_type = pj_SOCK_STREAM(); - else if (pj_stricmp2(&type, "udp")==0) - param_echo_sock_type = pj_SOCK_DGRAM(); + if (pj_argparse_exists(argv, "-t")) { + char *sock_type; + if (pj_argparse_get_str(&argc, argv, "-t", &sock_type)==PJ_SUCCESS) { + if (pj_ansi_stricmp(sock_type, "tcp")==0) + test_app.param_echo_sock_type = pj_SOCK_STREAM(); + else if (pj_ansi_stricmp(sock_type, "udp")==0) + test_app.param_echo_sock_type = pj_SOCK_DGRAM(); else { - printf("Error: unknown socket type %s\n", type.ptr); + printf("Error: unknown socket type %s for -t option\n", + sock_type); + usage(); return 1; } - } else if (strcmp(arg, "--ci-mode")==0) { - param_ci_mode = PJ_TRUE; - } else { - printf("Error in argument \"%s\"\n", arg); + usage(); return 1; } } + if (ut_parse_args(&test_app.ut_app, &argc, argv)) { + usage(); + return 1; + } + test_app.param_skip_essentials = pj_argparse_get_bool(&argc, argv, + "--skip-e"); + test_app.param_ci_mode = pj_argparse_get_bool(&argc, argv, "--ci-mode"); + + if (!no_trap) { init_signals(); } - rc = test_main(); + if (pj_argparse_peek_next_option(argv)) { + printf("Error: unknown argument %s\n", + pj_argparse_peek_next_option(argv)); + usage(); + return 1; + } + + /* argc/argv now contains option values only, if any */ + rc = test_main(argc, argv); if (interractive) { char s[10]; diff --git a/pjlib/src/pjlib-test/main_rtems.c b/pjlib/src/pjlib-test/main_rtems.c index 881b7b6d49..c382a12a4a 100644 --- a/pjlib/src/pjlib-test/main_rtems.c +++ b/pjlib/src/pjlib-test/main_rtems.c @@ -29,10 +29,6 @@ #include #include -extern int param_echo_sock_type; -extern const char *param_echo_server; -extern int param_echo_port; - #include #define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM diff --git a/pjlib/src/pjlib-test/main_win32.c b/pjlib/src/pjlib-test/main_win32.c index 1a89f41a15..b5487c5b5d 100644 --- a/pjlib/src/pjlib-test/main_win32.c +++ b/pjlib/src/pjlib-test/main_win32.c @@ -41,8 +41,6 @@ BOOL InitInstance (HINSTANCE, int); LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); -extern int param_log_decor; // in test.c - static HINSTANCE hInst; static HWND hwndLog; static HFONT hFixedFont; @@ -63,6 +61,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { MSG msg; + char *argv[] = {"pjlib-test", NULL}; PJ_UNUSED_ARG(lpCmdLine); PJ_UNUSED_ARG(hPrevInstance); @@ -72,10 +71,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, return FALSE; pj_log_set_log_func( &write_log ); - param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_CR; + test_app.param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_CR; // Run the test! - test_main(); + test_main(1, argv); PJ_LOG(3,(THIS_FILE,"")); PJ_LOG(3,(THIS_FILE,"Press ESC to quit")); diff --git a/pjlib/src/pjlib-test/rbtree.c b/pjlib/src/pjlib-test/rbtree.c index 7a96ac2855..846b4847c7 100644 --- a/pjlib/src/pjlib-test/rbtree.c +++ b/pjlib/src/pjlib-test/rbtree.c @@ -43,21 +43,13 @@ static int compare_node(const node_key *k1, const node_key *k2) } } -void randomize_string(char *str, int len) -{ - int i; - for (i=0; ikey,(node_key*)it->key)>=0) { - ++err; PJ_LOG(3, (THIS_FILE, "Error: %s >= %s", (char*)prev->user_data, (char*)it->user_data)); + rc=-45; + goto on_error; } } prev = it; @@ -124,13 +113,10 @@ static int test(void) // Search. for (j=0; j +#define THIS_FILE "test.c" + #ifdef _MSC_VER # pragma warning(disable:4127) @@ -32,185 +34,360 @@ #endif -#define DO_TEST(test) do { \ - PJ_LOG(3, ("test", "Running %s...", #test)); \ - rc = test; \ - PJ_LOG(3, ("test", \ - "%s(%d)", \ - (rc ? "..ERROR" : "..success"), rc)); \ - if (rc!=0) goto on_return; \ - } while (0) - - pj_pool_factory *mem; -int param_echo_sock_type; -const char *param_echo_server = ECHO_SERVER_ADDRESS; -int param_echo_port = ECHO_SERVER_START_PORT; -int param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | - PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_INDENT; -pj_bool_t param_ci_mode = PJ_FALSE; /* GH CI mode: more lenient tests */ +struct test_app_t test_app = { + .param_echo_sock_type = 0, + .param_echo_server = ECHO_SERVER_ADDRESS, + .param_echo_port = ECHO_SERVER_START_PORT, + .param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | + PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_INDENT, + .param_ci_mode = PJ_FALSE, +}; int null_func() { return 0; } -int test_inner(void) +static pj_bool_t test_included(const char *name, int argc, char *argv[]) { - pj_caching_pool caching_pool; - const char *filename; - int line; - int rc = 0; - - mem = &caching_pool.factory; + if (argc <= 1) + return PJ_TRUE; + + ++argv; + while (*argv) { + if (pj_ansi_strcmp(name, *argv)==0) + return PJ_TRUE; + ++argv; + } + return PJ_FALSE; +} - pj_log_set_level(3); - pj_log_set_decor(param_log_decor); +static pj_test_case *init_test_case( int (*test_func)(void), const char *obj_name, + unsigned flags, pj_test_case *tc, + char *log_buf, unsigned log_buf_size) +{ + flags |= PJ_TEST_FUNC_NO_ARG; + pj_test_case_init(tc, obj_name, flags, (int (*)(void*))test_func, NULL, + log_buf, log_buf_size, NULL); + return tc; +} - rc = pj_init(); - if (rc != 0) { - app_perror("pj_init() error!!", rc); - return rc; +static void list_tests(const pj_test_suite *suite, const char *title) +{ + unsigned d = pj_log_get_decor(); + const pj_test_case *tc; + + pj_log_set_decor(d ^ PJ_LOG_HAS_NEWLINE); + PJ_LOG(3,(THIS_FILE, "%ld %s:", pj_list_size(&suite->tests), title)); + pj_log_set_decor(0); + for (tc=suite->tests.next; tc!=&suite->tests; tc=tc->next) { + PJ_LOG(3,(THIS_FILE, " %s", tc->obj_name)); } + PJ_LOG(3,(THIS_FILE, "\n")); + pj_log_set_decor(d); +} - pj_dump_config(); - pj_caching_pool_init( &caching_pool, NULL, 0 ); +static pj_test_stat essential_tests(int argc, char *argv[]) +{ + pj_test_suite suite; + pj_test_runner runner; + pj_test_stat stat; + enum { + MAX_TESTS = 12, + LOG_BUF_SIZE = 256, + }; + char log_bufs[MAX_TESTS][LOG_BUF_SIZE]; + pj_test_case test_cases[MAX_TESTS]; + int ntests = 0; + + pj_bzero(&stat, sizeof(stat)); + /* Not necessary but to prevent unused-var warning when no test */ + pj_bzero(test_cases, sizeof(test_cases)); + pj_bzero(log_bufs, sizeof(log_bufs)); + + if (test_app.ut_app.prm_config) + pj_dump_config(); + + /* Test the unit-testing framework first, outside unit-test! + * Only perform the test if user is not requesting specific test. + */ + if (argc==1 && !test_app.ut_app.prm_list_test) { + PJ_LOG(3,(THIS_FILE, "Testing the unit-test framework (basic)")); + if (unittest_basic_test()) { + stat.nfailed = 1; + return stat; + } + } - if (param_ci_mode) - PJ_LOG(3,("test", "Using ci-mode")); + /* Now that the basic unit-testing framework has been tested, + * perform essential tests using basic unit-testing framework. + */ + pj_test_suite_init(&suite); + +#define ADD_TEST(test_func, flags) \ + if (ntests < MAX_TESTS) { \ + const char *test_name = #test_func; \ + if (test_included(test_name, argc, argv)) { \ + pj_test_case *tc = init_test_case( &test_func, test_name, flags, \ + &test_cases[ntests], \ + log_bufs[ntests], \ + LOG_BUF_SIZE); \ + pj_test_suite_add_case( &suite, tc); \ + ++ntests; \ + } \ + } else { \ + PJ_LOG(1,(THIS_FILE, "Too many tests for adding %s", #test_func)); \ + } #if INCLUDE_ERRNO_TEST - DO_TEST( errno_test() ); + ADD_TEST( errno_test, 0); #endif #if INCLUDE_EXCEPTION_TEST - DO_TEST( exception_test() ); + ADD_TEST( exception_test, 0); #endif #if INCLUDE_OS_TEST - DO_TEST( log_test() ); - DO_TEST( os_test() ); -#endif - -#if INCLUDE_RAND_TEST - DO_TEST( rand_test() ); + ADD_TEST( os_test, 0); #endif #if INCLUDE_LIST_TEST - DO_TEST( list_test() ); + ADD_TEST( list_test, 0); #endif #if INCLUDE_POOL_TEST - DO_TEST( pool_test() ); -#endif - -#if INCLUDE_POOL_PERF_TEST - DO_TEST( pool_perf_test() ); + ADD_TEST( pool_test, 0); #endif #if INCLUDE_STRING_TEST - DO_TEST( string_test() ); + ADD_TEST( string_test, 0); #endif #if INCLUDE_FIFOBUF_TEST - DO_TEST( fifobuf_test() ); + ADD_TEST( fifobuf_test, 0); +#endif + +#if INCLUDE_MUTEX_TEST + ADD_TEST( mutex_test, 0); +#endif + +#if INCLUDE_THREAD_TEST + ADD_TEST( thread_test, 0); +#endif + +#undef ADD_TEST + + if (test_app.ut_app.prm_list_test) { + list_tests(&suite, "essential tests"); + return stat; + } + + if (ntests > 0) { + pj_test_runner_param runner_prm; + pj_test_runner_param_default(&runner_prm); + runner_prm.stop_on_error = test_app.ut_app.prm_stop_on_error; + + PJ_LOG(3,(THIS_FILE, "Performing %d essential tests", ntests)); + pj_test_init_basic_runner(&runner, &runner_prm); + pj_test_run(&runner, &suite); + pj_test_display_log_messages(&suite, + test_app.ut_app.prm_logging_policy); + pj_test_get_stat(&suite, &stat); + pj_test_display_stat(&stat, "essential tests", THIS_FILE); + + if (stat.nfailed) + return stat; + } + + /* Now that the essential components have been tested, test the + * multithreaded unit-testing framework. + */ + if (argc==1) { + PJ_LOG(3,(THIS_FILE, "Testing the unit-test test scheduling")); + if (unittest_parallel_test()) { + stat.nfailed = 1; + return stat; + } + + PJ_LOG(3,(THIS_FILE, "Testing the unit-test framework (multithread)")); + if (unittest_test()) { + stat.nfailed = 1; + return stat; + } + } + + return stat; +} + +static int features_tests(int argc, char *argv[]) +{ + if (ut_app_init1(&test_app.ut_app, mem) != PJ_SUCCESS) + return 1; + +#if INCLUDE_RAND_TEST + UT_ADD_TEST(&test_app.ut_app, rand_test, 0); #endif -#if INCLUDE_UNITTEST_TEST - DO_TEST( unittest_basic_test() ); - DO_TEST( unittest_test() ); - DO_TEST( unittest_parallel_test() ); +#if INCLUDE_POOL_PERF_TEST + UT_ADD_TEST(&test_app.ut_app, pool_perf_test, 0); #endif #if INCLUDE_RBTREE_TEST - DO_TEST( rbtree_test() ); + UT_ADD_TEST(&test_app.ut_app, rbtree_test, 0); #endif #if INCLUDE_HASH_TEST - DO_TEST( hash_test() ); + UT_ADD_TEST(&test_app.ut_app, hash_test, 0); #endif #if INCLUDE_TIMESTAMP_TEST - DO_TEST( timestamp_test() ); + UT_ADD_TEST(&test_app.ut_app, timestamp_test, 0); #endif #if INCLUDE_ATOMIC_TEST - DO_TEST( atomic_test() ); -#endif - -#if INCLUDE_MUTEX_TEST - DO_TEST( mutex_test() ); + UT_ADD_TEST(&test_app.ut_app, atomic_test, 0); #endif #if INCLUDE_TIMER_TEST - DO_TEST( timer_test() ); + UT_ADD_TEST(&test_app.ut_app, timer_test, 0); #endif #if INCLUDE_SLEEP_TEST - DO_TEST( sleep_test() ); + UT_ADD_TEST(&test_app.ut_app, sleep_test, 0); #endif -#if INCLUDE_THREAD_TEST - DO_TEST( thread_test() ); +#if INCLUDE_FILE_TEST + UT_ADD_TEST(&test_app.ut_app, file_test, 0); #endif #if INCLUDE_SOCK_TEST - DO_TEST( sock_test() ); + UT_ADD_TEST(&test_app.ut_app, sock_test, 0); #endif #if INCLUDE_SOCK_PERF_TEST - DO_TEST( sock_perf_test() ); + UT_ADD_TEST(&test_app.ut_app, sock_perf_test, 0); #endif #if INCLUDE_SELECT_TEST - DO_TEST( select_test() ); + UT_ADD_TEST(&test_app.ut_app, select_test, 0); #endif #if INCLUDE_UDP_IOQUEUE_TEST - DO_TEST( udp_ioqueue_test() ); + UT_ADD_TEST(&test_app.ut_app, udp_ioqueue_test, 0); #endif #if PJ_HAS_TCP && INCLUDE_TCP_IOQUEUE_TEST - DO_TEST( tcp_ioqueue_test() ); + UT_ADD_TEST(&test_app.ut_app, tcp_ioqueue_test, 0); #endif -#if INCLUDE_IOQUEUE_UNREG_TEST - DO_TEST( udp_ioqueue_unreg_test() ); + /* Consistently encountered retcode 520 on Windows virtual machine + with 8 vcpu and 16GB RAM when multithread unit test is used, + with the following logs: + 17:50:57.761 .tcp (multithreads) + 17:50:58.254 ...pj_ioqueue_send() error: Object is busy (PJ_EBUSY) + 17:50:58.264 ..test failed (retcode=520) + 17:50:58.264 .tcp (multithreads, sequenced, concur=0) + 17:51:06.084 .tcp (multithreads, sequenced, concur=1) + 17:51:06.484 ...pj_ioqueue_send() error: Object is busy (PJ_EBUSY) + 17:51:06.486 ..test failed (retcode=520) + + I suspect it's because the ioq stress test also uses a lot of threads + and couldn't keep up with processing the data. + Therefore we'll disable parallelism on Windows for this test. [blp] + */ +#if INCLUDE_IOQUEUE_STRESS_TEST +# if defined(PJ_WIN32) && PJ_WIN32!=0 + UT_ADD_TEST(&test_app.ut_app, ioqueue_stress_test, PJ_TEST_EXCLUSIVE); +# else + UT_ADD_TEST(&test_app.ut_app, ioqueue_stress_test, 0); +# endif #endif -#if INCLUDE_IOQUEUE_STRESS_TEST - DO_TEST( ioqueue_stress_test() ); +#if INCLUDE_IOQUEUE_UNREG_TEST + UT_ADD_TEST(&test_app.ut_app, udp_ioqueue_unreg_test, 0); #endif #if INCLUDE_IOQUEUE_PERF_TEST - DO_TEST( ioqueue_perf_test() ); + UT_ADD_TEST(&test_app.ut_app, ioqueue_perf_test0, 0); + UT_ADD_TEST(&test_app.ut_app, ioqueue_perf_test1, 0); #endif #if INCLUDE_ACTIVESOCK_TEST - DO_TEST( activesock_test() ); -#endif - -#if INCLUDE_FILE_TEST - DO_TEST( file_test() ); + UT_ADD_TEST(&test_app.ut_app, activesock_test, 0); #endif #if INCLUDE_SSLSOCK_TEST - DO_TEST( ssl_sock_test() ); + UT_ADD_TEST(&test_app.ut_app, ssl_sock_test, 0); #endif + +#undef ADD_TEST + + if (ut_run_tests(&test_app.ut_app, "features tests", argc, argv)) { + ut_app_destroy(&test_app.ut_app); + return 1; + } + + ut_app_destroy(&test_app.ut_app); + return 0; +} + +int test_inner(int argc, char *argv[]) +{ + pj_caching_pool caching_pool; + pj_test_stat stat; + const char *filename; + int line; + int rc = 0; + + mem = &caching_pool.factory; + + pj_log_set_level(3); + pj_log_set_decor(test_app.param_log_decor); + + rc = pj_init(); + if (rc != 0) { + app_perror("pj_init() error!!", rc); + return rc; + } + + pj_caching_pool_init( &caching_pool, NULL, 0 ); + + if (test_app.param_ci_mode) + PJ_LOG(3,(THIS_FILE, "Using ci-mode")); + + if (!test_app.param_skip_essentials) { + stat = essential_tests(argc, argv); + if (stat.nfailed) { + rc = 1; + goto on_return; + } + } + + if (argc-1 > 0 && stat.nruns==argc-1) { + /* cmdline specifies test(s) to run, and the number of runs + * matches that. That means all requested tests have been run. + */ + } else { + rc = features_tests(argc, argv); + if (rc) + goto on_return; + } + #if INCLUDE_ECHO_SERVER //echo_server(); //echo_srv_sync(); udp_echo_srv_ioqueue(); #elif INCLUDE_ECHO_CLIENT - if (param_echo_sock_type == 0) - param_echo_sock_type = pj_SOCK_DGRAM(); + if (test_app.param_echo_sock_type == 0) + test_app.param_echo_sock_type = pj_SOCK_DGRAM(); - echo_client( param_echo_sock_type, - param_echo_server, - param_echo_port); + echo_client( test_app.param_echo_sock_type, + test_app.param_echo_server, + test_app.param_echo_port); #endif goto on_return; @@ -219,16 +396,16 @@ int test_inner(void) pj_caching_pool_destroy( &caching_pool ); - PJ_LOG(3,("test", " ")); + PJ_LOG(3,(THIS_FILE, " ")); pj_thread_get_stack_info(pj_thread_this(), &filename, &line); - PJ_LOG(3,("test", "Stack max usage: %u, deepest: %s:%u", + PJ_LOG(3,(THIS_FILE, "Stack max usage: %u, deepest: %s:%u", pj_thread_get_stack_max_usage(pj_thread_this()), filename, line)); if (rc == 0) - PJ_LOG(3,("test", "Looks like everything is okay!..")); + PJ_LOG(3,(THIS_FILE, "Looks like everything is okay!..")); else - PJ_LOG(3,("test", "Test completed with error(s)")); + PJ_LOG(3,(THIS_FILE, "**Test completed with error(s)**")); pj_shutdown(); @@ -237,16 +414,16 @@ int test_inner(void) #include -int test_main(void) +int test_main(int argc, char *argv[]) { PJ_USE_EXCEPTION; PJ_TRY { - return test_inner(); + return test_inner(argc, argv); } PJ_CATCH_ANY { int id = PJ_GET_EXCEPTION(); - PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)", + PJ_LOG(3,(THIS_FILE, "FATAL: unhandled exception id %d (%s)", id, pj_exception_id_name(id))); } PJ_END; diff --git a/pjlib/src/pjlib-test/test.h b/pjlib/src/pjlib-test/test.h index 226a71bf84..7a109a5fe2 100644 --- a/pjlib/src/pjlib-test/test.h +++ b/pjlib/src/pjlib-test/test.h @@ -20,6 +20,8 @@ #define __PJLIB_TEST_H__ #include +#include +#include #define TEST_DEFAULT 1 @@ -51,7 +53,7 @@ #define INCLUDE_FIFOBUF_TEST GROUP_DATA_STRUCTURE #define INCLUDE_RBTREE_TEST GROUP_DATA_STRUCTURE #define INCLUDE_TIMER_TEST GROUP_DATA_STRUCTURE -#define INCLUDE_UNITTEST_TEST GROUP_DATA_STRUCTUREc +#define INCLUDE_UNITTEST_TEST GROUP_DATA_STRUCTURE #define INCLUDE_ATOMIC_TEST GROUP_OS #define INCLUDE_MUTEX_TEST (PJ_HAS_THREADS && GROUP_OS) #define INCLUDE_SLEEP_TEST GROUP_OS @@ -109,11 +111,15 @@ extern int select_test(void); extern int udp_ioqueue_test(void); extern int udp_ioqueue_unreg_test(void); extern int tcp_ioqueue_test(void); -extern int ioqueue_perf_test(void); +extern int ioqueue_perf_test0(void); +extern int ioqueue_perf_test1(void); extern int ioqueue_stress_test(void); extern int activesock_test(void); extern int file_test(void); extern int ssl_sock_test(void); +extern int unittest_basic_test(void); +extern int unittest_parallel_test(void); +extern int unittest_test(void); extern int echo_server(void); extern int echo_client(int sock_type, const char *server, int port); @@ -122,10 +128,25 @@ extern int echo_srv_sync(void); extern int udp_echo_srv_ioqueue(void); extern int echo_srv_common_loop(pj_atomic_t *bytes_counter); +#define UT_MAX_TESTS 24 +#include "test_util.h" +/* Global vars */ extern pj_pool_factory *mem; - -extern int test_main(void); +struct test_app_t +{ + ut_app_t ut_app; + + int param_echo_sock_type; + const char *param_echo_server; + int param_echo_port; + int param_log_decor; + pj_bool_t param_ci_mode; + pj_bool_t param_skip_essentials; +}; +extern struct test_app_t test_app; + +extern int test_main(int argc, char *argv[]); extern void app_perror(const char *msg, pj_status_t err); extern pj_status_t app_socket(int family, int type, int proto, int port, pj_sock_t *ptr_sock); diff --git a/pjlib/src/pjlib-test/test_util.h b/pjlib/src/pjlib-test/test_util.h new file mode 100644 index 0000000000..7eb4575c7e --- /dev/null +++ b/pjlib/src/pjlib-test/test_util.h @@ -0,0 +1,317 @@ +#include +#include +#include +#include +#include +#include +#include + +/* Overrideable max tests */ +#ifndef UT_MAX_TESTS +# define UT_MAX_TESTS 16 +#endif + +/* Overrideable log max buffer size */ +#ifndef UT_LOG_BUF_SIZE +# define UT_LOG_BUF_SIZE 1000 +#endif + +/* Usually app won't supply THIS_FILE when including test_util.h, so + * create a temporary one + */ +#ifndef THIS_FILE +# define THIS_FILE "test.c" +# define UNDEF_THIS_FILE 1 +#endif + +/* Unit testing app */ +typedef struct ut_app_t +{ + pj_bool_t prm_config; + pj_test_select_tests prm_logging_policy; + int prm_nthreads; + int prm_list_test; + pj_bool_t prm_stop_on_error; + pj_bool_t prm_shuffle; + int prm_seed; + unsigned flags; + unsigned verbosity; + + pj_pool_t *pool; + pj_test_suite suite; + pj_test_runner *runner; + + int ntests; + pj_test_case test_cases[UT_MAX_TESTS]; +} ut_app_t; + +/* Call this in main.c before parsing arguments */ +PJ_INLINE(void) ut_app_init0(ut_app_t *ut_app) +{ + pj_bzero(ut_app, sizeof(*ut_app)); + ut_app->prm_logging_policy = PJ_TEST_FAILED_TESTS; + ut_app->prm_nthreads = -1; + ut_app->flags = 0; +} + +/* Call this in test.c before adding test cases */ +PJ_INLINE(pj_status_t) ut_app_init1(ut_app_t *ut_app, pj_pool_factory *mem) +{ + ut_app->pool = pj_pool_create(mem, THIS_FILE, 4000, 4000, NULL); + PJ_TEST_NOT_NULL(ut_app->pool, NULL, return PJ_ENOMEM); + pj_test_suite_init(&ut_app->suite); + return PJ_SUCCESS; +} + +/* Don't forget to call this */ +PJ_INLINE(void) ut_app_destroy(ut_app_t *ut_app) +{ + pj_pool_release(ut_app->pool); + ut_app->pool = NULL; +} + +typedef int (*ut_func)(void*); + +/* This is for adding test func that has no arg */ +#define UT_ADD_TEST(ut_app, test_func, flags) \ + ut_add_test(ut_app, (ut_func)test_func, 0, \ + #test_func, flags | PJ_TEST_FUNC_NO_ARG, argc, argv) + + +/* This is for adding test func that HAS arg */ +#define UT_ADD_TEST1(ut_app, test_func, arg, flags) \ + ut_add_test(ut_app, (ut_func)test_func, arg, #test_func, flags, argc, argv) + + +/* Check if a test is specified/requested in cmdline */ +PJ_INLINE(pj_bool_t) ut_test_included(const char *name, int argc, char *argv[]) +{ + if (argc <= 1) + return PJ_TRUE; + + ++argv; + while (*argv) { + if (pj_ansi_strcmp(name, *argv)==0) + return PJ_TRUE; + ++argv; + } + return PJ_FALSE; +} + +/* Add test case */ +PJ_INLINE(pj_status_t) ut_add_test(ut_app_t *ut_app, int (*test_func)(void*), + void *arg, const char *test_name, + unsigned flags, int argc, char *argv[]) +{ + char *log_buf; + pj_test_case *tc; + + if (ut_app->ntests >= UT_MAX_TESTS) { + PJ_LOG(1,(THIS_FILE, "Too many tests for adding %s", test_name)); + return PJ_ETOOMANY; + } + + if (!ut_test_included(test_name, argc, argv)) { + return PJ_ENOTFOUND; + } + + log_buf = (char*)pj_pool_alloc(ut_app->pool, UT_LOG_BUF_SIZE); + tc = &ut_app->test_cases[ut_app->ntests]; + flags |= ut_app->flags; + pj_test_case_init(tc, test_name, flags, (int (*)(void*))test_func, arg, + log_buf, UT_LOG_BUF_SIZE, NULL); + + pj_test_suite_add_case( &ut_app->suite, tc); + ++ut_app->ntests; + + return PJ_SUCCESS; +} + +PJ_INLINE(void) ut_list_tests(ut_app_t *ut_app, const char *title) +{ + unsigned d = pj_log_get_decor(); + const pj_test_case *tc, *prev=NULL; + + pj_log_set_decor(d ^ PJ_LOG_HAS_NEWLINE); + PJ_LOG(3,(THIS_FILE, "%ld %s:", pj_list_size(&ut_app->suite.tests), + title)); + pj_log_set_decor(0); + for (tc=ut_app->suite.tests.next; tc!=&ut_app->suite.tests; tc=tc->next) { + if (!prev || pj_ansi_strcmp(tc->obj_name, prev->obj_name)) + PJ_LOG(3,(THIS_FILE, " %s", tc->obj_name)); + prev = tc; + } + PJ_LOG(3,(THIS_FILE, "\n")); + pj_log_set_decor(d); +} + +PJ_INLINE(pj_status_t) ut_run_tests(ut_app_t *ut_app, const char *title, + int argc, char *argv[]) +{ + pj_test_runner_param runner_prm; + pj_test_runner_param_default(&runner_prm); + pj_test_runner *runner; + pj_test_stat stat; + pj_status_t status; + + if (ut_app->prm_shuffle) { + PJ_LOG(3,(THIS_FILE, "Shuffling tests, random seed=%d", + ut_app->prm_seed)); + pj_test_suite_shuffle(&ut_app->suite, ut_app->prm_seed); + } + + if (ut_app->prm_list_test) { + ut_list_tests(ut_app, title); + return PJ_SUCCESS; + } + + if (argc > 1) { + int i; + for (i=1; isuite.tests.next; tc!=&ut_app->suite.tests; + tc=tc->next) + { + if (pj_ansi_strcmp(argv[i], tc->obj_name)==0) + break; + } + if (tc==&ut_app->suite.tests) { + PJ_LOG(2,(THIS_FILE, "Test \"%s\" is not found in %s", + argv[i], title)); + } + } + } + + if (ut_app->ntests <= 0) + return PJ_SUCCESS; + + pj_test_runner_param_default(&runner_prm); + runner_prm.stop_on_error = ut_app->prm_stop_on_error; + if (ut_app->prm_nthreads >= 0) + runner_prm.nthreads = ut_app->prm_nthreads; + runner_prm.verbosity = ut_app->verbosity; + status = pj_test_create_text_runner(ut_app->pool, &runner_prm, &runner); + PJ_TEST_SUCCESS(status, "error creating text runner", return status); + + PJ_LOG(3,(THIS_FILE, + "Performing %d %s with %d worker thread%s", + ut_app->ntests, title, runner_prm.nthreads, + runner_prm.nthreads>1?"s":"")); + + pj_test_run(runner, &ut_app->suite); + pj_test_runner_destroy(runner); + pj_test_display_log_messages(&ut_app->suite, ut_app->prm_logging_policy); + pj_test_get_stat(&ut_app->suite, &stat); + pj_test_display_stat(&stat, title, THIS_FILE); + + return stat.nfailed ? PJ_EBUG : PJ_SUCCESS; +} + +PJ_INLINE(void) ut_usage() +{ + puts(" -c, --config Show configuration macros"); + puts(" -l 0,1,2,3 0: Don't show logging after tests"); + puts(" 1: Show logs of only failed tests (default)"); + puts(" 2: Show logs of only successful tests"); + puts(" 3: Show logs of all tests"); + puts(" --log-no-cache Do not cache logging"); + printf(" -w N Set N worker threads (0: disable. Default: %d)\n", + PJ_HAS_THREADS); + puts(" -L, --list List the tests and exit"); + puts(" --stop-err Stop testing on error"); + puts(" --shuffle Shuffle the test order"); + puts(" --seed N Set shuffle random seed (must be >= 0)"); + puts(" --stdout-buf N Set stdout buffering mode:"); + puts(" --stderr-buf N Set stderr buffering mode:"); + puts(" 0: unbufferred (default for stderr)"); + puts(" 1: line"); + puts(" 2: fully bufferred (default for stdout)"); + puts(" -v, --verbose Show info when starting/stopping tests"); +} + + +PJ_INLINE(pj_status_t) ut_parse_args(ut_app_t *ut_app, int *argc, char *argv[]) +{ + int itmp = -1; + pj_status_t status; + + ut_app->prm_config = pj_argparse_get_bool(argc, argv, "-c") || + pj_argparse_get_bool(argc, argv, "--config"); + ut_app->prm_list_test = pj_argparse_get_bool(argc, argv, "-L") || + pj_argparse_get_bool(argc, argv, "--list"); + ut_app->prm_stop_on_error = pj_argparse_get_bool(argc, argv, "--stop-err"); + ut_app->prm_shuffle = pj_argparse_get_bool(argc, argv, "--shuffle"); + if (pj_argparse_get_bool(argc, argv, "--log-no-cache")) { + ut_app->flags |= PJ_TEST_LOG_NO_CACHE; + } + + if (pj_argparse_exists(argv, "-l")) { + status = pj_argparse_get_int(argc, argv, "-l", &itmp); + if (status==PJ_SUCCESS && itmp>=0 && itmp<=3) { + ut_app->prm_logging_policy = (pj_test_select_tests)itmp; + } else { + puts("Error: invalid value for -l option"); + return PJ_EINVAL; + } + } + + if (pj_argparse_exists(argv, "-w")) { + status = pj_argparse_get_int(argc, argv, "-w", &itmp); + if (status==PJ_SUCCESS && itmp>=0 && itmp<50) { + ut_app->prm_nthreads = itmp; + } else { + puts("Error: invalid/missing value for -w option"); + return PJ_EINVAL; + } + } + + if (ut_app->prm_shuffle) { + pj_time_val tv; + + status = pj_gettimeofday(&tv); + if (status != PJ_SUCCESS) + return status; + + ut_app->prm_seed = (int)(tv.msec); + status = pj_argparse_get_int(argc, argv, "--seed", &ut_app->prm_seed); + if (status != PJ_SUCCESS) + return status; + } + + ut_app->verbosity = pj_argparse_get_bool(argc, argv, "-v") || + pj_argparse_get_bool(argc, argv, "--verbose"); + + itmp = -101; + if (pj_argparse_get_int(argc, argv, "--stdout-buf", &itmp)==PJ_SUCCESS && + itmp != -101) + { + switch (itmp) { + case 0: setvbuf(stdout, NULL, _IONBF, 0); break; + case 1: setvbuf(stdout, NULL, _IOLBF, 0); break; + case 2: setvbuf(stdout, NULL, _IOFBF, 0); break; + default: + printf("Error: invalid --stdout-buf value %d\n", itmp); + return PJ_EINVAL; + } + } + + itmp = -101; + if (pj_argparse_get_int(argc, argv, "--stderr-buf", &itmp)==PJ_SUCCESS && + itmp != -101) + { + switch (itmp) { + case 0: setvbuf(stderr, NULL, _IONBF, 0); break; + case 1: setvbuf(stderr, NULL, _IOLBF, 0); break; + case 2: setvbuf(stderr, NULL, _IOFBF, 0); break; + default: + printf("Error: invalid --stderr-buf value %d\n", itmp); + return PJ_EINVAL; + } + } + + return PJ_SUCCESS; +} + +#ifdef UNDEF_THIS_FILE +# undef THIS_FILE +#endif diff --git a/pjlib/src/pjlib-test/thread.c b/pjlib/src/pjlib-test/thread.c index 47867bb8b8..eb996ee99b 100644 --- a/pjlib/src/pjlib-test/thread.c +++ b/pjlib/src/pjlib-test/thread.c @@ -52,6 +52,8 @@ #define THIS_FILE "thread_test" +typedef unsigned long counter_t; +#define counter_fmt "%lu" static volatile int quit_flag=0; #if 0 @@ -74,7 +76,7 @@ static int thread_proc(void *data) pj_thread_t *this_thread; unsigned id; pj_status_t rc; - pj_uint32_t *pcounter = (pj_uint32_t *)data; + counter_t *pcounter = (counter_t *)data; id = *pcounter; PJ_UNUSED_ARG(id); /* Warning about unused var if TRACE__ is disabled */ @@ -105,7 +107,9 @@ static int thread_proc(void *data) for (;!quit_flag;) { (*pcounter)++; //Must sleep if platform doesn't do time-slicing. - //pj_thread_sleep(0); + //2024-12-18: always sleep since otherwise test may occasionaly throw + // error on Linux (bennylp) + pj_thread_sleep(0); } TRACE__((THIS_FILE, " thread %d quitting..", id)); @@ -120,7 +124,7 @@ static int simple_thread(const char *title, unsigned flags) pj_pool_t *pool; pj_thread_t *thread; pj_status_t rc; - pj_uint32_t counter = 0; + counter_t counter = 0; PJ_LOG(3,(THIS_FILE, "..%s", title)); @@ -187,7 +191,7 @@ static int timeslice_test(void) { enum { NUM_THREADS = 4 }; pj_pool_t *pool; - pj_uint32_t counter[NUM_THREADS], lowest, highest, diff; + counter_t counter[NUM_THREADS], lowest, highest, diff; pj_thread_t *thread[NUM_THREADS]; unsigned i; pj_status_t rc; @@ -273,9 +277,8 @@ static int timeslice_test(void) /* Now examine the value of the counters. * Check that all threads had equal proportion of processing. */ - lowest = 0xFFFFFFFF; - highest = 0; - for (i=0; i highest) @@ -295,12 +298,14 @@ static int timeslice_test(void) PJ_LOG(3,(THIS_FILE, "...ERROR: thread didn't have equal timeslice!")); PJ_LOG(3,(THIS_FILE, - ".....lowest counter=%u, highest counter=%u, diff=%u%%", + ".....lowest counter=" counter_fmt + ", highest counter=" counter_fmt + ", diff=" counter_fmt "%%", lowest, highest, diff)); return -80; } else { PJ_LOG(3,(THIS_FILE, - "...info: timeslice diff between lowest & highest=%u%%", + "...info: timeslice diff between lowest & highest=" counter_fmt "%%", diff)); } diff --git a/pjlib/src/pjlib-test/timer.c b/pjlib/src/pjlib-test/timer.c index 7acfefaaf8..2f9b9f597b 100644 --- a/pjlib/src/pjlib-test/timer.c +++ b/pjlib/src/pjlib-test/timer.c @@ -94,8 +94,6 @@ static int test_timer_heap(void) pj_timestamp t1, t2, t_sched, t_cancel, t_poll; pj_time_val now, expire; - pj_gettimeofday(&now); - pj_srand(now.sec); t_sched.u32.lo = t_cancel.u32.lo = t_poll.u32.lo = 0; // Register timers @@ -485,7 +483,6 @@ static int timer_stress_test(void) pj_thread_t **poll_threads = NULL; pj_thread_t **cancel_threads = NULL; struct thread_param tparam = {0}; - pj_time_val now; #if SIMULATE_CRASH pj_timer_entry *entry; pj_pool_t *tmp_pool; @@ -494,9 +491,6 @@ static int timer_stress_test(void) PJ_LOG(3,("test", "...Stress test")); - pj_gettimeofday(&now); - pj_srand(now.sec); - pool = pj_pool_create( mem, NULL, 128, 128, NULL); if (!pool) { PJ_LOG(3,("test", "...error: unable to create pool")); diff --git a/pjmedia/src/test/codec_vectors.c b/pjmedia/src/test/codec_vectors.c index f561354d2d..f5d121f950 100644 --- a/pjmedia/src/test/codec_vectors.c +++ b/pjmedia/src/test/codec_vectors.c @@ -579,7 +579,7 @@ int codec_test_vectors(void) unsigned i; pj_status_t status; - status = pjmedia_endpt_create(mem, NULL, 0, &endpt); + status = pjmedia_endpt_create2(mem, NULL, 0, &endpt); if (status != PJ_SUCCESS) return -5; @@ -588,7 +588,7 @@ int codec_test_vectors(void) #if PJMEDIA_HAS_G7221_CODEC status = pjmedia_codec_g7221_init(endpt); if (status != PJ_SUCCESS) { - pjmedia_endpt_destroy(endpt); + pjmedia_endpt_destroy2(endpt); return -7; } @@ -635,7 +635,7 @@ int codec_test_vectors(void) if (pj_file_exists(TMP_OUT)) pj_file_delete(TMP_OUT); - pjmedia_endpt_destroy(endpt); + pjmedia_endpt_destroy2(endpt); return rc_final; } diff --git a/pjmedia/src/test/jbuf_test.c b/pjmedia/src/test/jbuf_test.c index 82aabf79ad..c8c08e891a 100644 --- a/pjmedia/src/test/jbuf_test.c +++ b/pjmedia/src/test/jbuf_test.c @@ -26,10 +26,12 @@ #define JB_MAX_PREFETCH 10 #define JB_PTIME 20 #define JB_BUF_SIZE 50 +#define THIS_FILE "jbuf_test.c" //#define REPORT //#define PRINT_COMMENT + typedef struct test_param_t { pj_bool_t adaptive; unsigned init_prefetch; @@ -79,10 +81,16 @@ static pj_bool_t parse_test_headers(char *line, test_param_t *param, cond->lost = cond_val; } else if (*p == '=') { + char *newline_pos; + /* Test title. */ ++p; while (*p && isspace(*p)) ++p; - printf("%s", p); + + if ((newline_pos=strchr(p, '\n')) != NULL) + *newline_pos = '\0'; + + PJ_LOG(3, (THIS_FILE, "--- %s ---", p)); } else if (*p == '#') { /* Ignore comment line. */ @@ -121,15 +129,15 @@ static pj_bool_t process_test_data(char data, pjmedia_jbuf *jb, case 'L': /* Lost */ *last_seq = *seq; ++*seq; - printf("Lost\n"); + PJ_LOG(3,(THIS_FILE, "Lost")); break; case 'R': /* Sequence restarts */ *seq = 1; - printf("Sequence restarting, from %u to %u\n", *last_seq, *seq); + PJ_LOG(3,(THIS_FILE, "Sequence restarting, from %u to %u", *last_seq, *seq)); break; case 'J': /* Sequence jumps */ (*seq) += 20; - printf("Sequence jumping, from %u to %u\n", *last_seq, *seq); + PJ_LOG(3,(THIS_FILE, "Sequence jumping, from %u to %u", *last_seq, *seq)); break; case 'D': /* Frame duplicated */ pjmedia_jbuf_put_frame(jb, (void*)frame, 1, *seq - 1); @@ -142,7 +150,7 @@ static pj_bool_t process_test_data(char data, pjmedia_jbuf *jb, break; default: print_state = PJ_FALSE; - printf("Unknown test data '%c'\n", data); + PJ_LOG(3,(THIS_FILE, "Unknown test data '%c'", data)); break; } @@ -154,8 +162,8 @@ static pj_bool_t process_test_data(char data, pjmedia_jbuf *jb, pjmedia_jb_state state; pjmedia_jbuf_get_state(jb, &state); - printf("seq=%d\t%c\tsize=%d\tprefetch=%d\n", - *last_seq, toupper(data), state.size, state.prefetch); + PJ_LOG(3,(THIS_FILE, ("seq=%d\t%c\tsize=%d\tprefetch=%d", + *last_seq, toupper(data), state.size, state.prefetch)); } #else PJ_UNUSED_ARG(print_state); /* Warning about variable set but unused */ @@ -164,7 +172,7 @@ static pj_bool_t process_test_data(char data, pjmedia_jbuf *jb, return PJ_TRUE; } -int jbuf_main(void) +int jbuf_test(void) { FILE *input; pj_bool_t data_eof = PJ_FALSE; @@ -194,10 +202,8 @@ int jbuf_main(void) } /* Failed to open test data file. */ - if (input == NULL) { - printf("Failed to open test data file, Jbtest.dat\n"); - return -1; - } + PJ_TEST_NOT_NULL(input, "failed to open test data file, Jbtest.dat", + return -1); old_log_level = pj_log_get_level(); pj_log_set_level(5); @@ -226,7 +232,7 @@ int jbuf_main(void) cond.empty = -1; cond.lost = -1; - printf("\n\n"); + PJ_LOG(3,(THIS_FILE, "%s", "")); /* Parse test session title, param, and conditions */ do { @@ -237,8 +243,6 @@ int jbuf_main(void) if (p == NULL) break; - //printf("======================================================\n"); - /* Initialize test session */ pool = pj_pool_create(mem, "JBPOOL", 256*16, 256*16, NULL); pjmedia_jbuf_create(pool, &jb_name, 1, JB_PTIME, JB_BUF_SIZE, &jb); @@ -255,9 +259,9 @@ int jbuf_main(void) #ifdef REPORT pjmedia_jbuf_get_state(jb, &state); - printf("Initial\tsize=%d\tprefetch=%d\tmin.pftch=%d\tmax.pftch=%d\n", - state.size, state.prefetch, state.min_prefetch, - state.max_prefetch); + PJ_LOG(3,(THIS_FILE, (("Initial\tsize=%d\tprefetch=%d\tmin.pftch=%d\tmax.pftch=%d", + state.size, state.prefetch, state.min_prefetch, + state.max_prefetch)); #endif @@ -285,7 +289,7 @@ int jbuf_main(void) if (c == '#') { #ifdef PRINT_COMMENT while (*p && isspace(*p)) ++p; - if (*p) printf("..%s", p); + if (*p) printf(("..%s", p)); #endif *p = 0; continue; @@ -298,44 +302,44 @@ int jbuf_main(void) /* Print JB states */ pjmedia_jbuf_get_state(jb, &state); - printf("------------------------------------------------------\n"); - printf("Summary:\n"); - printf(" size=%d prefetch=%d\n", state.size, state.prefetch); - printf(" delay (min/max/avg/dev)=%d/%d/%d/%d ms\n", - state.min_delay, state.max_delay, state.avg_delay, - state.dev_delay); - printf(" lost=%d discard=%d empty=%d burst(avg)=%d\n", - state.lost, state.discard, state.empty, state.avg_burst); + //PJ_LOG(3,(THIS_FILE, "------------------------------------------------------")); + PJ_LOG(3,(THIS_FILE, "Summary:")); + PJ_LOG(3,(THIS_FILE, " size=%d prefetch=%d", state.size, state.prefetch)); + PJ_LOG(3,(THIS_FILE, " delay (min/max/avg/dev)=%d/%d/%d/%d ms", + state.min_delay, state.max_delay, state.avg_delay, + state.dev_delay)); + PJ_LOG(3,(THIS_FILE, " lost=%d discard=%d empty=%d burst(avg)=%d", + state.lost, state.discard, state.empty, state.avg_burst)); /* Evaluate test session */ if (cond.burst >= 0 && (int)state.avg_burst > cond.burst) { - printf("! 'Burst' should be %d, it is %d\n", - cond.burst, state.avg_burst); + PJ_LOG(1,(THIS_FILE, "! 'Burst' should be %d, it is %d", + cond.burst, state.avg_burst)); rc |= 1; } if (cond.delay >= 0 && (int)state.avg_delay/JB_PTIME > cond.delay) { - printf("! 'Delay' should be %d, it is %d\n", - cond.delay, state.avg_delay/JB_PTIME); + PJ_LOG(1,(THIS_FILE, "! 'Delay' should be %d, it is %d", + cond.delay, state.avg_delay/JB_PTIME)); rc |= 2; } if (cond.delay_min >= 0 && (int)state.min_delay/JB_PTIME > cond.delay_min) { - printf("! 'Minimum delay' should be %d, it is %d\n", - cond.delay_min, state.min_delay/JB_PTIME); + PJ_LOG(1,(THIS_FILE, "! 'Minimum delay' should be %d, it is %d", + cond.delay_min, state.min_delay/JB_PTIME)); rc |= 32; } if (cond.discard >= 0 && (int)state.discard > cond.discard) { - printf("! 'Discard' should be %d, it is %d\n", - cond.discard, state.discard); + PJ_LOG(3,(THIS_FILE, "! 'Discard' should be %d, it is %d", + cond.discard, state.discard)); rc |= 4; } if (cond.empty >= 0 && (int)state.empty > cond.empty) { - printf("! 'Empty' should be %d, it is %d\n", - cond.empty, state.empty); + PJ_LOG(3,(THIS_FILE, "! 'Empty' should be %d, it is %d", + cond.empty, state.empty)); rc |= 8; } if (cond.lost >= 0 && (int)state.lost > cond.lost) { - printf("! 'Lost' should be %d, it is %d\n", - cond.lost, state.lost); + PJ_LOG(3,(THIS_FILE, "! 'Lost' should be %d, it is %d", + cond.lost, state.lost)); rc |= 16; } diff --git a/pjmedia/src/test/main.c b/pjmedia/src/test/main.c index 77b49700cf..f0ee9ca799 100644 --- a/pjmedia/src/test/main.c +++ b/pjmedia/src/test/main.c @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #include "test.h" @@ -33,19 +34,19 @@ #if (PJ_LINUX || PJ_DARWINOS) && defined(PJ_HAS_EXECINFO_H) && PJ_HAS_EXECINFO_H != 0 -#include +#include #include -#include -#include -#include +#include +#include +#include static void print_stack(int sig) { - void *array[16]; - size_t size; - - size = backtrace(array, 16); - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); + void *array[16]; + size_t size; + + size = backtrace(array, 16); + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, STDERR_FILENO); exit(1); } @@ -59,6 +60,21 @@ static void init_signals(void) #define init_signals() #endif +static void usage() +{ + puts("Usage:"); + puts(" pjmedia-test [OPTIONS] [test_to_run] [test to run] [..]"); + puts(""); + puts("where OPTIONS:"); + puts(""); + puts(" -h, --help Show this help screen"); + + ut_usage(); + + puts(" -i Ask ENTER before quitting"); + puts(" -n Do not trap signals"); +} + static int main_func(int argc, char *argv[]) { @@ -66,22 +82,25 @@ static int main_func(int argc, char *argv[]) int interractive = 0; int no_trap = 0; - while (argc > 1) { - char *arg = argv[--argc]; + if (pj_argparse_get_bool(&argc, argv, "-h") || + pj_argparse_get_bool(&argc, argv, "--help")) + { + usage(); + return 0; + } - if (*arg=='-' && *(arg+1)=='i') { - interractive = 1; + ut_app_init0(&test_app.ut_app); - } else if (*arg=='-' && *(arg+1)=='n') { - no_trap = 1; - } - } + interractive = pj_argparse_get_bool(&argc, argv, "-i"); + no_trap = pj_argparse_get_bool(&argc, argv, "-n"); + if (ut_parse_args(&test_app.ut_app, &argc, argv)) + return 1; if (!no_trap) { init_signals(); } - rc = test_main(); + rc = test_main(argc, argv); if (interractive) { char s[10]; diff --git a/pjmedia/src/test/mips_test.c b/pjmedia/src/test/mips_test.c index 25f89bfcbe..69391787b1 100644 --- a/pjmedia/src/test/mips_test.c +++ b/pjmedia/src/test/mips_test.c @@ -731,7 +731,7 @@ static pj_status_t codec_on_destroy(struct pjmedia_port *this_port) pjmedia_codec_mgr_dealloc_codec(pjmedia_endpt_get_codec_mgr(cp->endpt), cp->codec); cp->codec_deinit(); - pjmedia_endpt_destroy(cp->endpt); + pjmedia_endpt_destroy2(cp->endpt); return PJ_SUCCESS; } @@ -764,7 +764,7 @@ static pjmedia_port* codec_encode_decode( pj_pool_t *pool, cp->base.on_destroy = &codec_on_destroy; cp->codec_deinit = codec_deinit; - status = pjmedia_endpt_create(mem, NULL, 0, &cp->endpt); + status = pjmedia_endpt_create2(mem, NULL, 0, &cp->endpt); if (status != PJ_SUCCESS) return NULL; @@ -1699,7 +1699,7 @@ static void stream_port_custom_deinit(struct test_entry *te) pjmedia_stream_destroy(sp->stream); pjmedia_transport_close(sp->transport); sp->codec_deinit(); - pjmedia_endpt_destroy(sp->endpt); + pjmedia_endpt_destroy2(sp->endpt); } @@ -1743,7 +1743,7 @@ static pjmedia_port* create_stream( pj_pool_t *pool, te->custom_deinit = &stream_port_custom_deinit; sp->codec_deinit = codec_deinit; - status = pjmedia_endpt_create(mem, NULL, 0, &sp->endpt); + status = pjmedia_endpt_create2(mem, NULL, 0, &sp->endpt); if (status != PJ_SUCCESS) return NULL; diff --git a/pjmedia/src/test/test.c b/pjmedia/src/test/test.c index 5023bdf6f0..a7eb075851 100644 --- a/pjmedia/src/test/test.c +++ b/pjmedia/src/test/test.c @@ -20,17 +20,8 @@ #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) - - pj_pool_factory *mem; +struct test_app_t test_app; void app_perror(pj_status_t status, const char *msg) @@ -53,15 +44,21 @@ void *dummy() } #endif -int test_main(void) +int test_main(int argc, char *argv[]) { int rc = 0; pj_caching_pool caching_pool; - pj_pool_t *pool; + pj_pool_t *pool = NULL; + + PJ_TEST_SUCCESS(pj_init(), NULL, return 1); + + if (test_app.ut_app.prm_config) + pj_dump_config(); - pj_init(); pj_caching_pool_init(&caching_pool, &pj_pool_factory_default_policy, 0); - pool = pj_pool_create(&caching_pool.factory, "test", 1000, 512, NULL); + PJ_TEST_NOT_NULL(pool=pj_pool_create(&caching_pool.factory, "test", + 1000, 512, NULL), + NULL, {rc=10; goto on_return;}); pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_INDENT); @@ -69,43 +66,59 @@ int test_main(void) mem = &caching_pool.factory; - pjmedia_event_mgr_create(pool, 0, NULL); + PJ_TEST_SUCCESS(pjmedia_event_mgr_create(pool, 0, NULL), + NULL, {rc=30; goto on_return;}); #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) - pjmedia_video_format_mgr_create(pool, 64, 0, NULL); - pjmedia_converter_mgr_create(pool, NULL); - pjmedia_vid_codec_mgr_create(pool, NULL); + PJ_TEST_SUCCESS(pjmedia_video_format_mgr_create(pool, 64, 0, NULL), + NULL, {rc=50; goto on_return;}); + PJ_TEST_SUCCESS(pjmedia_converter_mgr_create(pool, NULL), + NULL, {rc=60; goto on_return;}); + PJ_TEST_SUCCESS(pjmedia_vid_codec_mgr_create(pool, NULL), + NULL, {rc=70; goto on_return;}); #endif -#if HAS_VID_PORT_TEST - DO_TEST(vid_port_test()); -#endif + PJ_TEST_SUCCESS(ut_app_init1(&test_app.ut_app, mem), + NULL, {rc=40; goto on_return;}); -#if HAS_VID_DEV_TEST - DO_TEST(vid_dev_test()); +#if HAS_MIPS_TEST + /* Run in exclusive mode to get the best performance */ + UT_ADD_TEST(&test_app.ut_app, mips_test, PJ_TEST_EXCLUSIVE); #endif #if HAS_VID_CODEC_TEST - DO_TEST(vid_codec_test()); + /* Run in exclusive mode due to device sharing error? */ + UT_ADD_TEST(&test_app.ut_app, vid_codec_test, PJ_TEST_EXCLUSIVE); +#endif + +#if HAS_VID_PORT_TEST + UT_ADD_TEST(&test_app.ut_app, vid_port_test, 0); +#endif + +#if HAS_VID_DEV_TEST + UT_ADD_TEST(&test_app.ut_app, vid_dev_test, 0); #endif #if HAS_SDP_NEG_TEST - DO_TEST(sdp_neg_test()); + UT_ADD_TEST(&test_app.ut_app, sdp_neg_test, 0); #endif //DO_TEST(sdp_test (&caching_pool.factory)); //DO_TEST(rtp_test(&caching_pool.factory)); //DO_TEST(session_test (&caching_pool.factory)); #if HAS_JBUF_TEST - DO_TEST(jbuf_main()); -#endif -#if HAS_MIPS_TEST - DO_TEST(mips_test()); + UT_ADD_TEST(&test_app.ut_app, jbuf_test, 0); #endif #if HAS_CODEC_VECTOR_TEST - DO_TEST(codec_test_vectors()); + UT_ADD_TEST(&test_app.ut_app, codec_test_vectors, 0); #endif - PJ_LOG(3,(THIS_FILE," ")); + if (ut_run_tests(&test_app.ut_app, "pjmedia tests", argc, argv)) { + rc = 99; + } else { + rc = 0; + } + + ut_app_destroy(&test_app.ut_app); on_return: if (rc != 0) { @@ -121,8 +134,8 @@ int test_main(void) #endif pjmedia_event_mgr_destroy(pjmedia_event_mgr_instance()); - - pj_pool_release(pool); + if (pool) + pj_pool_release(pool); pj_caching_pool_destroy(&caching_pool); return rc; diff --git a/pjmedia/src/test/test.h b/pjmedia/src/test/test.h index a4d2b48dcc..848ae97eda 100644 --- a/pjmedia/src/test/test.h +++ b/pjmedia/src/test/test.h @@ -41,7 +41,7 @@ int session_test(void); int rtp_test(void); int sdp_test(void); -int jbuf_main(void); +int jbuf_test(void); int sdp_neg_test(void); int mips_test(void); int codec_test_vectors(void); @@ -52,6 +52,16 @@ int vid_port_test(void); extern pj_pool_factory *mem; void app_perror(pj_status_t status, const char *title); -int test_main(void); +int test_main(int argc, char *argv[]); + +#define UT_MAX_TESTS 80 +#include "../../../pjlib/src/pjlib-test/test_util.h" + +struct test_app_t +{ + ut_app_t ut_app; +}; +extern struct test_app_t test_app; + #endif /* __PJMEDIA_TEST_H__ */ diff --git a/pjmedia/src/test/vid_codec_test.c b/pjmedia/src/test/vid_codec_test.c index 286f2f96b0..4d2c2402df 100644 --- a/pjmedia/src/test/vid_codec_test.c +++ b/pjmedia/src/test/vid_codec_test.c @@ -200,6 +200,7 @@ static int encode_decode_test(pj_pool_t *pool, const char *codec_id, char codec_name[5]; pj_status_t status; int rc = 0; + unsigned i, count; switch (packing) { case PJMEDIA_VID_PACKING_PACKETS: @@ -268,10 +269,28 @@ static int encode_decode_test(pj_pool_t *pool, const char *codec_id, cap_idx = CAPTURE_DEV; #endif - /* Lookup SDL renderer */ - status = pjmedia_vid_dev_lookup("SDL", "SDL renderer", &rdr_idx); - if (status != PJ_SUCCESS) { - rc = 207; goto on_return; + /* Lookup renderer */ + rdr_idx = PJMEDIA_VID_INVALID_DEV; + count = pjmedia_vid_dev_count(); + for (i = 0; i < count; ++i) { + pjmedia_vid_dev_info cdi; + + status = pjmedia_vid_dev_get_info(i, &cdi); + if (status != PJ_SUCCESS) + rc = 211; goto on_return; + + /* Only interested with render device */ + if ((cdi.dir & PJMEDIA_DIR_RENDER) != 0) { + rdr_idx = i; + break; + } + } + if (rdr_idx == PJMEDIA_VID_INVALID_DEV) { + PJ_LOG(3, (THIS_FILE, "Unable to find renderer device")); + /* We may be on a machine that doesn't have access to a renderer + * device, don't fail the test. + */ + rc = 0; goto on_return; } /* Prepare codec */ diff --git a/pjnath/src/pjnath-test/concur_test.c b/pjnath/src/pjnath-test/concur_test.c index 54ddb7b6c7..31d575f5f9 100644 --- a/pjnath/src/pjnath-test/concur_test.c +++ b/pjnath/src/pjnath-test/concur_test.c @@ -226,14 +226,14 @@ static int stun_destroy_test_session(struct stun_test_session *test_sess) static int stun_destroy_test(void) { - enum { LOOP = 500 }; +#define ERR(errval) { rc=errval; goto on_return; } + enum { LOOP = 10 }; struct stun_test_session test_sess; pj_sockaddr bind_addr; int addr_len; pj_caching_pool cp; pj_pool_t *pool; unsigned i; - pj_status_t status; int rc = 0; PJ_LOG(3,(THIS_FILE, " STUN destroy concurrency test")); @@ -241,53 +241,61 @@ static int stun_destroy_test(void) pj_bzero(&test_sess, sizeof(test_sess)); pj_caching_pool_init(&cp, NULL, 0); - pool = pj_pool_create(&cp.factory, "testsess", 512, 512, NULL); + PJ_TEST_NOT_NULL((pool=pj_pool_create(&cp.factory, "testsess", + 512, 512, NULL)), NULL, ERR(-10)); pj_stun_config_init(&test_sess.stun_cfg, &cp.factory, 0, NULL, NULL); - status = pj_timer_heap_create(pool, 1023, &test_sess.stun_cfg.timer_heap); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_timer_heap_create(pool, 1023, + &test_sess.stun_cfg.timer_heap), + NULL, ERR(-20)); - status = pj_lock_create_recursive_mutex(pool, NULL, &test_sess.lock); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_lock_create_recursive_mutex(pool, NULL, + &test_sess.lock), + NULL, ERR(-30)); - pj_timer_heap_set_lock(test_sess.stun_cfg.timer_heap, test_sess.lock, PJ_TRUE); - pj_assert(status == PJ_SUCCESS); + pj_timer_heap_set_lock(test_sess.stun_cfg.timer_heap, test_sess.lock, + PJ_TRUE); - status = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &test_sess.stun_cfg.ioqueue); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, + &test_sess.stun_cfg.ioqueue), + NULL, ERR(-40)); - pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &test_sess.server_sock); + PJ_TEST_SUCCESS(pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, + &test_sess.server_sock), + NULL, ERR(-50)); pj_sockaddr_init(pj_AF_INET(), &bind_addr, NULL, 0); - status = pj_sock_bind(test_sess.server_sock, &bind_addr, pj_sockaddr_get_len(&bind_addr)); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_sock_bind(test_sess.server_sock, &bind_addr, + pj_sockaddr_get_len(&bind_addr)), + NULL, ERR(-60)); /* Set socket to nonblocking to avoid stuck in recv/recvfrom() on concurrent events */ app_set_sock_nb(test_sess.server_sock); addr_len = sizeof(bind_addr); - status = pj_sock_getsockname(test_sess.server_sock, &bind_addr, &addr_len); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_sock_getsockname(test_sess.server_sock, &bind_addr, + &addr_len), + NULL, ERR(-70)); test_sess.server_port = pj_sockaddr_get_port(&bind_addr); - status = pj_event_create(pool, NULL, PJ_TRUE, PJ_FALSE, &test_sess.server_event); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pj_event_create(pool, NULL, PJ_TRUE, PJ_FALSE, + &test_sess.server_event), + NULL, ERR(-80)); for (i=0; icfg.enable_stun & YES) { unsigned stun_idx = ice_cfg->stun_tp_cnt++; @@ -168,7 +173,7 @@ static void set_stun_turn_cfg(struct ice_ept *ept, } else { ice_cfg->stun_tp[stun_idx].server = pj_str(serverip); } - ice_cfg->stun_tp[stun_idx].port = STUN_SERVER_PORT; + ice_cfg->stun_tp[stun_idx].port = stun_server_port; ice_cfg->stun_tp[stun_idx].af = GET_AF(use_ipv6); } @@ -189,7 +194,7 @@ static void set_stun_turn_cfg(struct ice_ept *ept, } else { ice_cfg->turn_tp[turn_idx].server = pj_str(serverip); } - ice_cfg->turn_tp[turn_idx].port = TURN_SERVER_PORT; + ice_cfg->turn_tp[turn_idx].port = turn_server_port; ice_cfg->turn_tp[turn_idx].conn_type = PJ_TURN_TP_UDP; ice_cfg->turn_tp[turn_idx].auth_cred.type = PJ_STUN_AUTH_CRED_STATIC; ice_cfg->turn_tp[turn_idx].auth_cred.data.static_cred.realm = @@ -221,19 +226,15 @@ static int create_ice_strans(struct test_sess *test_sess, pj_sockaddr hostip; char serveripv4[PJ_INET6_ADDRSTRLEN]; char serveripv6[PJ_INET6_ADDRSTRLEN]; - pj_status_t status; unsigned flag = (ept->cfg.client_flag)?ept->cfg.client_flag:CLIENT_IPV4; - status = pj_gethostip(pj_AF_INET(), &hostip); - if (status != PJ_SUCCESS) - return -1030; + PJ_TEST_SUCCESS(pj_gethostip(pj_AF_INET(), &hostip), NULL, return -1030); pj_sockaddr_print(&hostip, serveripv4, sizeof(serveripv4), 0); if (flag & CLIENT_IPV6) { - status = pj_gethostip(pj_AF_INET6(), &hostip); - if (status != PJ_SUCCESS) - return -1031; + PJ_TEST_SUCCESS(pj_gethostip(pj_AF_INET6(), &hostip), + NULL, return -1031); pj_sockaddr_print(&hostip, serveripv6, sizeof(serveripv6), 0); } @@ -251,29 +252,35 @@ static int create_ice_strans(struct test_sess *test_sess, if ((ept->cfg.enable_stun & SRV)==SRV || (ept->cfg.enable_turn & SRV)==SRV) ice_cfg.resolver = test_sess->resolver; + /* Assertion in pj_stun_sock_start() if default_port is zero*/ +#define OR(val1,val2) (val1? val1 : val2) + if (flag & CLIENT_IPV4) { - set_stun_turn_cfg(ept, &ice_cfg, serveripv4, PJ_FALSE); + set_stun_turn_cfg(ept, &ice_cfg, serveripv4, + OR(test_sess->server1->stun_server_port, STUN_RANDOM_PORT), + OR(test_sess->server1->turn_server_port, TURN_RANDOM_PORT), + PJ_FALSE); } if (flag & CLIENT_IPV6) { - set_stun_turn_cfg(ept, &ice_cfg, serveripv6, PJ_TRUE); + set_stun_turn_cfg(ept, &ice_cfg, serveripv6, + OR(test_sess->server2->stun_server_port, STUN_RANDOM_PORT), + OR(test_sess->server2->turn_server_port, TURN_RANDOM_PORT), + PJ_TRUE); } +#undef OR /* Create ICE stream transport */ - status = pj_ice_strans_create(NULL, &ice_cfg, ept->cfg.comp_cnt, - (void*)ept, &ice_cb, - &ice); - if (status != PJ_SUCCESS) { - app_perror(INDENT "err: pj_ice_strans_create()", status); - return status; - } + PJ_TEST_SUCCESS(pj_ice_strans_create(NULL, &ice_cfg, ept->cfg.comp_cnt, + (void*)ept, &ice_cb, &ice), + NULL, return -1040); pj_create_unique_string(test_sess->pool, &ept->ufrag); pj_create_unique_string(test_sess->pool, &ept->pass); /* Looks alright */ *p_ice = ice; - return PJ_SUCCESS; + return 0; } /* Create test session */ @@ -289,10 +296,10 @@ static int create_sess(pj_stun_config *stun_cfg, pj_str_t ns_ip; pj_uint16_t ns_port; unsigned flags; - pj_status_t status = PJ_SUCCESS; + int rc; /* Create session structure */ - pool = pj_pool_create(mem, "testsess", 512, 512, NULL); + pool = pj_pool_create(stun_cfg->pf, "testsess", 512, 512, NULL); sess = PJ_POOL_ZALLOC_T(pool, struct test_sess); sess->pool = pool; sess->stun_cfg = stun_cfg; @@ -307,20 +314,17 @@ static int create_sess(pj_stun_config *stun_cfg, /* Create server */ flags = server_flag; if (flags & SERVER_IPV4) { - status = create_test_server(stun_cfg, (flags & ~SERVER_IPV6), - SRV_DOMAIN, &sess->server1); + PJ_TEST_SUCCESS(create_test_server(stun_cfg, (flags & ~SERVER_IPV6), + SRV_DOMAIN, &sess->server1), + NULL, { destroy_sess(sess, 500); return -10; }); } - if ((status == PJ_SUCCESS) && (flags & SERVER_IPV6)) { - status = create_test_server(stun_cfg, (flags & ~SERVER_IPV4), - SRV_DOMAIN, &sess->server2); + if (flags & SERVER_IPV6) { + PJ_TEST_SUCCESS(create_test_server(stun_cfg, (flags & ~SERVER_IPV4), + SRV_DOMAIN, &sess->server2), + NULL, { destroy_sess(sess, 500); return -11; }); } - if (status != PJ_SUCCESS) { - app_perror(INDENT "error: create_test_server()", status); - destroy_sess(sess, 500); - return -10; - } if (flags & SERVER_IPV4) { sess->server1->turn_respond_allocate = sess->server1->turn_respond_refresh = PJ_TRUE; @@ -337,36 +341,37 @@ static int create_sess(pj_stun_config *stun_cfg, (sess->caller.cfg.enable_stun & SRV)==SRV || (sess->caller.cfg.enable_turn & SRV)==SRV) { - status = pj_dns_resolver_create(mem, NULL, 0, stun_cfg->timer_heap, - stun_cfg->ioqueue, &sess->resolver); - if (status != PJ_SUCCESS) { - app_perror(INDENT "error: pj_dns_resolver_create()", status); - destroy_sess(sess, 500); - return -20; + PJ_TEST_SUCCESS(pj_dns_resolver_create(stun_cfg->pf, NULL, 0, + stun_cfg->timer_heap, + stun_cfg->ioqueue, + &sess->resolver), + NULL, { destroy_sess(sess, 500); return -20; }); + + if (flags & SERVER_IPV6) { + ns_ip = pj_str("::1"); + ns_port = sess->server2->dns_server_port; + } else { + ns_ip = pj_str("127.0.0.1"); + ns_port = sess->server1->dns_server_port; } - ns_ip = (flags & SERVER_IPV6)?pj_str("::1"):pj_str("127.0.0.1"); - ns_port = (pj_uint16_t)DNS_SERVER_PORT; - status = pj_dns_resolver_set_ns(sess->resolver, 1, &ns_ip, &ns_port); - if (status != PJ_SUCCESS) { - app_perror(INDENT "error: pj_dns_resolver_set_ns()", status); - destroy_sess(sess, 500); - return -21; - } + PJ_TEST_SUCCESS(pj_dns_resolver_set_ns(sess->resolver, 1, &ns_ip, + &ns_port), + NULL, { destroy_sess(sess, 500); return -21; }); } /* Create caller ICE stream transport */ - status = create_ice_strans(sess, &sess->caller, &sess->caller.ice); - if (status != PJ_SUCCESS) { + rc = create_ice_strans(sess, &sess->caller, &sess->caller.ice); + if (rc != 0) { destroy_sess(sess, 500); - return -30; + return rc; } /* Create callee ICE stream transport */ - status = create_ice_strans(sess, &sess->callee, &sess->callee.ice); - if (status != PJ_SUCCESS) { + rc = create_ice_strans(sess, &sess->callee, &sess->callee.ice); + if (rc != 0) { destroy_sess(sess, 500); - return -40; + return rc; } *p_sess = sess; @@ -502,22 +507,18 @@ static pj_status_t start_ice(struct ice_ept *ept, const struct ice_ept *remote) unsigned i; for (i=0; icfg.comp_cnt; ++i) { unsigned cnt = PJ_ARRAY_SIZE(rcand) - rcand_cnt; - status = pj_ice_strans_enum_cands(remote->ice, i+1, &cnt, rcand+rcand_cnt); - if (status != PJ_SUCCESS) { - app_perror(INDENT "err: pj_ice_strans_enum_cands()", status); - return status; - } + PJ_TEST_SUCCESS((status=pj_ice_strans_enum_cands(remote->ice, i+1, &cnt, + rcand+rcand_cnt)), + NULL, return status); rcand_cnt += cnt; } } - status = pj_ice_strans_start_ice(ept->ice, &remote->ufrag, &remote->pass, - rcand_cnt, rcand); - - if (status != ept->cfg.expected.start_status) { - app_perror(INDENT "err: pj_ice_strans_start_ice()", status); - return status; - } + PJ_TEST_EQ((status=pj_ice_strans_start_ice(ept->ice, &remote->ufrag, + &remote->pass, + rcand_cnt, rcand)), + ept->cfg.expected.start_status, NULL, + {return status==PJ_SUCCESS? PJ_EINVALIDOP : status; }); return status; } @@ -688,7 +689,7 @@ static int perform_test2(const char *title, if (rc != PJ_SUCCESS) { app_perror(INDENT "err: caller pj_ice_strans_init_ice()", rc); destroy_sess(sess, 500); - return -100; + return -106; } /* Init ICE on callee */ @@ -902,10 +903,10 @@ static int perform_test(const char *title, #define ROLE1 PJ_ICE_SESS_ROLE_CONTROLLED #define ROLE2 PJ_ICE_SESS_ROLE_CONTROLLING -int ice_test(void) +int ice_test(void *p) { - pj_pool_t *pool; - pj_stun_config stun_cfg; + unsigned test_id = (unsigned)(long)p; + app_sess_t app_sess; unsigned i; int rc; struct sess_cfg_t { @@ -913,7 +914,7 @@ int ice_test(void) unsigned server_flag; struct test_cfg ua1; struct test_cfg ua2; - } sess_cfg[] = + } sess_cfg[ICE_TEST_ARRAY_COUNT] = { /* Role comp# host? stun? turn? flag? ans_del snd_del des_del */ { @@ -954,15 +955,14 @@ int ice_test(void) }, }; - pool = pj_pool_create(mem, NULL, 512, 512, NULL); - rc = create_stun_config(pool, &stun_cfg); - if (rc != PJ_SUCCESS) { - pj_pool_release(pool); + assert(test_id < ICE_TEST_START_ARRAY+PJ_ARRAY_SIZE(sess_cfg)); + + rc = create_stun_config(&app_sess); + if (rc != PJ_SUCCESS) return -7; - } /* Simple test first with host candidate */ - if (1) { + if (test_id==ICE_TEST_BASIC_HOST) { struct sess_cfg_t cfg = { "Basic with host candidates", @@ -972,7 +972,7 @@ int ice_test(void) {ROLE2, 1, YES, NO, NO, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS, PJ_SUCCESS}} }; - rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, + rc = perform_test(cfg.title, &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; @@ -980,14 +980,14 @@ int ice_test(void) cfg.ua1.comp_cnt = 2; cfg.ua2.comp_cnt = 2; rc = perform_test("Basic with host candidates, 2 components", - &stun_cfg, cfg.server_flag, + &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; } /* Simple test first with srflx candidate */ - if (1) { + if (test_id==ICE_TEST_BASIC_SRFLX) { struct sess_cfg_t cfg = { "Basic with srflx candidates", @@ -997,7 +997,7 @@ int ice_test(void) {ROLE2, 1, YES, YES, NO, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS, PJ_SUCCESS}} }; - rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, + rc = perform_test(cfg.title, &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; @@ -1006,14 +1006,14 @@ int ice_test(void) cfg.ua2.comp_cnt = 2; rc = perform_test("Basic with srflx candidates, 2 components", - &stun_cfg, cfg.server_flag, + &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; } /* Simple test with relay candidate */ - if (1) { + if (test_id==ICE_TEST_BASIC_RELAY) { struct sess_cfg_t cfg = { "Basic with relay candidates", @@ -1023,7 +1023,7 @@ int ice_test(void) {ROLE2, 1, NO, NO, YES, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS, PJ_SUCCESS}} }; - rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, + rc = perform_test(cfg.title, &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; @@ -1032,14 +1032,14 @@ int ice_test(void) cfg.ua2.comp_cnt = 2; rc = perform_test("Basic with relay candidates, 2 components", - &stun_cfg, cfg.server_flag, + &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; } /* Failure test with STUN resolution */ - if (1) { + if (test_id==ICE_TEST_STUN_RES_FAIL) { struct sess_cfg_t cfg = { "STUN resolution failure", @@ -1049,7 +1049,7 @@ int ice_test(void) {ROLE2, 2, NO, YES, NO, 0, 0, 0, 0, {PJ_SUCCESS, PJNATH_ESTUNTIMEDOUT, -1}} }; - rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, + rc = perform_test(cfg.title, &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; @@ -1058,14 +1058,14 @@ int ice_test(void) cfg.ua2.client_flag |= DEL_ON_ERR; rc = perform_test("STUN resolution failure with destroy on callback", - &stun_cfg, cfg.server_flag, + &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; } /* Failure test with TURN resolution */ - if (1) { + if (test_id==ICE_TEST_TURN_ALLOC_FAIL) { struct sess_cfg_t cfg = { "TURN allocation failure", @@ -1075,7 +1075,7 @@ int ice_test(void) {ROLE2, 2, NO, NO, YES, WRONG_TURN, 0, 0, 0, {PJ_SUCCESS, PJ_STATUS_FROM_STUN_CODE(401), -1}} }; - rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, + rc = perform_test(cfg.title, &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; @@ -1084,7 +1084,7 @@ int ice_test(void) cfg.ua2.client_flag |= DEL_ON_ERR; rc = perform_test("TURN allocation failure with destroy on callback", - &stun_cfg, cfg.server_flag, + &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; @@ -1092,7 +1092,7 @@ int ice_test(void) /* STUN failure, testing TURN deallocation */ - if (1) { + if (test_id==ICE_TEST_STUN_FAIL_TURN_DEALLOC) { struct sess_cfg_t cfg = { "STUN failure, testing TURN deallocation", @@ -1102,7 +1102,7 @@ int ice_test(void) {ROLE2, 1, YES, YES, YES, 0, 0, 0, 0, {PJ_SUCCESS, PJNATH_ESTUNTIMEDOUT, -1}} }; - rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, + rc = perform_test(cfg.title, &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; @@ -1111,15 +1111,15 @@ int ice_test(void) cfg.ua2.client_flag |= DEL_ON_ERR; rc = perform_test("STUN failure, testing TURN deallocation (cb)", - &stun_cfg, cfg.server_flag, + &app_sess.stun_cfg, cfg.server_flag, &cfg.ua1, &cfg.ua2); if (rc != 0) goto on_return; } rc = 0; - /* Iterate each test item */ - for (i=0; i= ICE_TEST_START_ARRAY) { + i = test_id - ICE_TEST_START_ARRAY; struct sess_cfg_t *cfg = &sess_cfg[i]; unsigned delay[] = { 50, 2000 }; unsigned d; @@ -1166,7 +1166,7 @@ int ice_test(void) delay[d], k1, k2); cfg->ua2.comp_cnt = k2; - rc = perform_test(title, &stun_cfg, cfg->server_flag, + rc = perform_test(title, &app_sess.stun_cfg, cfg->server_flag, &cfg->ua1, &cfg->ua2); if (rc != 0) goto on_return; @@ -1177,8 +1177,7 @@ int ice_test(void) } on_return: - destroy_stun_config(&stun_cfg); - pj_pool_release(pool); + destroy_stun_config(&app_sess); return rc; } @@ -1239,22 +1238,19 @@ int ice_one_conc_test(pj_stun_config *stun_cfg, int err_quit) int ice_conc_test(void) { - const unsigned LOOP = 100; - pj_pool_t *pool; - pj_stun_config stun_cfg; + const unsigned LOOP = 20; + app_sess_t app_sess; unsigned i; int rc; - pool = pj_pool_create(mem, NULL, 512, 512, NULL); - rc = create_stun_config(pool, &stun_cfg); + rc = create_stun_config(&app_sess); if (rc != PJ_SUCCESS) { - pj_pool_release(pool); return -7; } for (i = 0; i < LOOP; i++) { PJ_LOG(3,(THIS_FILE, INDENT "Test %d of %d", i+1, LOOP)); - rc = ice_one_conc_test(&stun_cfg, PJ_TRUE); + rc = ice_one_conc_test(&app_sess.stun_cfg, PJ_TRUE); if (rc) break; } @@ -1263,8 +1259,7 @@ int ice_conc_test(void) goto on_return; on_return: - destroy_stun_config(&stun_cfg); - pj_pool_release(pool); + destroy_stun_config(&app_sess); return rc; } @@ -1531,8 +1526,7 @@ static int perform_trickle_test(const char *title, /* Simple trickle ICE test */ int trickle_ice_test(void) { - pj_pool_t *pool; - pj_stun_config stun_cfg; + app_sess_t app_sess; struct sess_param test_param; unsigned i; int rc; @@ -1569,11 +1563,8 @@ int trickle_ice_test(void) PJ_LOG(3,(THIS_FILE, "Trickle ICE")); pj_log_push_indent(); - pool = pj_pool_create(mem, NULL, 512, 512, NULL); - - rc = create_stun_config(pool, &stun_cfg); + rc = create_stun_config(&app_sess); if (rc != PJ_SUCCESS) { - pj_pool_release(pool); pj_log_pop_indent(); return -10; } @@ -1588,7 +1579,7 @@ int trickle_ice_test(void) cfg[i].ua1.comp_cnt = c1; cfg[i].ua2.comp_cnt = c2; rc = perform_trickle_test(cfg[i].title, - &stun_cfg, + &app_sess.stun_cfg, cfg[i].server_flag, &cfg[i].ua1, &cfg[i].ua2, @@ -1597,8 +1588,7 @@ int trickle_ice_test(void) } } - destroy_stun_config(&stun_cfg); - pj_pool_release(pool); + destroy_stun_config(&app_sess); pj_log_pop_indent(); return rc; diff --git a/pjnath/src/pjnath-test/main.c b/pjnath/src/pjnath-test/main.c index 9ecc43e948..7f184dd568 100644 --- a/pjnath/src/pjnath-test/main.c +++ b/pjnath/src/pjnath-test/main.c @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "test.h" +#include #if defined(PJ_SUNOS) && PJ_SUNOS!=0 @@ -33,19 +34,19 @@ static void init_signals() #elif (PJ_LINUX || PJ_DARWINOS) && defined(PJ_HAS_EXECINFO_H) && PJ_HAS_EXECINFO_H != 0 -#include +#include #include -#include -#include -#include +#include +#include +#include static void print_stack(int sig) { - void *array[16]; - size_t size; - - size = backtrace(array, 16); - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); + void *array[16]; + size_t size; + + size = backtrace(array, 16); + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, STDERR_FILENO); exit(1); } @@ -61,6 +62,21 @@ static void init_signals(void) #define boost() +static void usage() +{ + puts("Usage:"); + puts(" pjnath-test [OPTION] [test_to_run] [..]"); + puts(""); + puts("where OPTIONS:"); + puts(""); + puts(" -h, --help Show this help screen"); + + ut_usage(); + + puts(" -i Ask ENTER before quitting"); + puts(" -n Do not trap signals"); +} + int main(int argc, char *argv[]) { int rc; @@ -69,22 +85,25 @@ int main(int argc, char *argv[]) boost(); - while (argc > 1) { - char *arg = argv[--argc]; + if (pj_argparse_get_bool(&argc, argv, "-h") || + pj_argparse_get_bool(&argc, argv, "--help")) + { + usage(); + return 0; + } - if (*arg=='-' && *(arg+1)=='i') { - interractive = 1; + ut_app_init0(&test_app.ut_app); - } else if (*arg=='-' && *(arg+1)=='n') { - no_trap = 1; - } - } + interractive = pj_argparse_get_bool(&argc, argv, "-i"); + no_trap = pj_argparse_get_bool(&argc, argv, "-n"); + if (ut_parse_args(&test_app.ut_app, &argc, argv)) + return 1; if (!no_trap) { init_signals(); } - rc = test_main(); + rc = test_main(argc, argv); if (interractive) { char s[10]; diff --git a/pjnath/src/pjnath-test/server.c b/pjnath/src/pjnath-test/server.c index 5b6699df4b..4b5d72d41d 100644 --- a/pjnath/src/pjnath-test/server.c +++ b/pjnath/src/pjnath-test/server.c @@ -86,7 +86,7 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, { pj_pool_t *pool; test_server *test_srv; - pj_sockaddr hostip; + pj_sockaddr hostip, bound_addr; char strbuf[100]; pj_status_t status = PJ_EINVAL; pj_bool_t use_ipv6 = flags & SERVER_IPV6; @@ -105,7 +105,7 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, RETURN_ERROR(status); } - pool = pj_pool_create(mem, THIS_FILE, 512, 512, NULL); + pool = pj_pool_create(stun_cfg->pf, THIS_FILE, 512, 512, NULL); test_srv = (test_server*) PJ_POOL_ZALLOC_T(pool, test_server); test_srv->pool = pool; test_srv->flags = flags; @@ -118,14 +118,17 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, pj_ioqueue_op_key_init(&test_srv->send_key, sizeof(test_srv->send_key)); if (flags & CREATE_DNS_SERVER) { - status = pj_dns_server_create(mem, test_srv->stun_cfg->ioqueue, - GET_AF(use_ipv6), DNS_SERVER_PORT, + status = pj_dns_server_create(stun_cfg->pf, test_srv->stun_cfg->ioqueue, + GET_AF(use_ipv6), 0, 0, &test_srv->dns_server); if (status != PJ_SUCCESS) { destroy_test_server(test_srv); RETURN_ERROR(status); } + pj_dns_server_get_addr(test_srv->dns_server, &bound_addr); + test_srv->dns_server_port = pj_sockaddr_get_port(&bound_addr); + /* Add DNS A record for the domain, for fallback */ if (flags & CREATE_A_RECORD_FOR_DOMAIN) { pj_dns_parsed_rr rr; @@ -154,17 +157,18 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, stun_sock_cb.on_data_recvfrom = &stun_on_data_recvfrom; pj_sockaddr_init(GET_AF(use_ipv6), &bound_addr, - NULL, STUN_SERVER_PORT); + NULL, 0); status = pj_activesock_create_udp(pool, &bound_addr, NULL, test_srv->stun_cfg->ioqueue, &stun_sock_cb, test_srv, - &test_srv->stun_sock, NULL); + &test_srv->stun_sock, &bound_addr); if (status != PJ_SUCCESS) { destroy_test_server(test_srv); RETURN_ERROR(status); } + test_srv->stun_server_port = pj_sockaddr_get_port(&bound_addr); status = pj_activesock_start_recvfrom(test_srv->stun_sock, pool, MAX_STUN_PKT, 0); if (status != PJ_SUCCESS) { @@ -187,7 +191,7 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, "stun.%s", domain); pj_strdup2(pool, &target, strbuf); pj_dns_init_srv_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, 0, 0, - STUN_SERVER_PORT, &target); + test_srv->stun_server_port, &target); pj_dns_server_add_rec(test_srv->dns_server, 1, &rr); res_name = target; @@ -208,7 +212,7 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, pj_sockaddr bound_addr; pj_turn_tp_type tp_type = get_turn_tp_type(flags); - pj_sockaddr_init(GET_AF(use_ipv6), &bound_addr, NULL, TURN_SERVER_PORT); + pj_sockaddr_init(GET_AF(use_ipv6), &bound_addr, NULL, 0); if (tp_type == PJ_TURN_TP_UDP) { pj_activesock_cb turn_sock_cb; @@ -219,18 +223,21 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, status = pj_activesock_create_udp(pool, &bound_addr, NULL, test_srv->stun_cfg->ioqueue, &turn_sock_cb, test_srv, - &test_srv->turn_sock, NULL); + &test_srv->turn_sock, + &bound_addr); if (status != PJ_SUCCESS) { destroy_test_server(test_srv); RETURN_ERROR(status); } + test_srv->turn_server_port = pj_sockaddr_get_port(&bound_addr); status = pj_activesock_start_recvfrom(test_srv->turn_sock, pool, MAX_STUN_PKT, 0); } else if (tp_type == PJ_TURN_TP_TCP) { pj_sock_t sock_fd; pj_activesock_cb turn_sock_cb; + int name_len = sizeof(bound_addr); pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb)); turn_sock_cb.on_accept_complete2 = &turn_tcp_on_accept_complete; @@ -271,6 +278,11 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, status = pj_activesock_start_accept(test_srv->turn_sock, pool); + + if (pj_sock_getsockname(sock_fd, &bound_addr, &name_len)==PJ_SUCCESS) { + test_srv->turn_server_port = pj_sockaddr_get_port(&bound_addr); + } + } #if USE_TLS else if (tp_type == PJ_TURN_TP_TLS) { @@ -281,6 +293,7 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, pj_str_t cert_file = pj_str(CERT_FILE); pj_str_t privkey_file = pj_str(CERT_PRIVKEY_FILE); pj_str_t privkey_pass = pj_str(CERT_PRIVKEY_PASS); + pj_ssl_sock_info ssock_info; pj_ssl_sock_param_default(&ssl_param); ssl_param.cb.on_accept_complete2 = &turn_tls_on_accept_complete2; @@ -296,6 +309,7 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, pj_ssl_sock_close(ssock_serv); } +#if (PJ_SSL_SOCK_IMP != PJ_SSL_SOCK_IMP_SCHANNEL) status = pj_ssl_cert_load_from_files(pool, &ca_file, &cert_file, &privkey_file, &privkey_pass, &cert); @@ -303,15 +317,32 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, if (ssock_serv) pj_ssl_sock_close(ssock_serv); } - status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert); if (status != PJ_SUCCESS) { if (ssock_serv) pj_ssl_sock_close(ssock_serv); } +#else + /* Schannel backend currently can only load certificates from + * OS cert store, here we don't load any cert so the SSL socket + * will create & use a self-signed cert. + */ + PJ_UNUSED_ARG(ca_file); + PJ_UNUSED_ARG(cert_file); + PJ_UNUSED_ARG(privkey_file); + PJ_UNUSED_ARG(privkey_pass); +#endif test_srv->ssl_srv_sock = ssock_serv; + status = pj_ssl_sock_start_accept(ssock_serv, pool, &bound_addr, pj_sockaddr_get_len(&bound_addr)); + + /* Can only get local address after start_accept() */ + if (pj_ssl_sock_get_info(ssock_serv, &ssock_info)==PJ_SUCCESS) { + test_srv->turn_server_port = + pj_sockaddr_get_port(&ssock_info.local_addr); + } + } #endif if (status != PJ_SUCCESS) { @@ -346,7 +377,7 @@ pj_status_t create_test_server(pj_stun_config *stun_cfg, "turn.%s", domain); pj_strdup2(pool, &target, strbuf); pj_dns_init_srv_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, 0, 0, - TURN_SERVER_PORT, &target); + test_srv->turn_server_port, &target); pj_dns_server_add_rec(test_srv->dns_server, 1, &rr); res_name = target; diff --git a/pjnath/src/pjnath-test/server.h b/pjnath/src/pjnath-test/server.h index bb9a9baeb3..4cfb52c944 100644 --- a/pjnath/src/pjnath-test/server.h +++ b/pjnath/src/pjnath-test/server.h @@ -23,10 +23,6 @@ #include #include -#define DNS_SERVER_PORT 55533 -#define STUN_SERVER_PORT 33478 -#define TURN_SERVER_PORT 33479 - #define TURN_USERNAME "auser" #define TURN_PASSWD "apass" @@ -81,10 +77,13 @@ struct test_server pj_ioqueue_op_key_t send_key; pj_dns_server *dns_server; + pj_uint16_t dns_server_port; pj_activesock_t *stun_sock; + pj_uint16_t stun_server_port; pj_activesock_t *turn_sock; + pj_uint16_t turn_server_port; pj_ssl_sock_t *ssl_srv_sock; diff --git a/pjnath/src/pjnath-test/stun_sock_test.c b/pjnath/src/pjnath-test/stun_sock_test.c index f44988aee3..8244e22ec0 100644 --- a/pjnath/src/pjnath-test/stun_sock_test.c +++ b/pjnath/src/pjnath-test/stun_sock_test.c @@ -832,53 +832,34 @@ static int keep_alive_test(pj_stun_config *cfg, pj_bool_t use_ipv6) #define DO_TEST(expr) \ - capture_pjlib_state(&stun_cfg, &pjlib_state); \ + capture_pjlib_state(&app_sess.stun_cfg, &pjlib_state); \ ret = expr; \ if (ret != 0) goto on_return; \ - ret = check_pjlib_state(&stun_cfg, &pjlib_state); \ + ret = check_pjlib_state(&app_sess.stun_cfg, &pjlib_state); \ if (ret != 0) goto on_return; int stun_sock_test(void) { struct pjlib_state pjlib_state; - pj_stun_config stun_cfg; - pj_ioqueue_t *ioqueue = NULL; - pj_timer_heap_t *timer_heap = NULL; - pj_pool_t *pool = NULL; + app_sess_t app_sess; pj_status_t status; int ret = 0; - pool = pj_pool_create(mem, NULL, 512, 512, NULL); + status = create_stun_config(&app_sess); + if (status) + return -11; - status = pj_ioqueue_create(pool, 12, &ioqueue); - if (status != PJ_SUCCESS) { - app_perror(" pj_ioqueue_create()", status); - ret = -4; - goto on_return; - } - - status = pj_timer_heap_create(pool, 100, &timer_heap); - if (status != PJ_SUCCESS) { - app_perror(" pj_timer_heap_create()", status); - ret = -8; - goto on_return; - } - - pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap); - - DO_TEST(timeout_test(&stun_cfg, PJ_FALSE, USE_IPV6)); - DO_TEST(timeout_test(&stun_cfg, PJ_TRUE, USE_IPV6)); + DO_TEST(timeout_test(&app_sess.stun_cfg, PJ_FALSE, USE_IPV6)); + DO_TEST(timeout_test(&app_sess.stun_cfg, PJ_TRUE, USE_IPV6)); - DO_TEST(missing_attr_test(&stun_cfg, PJ_FALSE, USE_IPV6)); - DO_TEST(missing_attr_test(&stun_cfg, PJ_TRUE, USE_IPV6)); + DO_TEST(missing_attr_test(&app_sess.stun_cfg, PJ_FALSE, USE_IPV6)); + DO_TEST(missing_attr_test(&app_sess.stun_cfg, PJ_TRUE, USE_IPV6)); - DO_TEST(keep_alive_test(&stun_cfg, USE_IPV6)); + DO_TEST(keep_alive_test(&app_sess.stun_cfg, USE_IPV6)); on_return: - if (timer_heap) pj_timer_heap_destroy(timer_heap); - if (ioqueue) pj_ioqueue_destroy(ioqueue); - if (pool) pj_pool_release(pool); + destroy_stun_config(&app_sess); return ret; } diff --git a/pjnath/src/pjnath-test/test.c b/pjnath/src/pjnath-test/test.c index 8626ac80d9..41130524fb 100644 --- a/pjnath/src/pjnath-test/test.c +++ b/pjnath/src/pjnath-test/test.c @@ -20,6 +20,8 @@ #include #include +#define THIS_FILE "test.c" + void app_perror_dbg(const char *msg, pj_status_t rc, const char *file, int line) { @@ -46,44 +48,63 @@ void app_set_sock_nb(pj_sock_t sock) #endif } -pj_status_t create_stun_config(pj_pool_t *pool, pj_stun_config *stun_cfg) +pj_status_t create_stun_config(app_sess_t *app_sess) { - pj_ioqueue_t *ioqueue; - pj_timer_heap_t *timer_heap; - pj_lock_t *lock; + pj_ioqueue_t *ioqueue = NULL; + pj_timer_heap_t *timer_heap = NULL; + pj_lock_t *lock = NULL; pj_status_t status; - status = pj_ioqueue_create(pool, 64, &ioqueue); - if (status != PJ_SUCCESS) { - app_perror(" pj_ioqueue_create()", status); - return status; - } + pj_bzero(app_sess, sizeof(*app_sess)); + pj_caching_pool_init(&app_sess->cp, + &pj_pool_factory_default_policy, 0 ); + app_sess->pool = pj_pool_create(&app_sess->cp.factory, NULL, + 512, 512, NULL); + PJ_TEST_NOT_NULL(app_sess->pool, NULL, + { status=PJ_ENOMEM; goto on_error;}); - status = pj_timer_heap_create(pool, 256, &timer_heap); - if (status != PJ_SUCCESS) { - app_perror(" pj_timer_heap_create()", status); - pj_ioqueue_destroy(ioqueue); - return status; - } + PJ_TEST_SUCCESS(pj_ioqueue_create(app_sess->pool, 64, &ioqueue), NULL, + goto on_error); + PJ_TEST_SUCCESS(pj_timer_heap_create(app_sess->pool, 256, &timer_heap), + NULL, goto on_error); - pj_lock_create_recursive_mutex(pool, NULL, &lock); + pj_lock_create_recursive_mutex(app_sess->pool, NULL, &lock); pj_timer_heap_set_lock(timer_heap, lock, PJ_TRUE); + lock = NULL; - pj_stun_config_init(stun_cfg, mem, 0, ioqueue, timer_heap); + pj_stun_config_init(&app_sess->stun_cfg, app_sess->pool->factory, 0, + ioqueue, timer_heap); return PJ_SUCCESS; + +on_error: + if (ioqueue) + pj_ioqueue_destroy(ioqueue); + if (timer_heap) + pj_timer_heap_destroy(timer_heap); + if (lock) + pj_lock_destroy(lock); + if (app_sess->pool) + pj_pool_release(app_sess->pool); + pj_caching_pool_destroy(&app_sess->cp); + return status; } -void destroy_stun_config(pj_stun_config *stun_cfg) +void destroy_stun_config(app_sess_t *app_sess) { - if (stun_cfg->timer_heap) { - pj_timer_heap_destroy(stun_cfg->timer_heap); - stun_cfg->timer_heap = NULL; + if (app_sess->stun_cfg.timer_heap) { + pj_timer_heap_destroy(app_sess->stun_cfg.timer_heap); + app_sess->stun_cfg.timer_heap = NULL; + } + if (app_sess->stun_cfg.ioqueue) { + pj_ioqueue_destroy(app_sess->stun_cfg.ioqueue); + app_sess->stun_cfg.ioqueue = NULL; } - if (stun_cfg->ioqueue) { - pj_ioqueue_destroy(stun_cfg->ioqueue); - stun_cfg->ioqueue = NULL; + if (app_sess->pool) { + pj_pool_release(app_sess->pool); + app_sess->pool = NULL; } + pj_caching_pool_destroy(&app_sess->cp); } void poll_events(pj_stun_config *stun_cfg, unsigned msec, @@ -138,18 +159,18 @@ int check_pjlib_state(pj_stun_config *cfg, capture_pjlib_state(cfg, ¤t_state); if (current_state.timer_cnt > initial_st->timer_cnt) { - PJ_LOG(3,("", " error: possibly leaking timer")); rc |= ERR_TIMER_LEAK; #if PJ_TIMER_DEBUG pj_timer_heap_dump(cfg->timer_heap); #endif + PJ_LOG(3,("", " error: possibly leaking timer")); } if (current_state.pool_used_cnt > initial_st->pool_used_cnt) { - PJ_LOG(3,("", " error: possibly leaking memory")); PJ_LOG(3,("", " dumping memory pool:")); - pj_pool_factory_dump(mem, PJ_TRUE); + pj_pool_factory_dump(cfg->pf, PJ_TRUE); + PJ_LOG(3,("", " error: possibly leaking memory")); rc |= ERR_MEMORY_LEAK; } @@ -157,17 +178,8 @@ int check_pjlib_state(pj_stun_config *cfg, } -#define DO_TEST(test) do { \ - PJ_LOG(3, ("test", "Running %s...", #test)); \ - rc = test; \ - PJ_LOG(3, ("test", \ - "%s(%d)", \ - (char*)(rc ? "..ERROR" : "..success"), rc)); \ - if (rc!=0) goto on_return; \ - } while (0) - - pj_pool_factory *mem; +struct test_app_t test_app; int param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | PJ_LOG_HAS_SENDER | PJ_LOG_HAS_MICRO_SEC; @@ -184,10 +196,10 @@ static void test_log_func(int level, const char *data, int len) orig_log_func(level, data, len); } -static int test_inner(void) +static int test_inner(int argc, char *argv[]) { pj_caching_pool caching_pool; - int rc = 0; + int i, rc = 0; mem = &caching_pool.factory; @@ -202,55 +214,73 @@ static int test_inner(void) pj_log_set_log_func(&test_log_func); #endif - rc = pj_init(); - if (rc != 0) { - app_perror("pj_init() error!!", rc); - goto on_return; - } + PJ_TEST_SUCCESS(pj_init(), NULL, + {if (log_file) fclose(log_file); return 1; }); - pj_dump_config(); + if (test_app.ut_app.prm_config) + pj_dump_config(); pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 ); - pjlib_util_init(); - pjnath_init(); + PJ_TEST_SUCCESS(pjlib_util_init(), NULL, {rc=2; goto on_return;}); + PJ_TEST_SUCCESS(pjnath_init(), NULL, {rc=3; goto on_return;}); + PJ_TEST_SUCCESS(ut_app_init1(&test_app.ut_app, mem), + NULL, {rc=4; goto on_return;}); #if INCLUDE_STUN_TEST - DO_TEST(stun_test()); - DO_TEST(sess_auth_test()); + UT_ADD_TEST(&test_app.ut_app, stun_test, 0); + UT_ADD_TEST(&test_app.ut_app, sess_auth_test, 0); #endif -#if INCLUDE_ICE_TEST - DO_TEST(ice_test()); +#if INCLUDE_STUN_SOCK_TEST + UT_ADD_TEST(&test_app.ut_app, stun_sock_test, 0); #endif -#if INCLUDE_TRICKLE_ICE_TEST - DO_TEST(trickle_ice_test()); +#if INCLUDE_ICE_TEST + for (i=0; itest_srv->dns_server_port; status = pj_dns_resolver_set_ns(sess->resolver, 1, &dns_srv, &dns_srv_port); if (status != PJ_SUCCESS) { @@ -178,13 +179,15 @@ static int create_test_session(pj_stun_config *stun_cfg, if (cfg->client.enable_dns_srv) { /* Use DNS SRV to resolve server, may fallback to DNS A */ pj_str_t domain = pj_str(SRV_DOMAIN); - status = pj_turn_sock_alloc(sess->turn_sock, &domain, TURN_SERVER_PORT, + status = pj_turn_sock_alloc(sess->turn_sock, &domain, + sess->test_srv->turn_server_port, sess->resolver, &cred, &alloc_param); } else { /* Explicitly specify server address */ pj_str_t host = use_ipv6?pj_str("::1") : pj_str("127.0.0.1"); - status = pj_turn_sock_alloc(sess->turn_sock, &host, TURN_SERVER_PORT, + status = pj_turn_sock_alloc(sess->turn_sock, &host, + sess->test_srv->turn_server_port, NULL, &cred, &alloc_param); } @@ -531,50 +534,50 @@ static int destroy_test(pj_stun_config *stun_cfg, ///////////////////////////////////////////////////////////////////// -int turn_sock_test(void) +int turn_sock_test(void *p) { - pj_pool_t *pool; - pj_stun_config stun_cfg; - int n, i, rc = 0; + unsigned n = (int)(long)p; + app_sess_t app_sess; + pj_turn_tp_type tp_type = PJ_TURN_TP_UDP; + int i, rc = 0; + + if ((n == 2) && !USE_TLS) + return 0; + + switch (n) { + case 0: + tp_type = PJ_TURN_TP_UDP; + break; + case 1: + tp_type = PJ_TURN_TP_TCP; + break; + case 2: + tp_type = PJ_TURN_TP_TLS; + break; + default: + PJ_TEST_LTE(n, 2, NULL, return -1); + } - pool = pj_pool_create(mem, "turntest", 512, 512, NULL); - rc = create_stun_config(pool, &stun_cfg); + rc = create_stun_config(&app_sess); if (rc != PJ_SUCCESS) { - pj_pool_release(pool); return -2; } - for (n = 0; n <= 2; ++n) { - pj_turn_tp_type tp_type = PJ_TURN_TP_UDP; - - if ((n == 2) && !USE_TLS) - break; - - switch (n) { - case 1: - tp_type = PJ_TURN_TP_TCP; - break; - case 2: - tp_type = PJ_TURN_TP_TLS; - } - - rc = state_progression_test(&stun_cfg, USE_IPV6, tp_type); - if (rc != 0) - goto on_return; + rc = state_progression_test(&app_sess.stun_cfg, USE_IPV6, tp_type); + if (rc != 0) + goto on_return; - for (i=0; i<=1; ++i) { - int j; - for (j=0; j<=1; ++j) { - rc = destroy_test(&stun_cfg, i, j, USE_IPV6, tp_type); - if (rc != 0) - goto on_return; - } + for (i=0; i<=1; ++i) { + int j; + for (j=0; j<=1; ++j) { + rc = destroy_test(&app_sess.stun_cfg, i, j, USE_IPV6, tp_type); + if (rc != 0) + goto on_return; } } on_return: - destroy_stun_config(&stun_cfg); - pj_pool_release(pool); + destroy_stun_config(&app_sess); return rc; } diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h index 75fcfad034..14c2e5c522 100644 --- a/pjsip/include/pjsip/sip_transport.h +++ b/pjsip/include/pjsip/sip_transport.h @@ -1302,6 +1302,19 @@ PJ_DECL(pj_status_t) pjsip_tpmgr_find_local_addr2(pjsip_tpmgr *tpmgr, PJ_DECL(unsigned) pjsip_tpmgr_get_transport_count(pjsip_tpmgr *mgr); +/** + * Return number of transports of the specified type currently registered to + * the transport manager. + * + * @param mgr The transport manager. + * @param type Transport type (can be from pjsip_transport_type_e enum) + * + * @return Number of transports. + */ +PJ_DECL(unsigned) pjsip_tpmgr_get_transport_count_by_type(pjsip_tpmgr *mgr, + int type); + + /** * Destroy a transport manager. Normally application doesn't need to call * this function directly, since a transport manager will be created and diff --git a/pjsip/src/pjsip/sip_resolve.c b/pjsip/src/pjsip/sip_resolve.c index bd7942415f..b58e67ac6c 100644 --- a/pjsip/src/pjsip/sip_resolve.c +++ b/pjsip/src/pjsip/sip_resolve.c @@ -445,7 +445,6 @@ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver, else { pj_assert(!"Unknown transport type"); query->naptr[0].res_type = pj_str("_sip._udp."); - } } else { diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c index c5885f3056..7ce617d4c7 100644 --- a/pjsip/src/pjsip/sip_transport.c +++ b/pjsip/src/pjsip/sip_transport.c @@ -1907,6 +1907,12 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr, * manager. */ PJ_DEF(unsigned) pjsip_tpmgr_get_transport_count(pjsip_tpmgr *mgr) +{ + return pjsip_tpmgr_get_transport_count_by_type(mgr, -1); +} + +PJ_DEF(unsigned) pjsip_tpmgr_get_transport_count_by_type(pjsip_tpmgr *mgr, + int type) { pj_hash_iterator_t itr_val; pj_hash_iterator_t *itr; @@ -1917,7 +1923,15 @@ PJ_DEF(unsigned) pjsip_tpmgr_get_transport_count(pjsip_tpmgr *mgr) itr = pj_hash_first(mgr->table, &itr_val); while (itr) { transport *tp_entry = (transport *)pj_hash_this(mgr->table, itr); - nr_of_transports += (int)pj_list_size(tp_entry); + if (type<0) { + nr_of_transports += (int)pj_list_size(tp_entry); + } else { + transport *node = tp_entry->next; + for (; node!=tp_entry; node=node->next) { + if (tp_entry->tp->key.type==type) + ++nr_of_transports; + } + } itr = pj_hash_next(mgr->table, itr); } diff --git a/pjsip/src/test/dns_test.c b/pjsip/src/test/dns_test.c index 29dc762223..86ed8cd53e 100644 --- a/pjsip/src/test/dns_test.c +++ b/pjsip/src/test/dns_test.c @@ -331,7 +331,11 @@ static int test_resolve(const char *title, int port, pjsip_server_addresses *ref) { + enum { + TIMEOUT_SECS = 60 + }; pjsip_host_info dest; + pj_time_val timeout; struct result result; PJ_LOG(3,(THIS_FILE, " test_resolve(): %s", title)); @@ -343,14 +347,22 @@ static int test_resolve(const char *title, result.status = 0x12345678; + pj_gettimeofday(&timeout); + timeout.sec += TIMEOUT_SECS; + pjsip_endpt_resolve(endpt, pool, &dest, &result, &cb); while (result.status == 0x12345678) { int i = 0; pj_time_val timeout = { 1, 0 }; + pj_time_val now; + pjsip_endpt_handle_events(endpt, &timeout); if (i == 1) pj_dns_resolver_dump(pjsip_endpt_get_resolver(endpt), PJ_TRUE); + + pj_gettimeofday(&now); + PJ_TEST_TRUE(PJ_TIME_VAL_LT(now, timeout), NULL, return 12345678); } if (result.status != PJ_SUCCESS) { diff --git a/pjsip/src/test/inv_offer_answer_test.c b/pjsip/src/test/inv_offer_answer_test.c index 2fc0d22c7e..80b9ae552c 100644 --- a/pjsip/src/test/inv_offer_answer_test.c +++ b/pjsip/src/test/inv_offer_answer_test.c @@ -23,9 +23,9 @@ #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) +#define PORT 50068 +#define CONTACT "sip:inv_offer_answer_test@127.0.0.1:50068" +#define TRACE_(x) //PJ_LOG(3,x) static struct oa_sdp_t { @@ -277,6 +277,7 @@ static void on_state_changed(pjsip_inv_session *inv, pjsip_event *e) const char *who = NULL; PJ_UNUSED_ARG(e); + PJ_UNUSED_ARG(who); if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { TRACE_((THIS_FILE, " %s call disconnected", @@ -314,15 +315,17 @@ static pj_bool_t on_rx_request(pjsip_rx_data *rdata) pjmedia_sdp_session *sdp = NULL; pj_str_t uri; pjsip_tx_data *tdata; - pj_status_t status; + + if (!is_user_equal(rdata->msg_info.from, "inv_offer_answer_test")) + return PJ_FALSE; /* * Create UAS */ uri = pj_str(CONTACT); - status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(), rdata, - &uri, &dlg); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(), rdata, + &uri, &dlg), + NULL, { pj_assert(0); return PJ_FALSE; }); if (inv_test.param.oa[0] == OFFERER_UAC) sdp = create_sdp(rdata->tp_info.pool, oa_sdp[0].answer); @@ -331,8 +334,10 @@ static pj_bool_t on_rx_request(pjsip_rx_data *rdata) 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); + PJ_TEST_SUCCESS(pjsip_inv_create_uas(dlg, rdata, sdp, + inv_test.param.inv_option, + &inv_test.uas), + NULL, { pj_assert(0); return PJ_FALSE; }); pjsip_dlg_dec_lock(dlg); TRACE_((THIS_FILE, " Sending 183 with SDP")); @@ -340,23 +345,23 @@ static pj_bool_t on_rx_request(pjsip_rx_data *rdata) /* * Answer with 183 */ - status = pjsip_inv_initial_answer(inv_test.uas, rdata, 183, NULL, - NULL, &tdata); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pjsip_inv_initial_answer(inv_test.uas, rdata, 183, + NULL, NULL, &tdata), + NULL, { pj_assert(0); return PJ_FALSE; }); /* Use multipart body, if configured */ if (sdp && inv_test.param.multipart_body) { - status = pjsip_create_multipart_sdp_body( + PJ_TEST_SUCCESS(pjsip_create_multipart_sdp_body( tdata->pool, pjmedia_sdp_session_clone(tdata->pool, sdp), - &tdata->msg->body); + &tdata->msg->body), + NULL, { pj_assert(0); return PJ_FALSE; }); } - pj_assert(status == PJ_SUCCESS); - status = pjsip_inv_send_msg(inv_test.uas, tdata); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pjsip_inv_send_msg(inv_test.uas, tdata), + NULL, { pj_assert(0); return PJ_FALSE; }); - return (status == PJ_SUCCESS); + return PJ_TRUE; } return PJ_FALSE; @@ -466,8 +471,8 @@ static int perform_test(inv_test_param_t *param) } PJ_ASSERT_RETURN(status==PJ_SUCCESS, -40); - status = pjsip_inv_send_msg(inv_test.uac, tdata); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, -50); + PJ_TEST_SUCCESS(pjsip_inv_send_msg(inv_test.uac, tdata), + NULL, PJ_ASSERT_RETURN(0, -50)); /* * Wait until test completes @@ -498,8 +503,8 @@ static int perform_test(inv_test_param_t *param) pj_assert(status == PJ_SUCCESS); if (tdata) { - status = pjsip_inv_send_msg(inv_test.uas, tdata); - pj_assert(status == PJ_SUCCESS); + PJ_TEST_SUCCESS(pjsip_inv_send_msg(inv_test.uas, tdata), + NULL, pj_assert(0)); } flush_events(500); @@ -513,6 +518,9 @@ static pj_bool_t log_on_rx_msg(pjsip_rx_data *rdata) pjsip_msg *msg = rdata->msg_info.msg; char info[80]; + if (!is_user_equal(rdata->msg_info.from, "inv_offer_answer_test")) + return PJ_FALSE; + if (msg->type == PJSIP_REQUEST_MSG) pj_ansi_snprintf(info, sizeof(info), "%.*s", (int)msg->line.req.method.name.slen, @@ -764,12 +772,10 @@ int inv_offer_answer_test(void) { 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); - PJ_UNUSED_ARG(status); + PJ_TEST_SUCCESS(pjsip_udp_transport_start(endpt, &addr, NULL, 1, &tp), + NULL, return -5); } /* Do tests */ diff --git a/pjsip/src/test/main.c b/pjsip/src/test/main.c index 18dc2e266c..cf17b5e177 100644 --- a/pjsip/src/test/main.c +++ b/pjsip/src/test/main.c @@ -20,19 +20,39 @@ #include #include #include +#include extern const char *system_name; +static void warn(void) +{ + puts("********************************************************************"); + puts("** W A R N I N G **"); + puts("********************************************************************"); + puts("** Due to centralized event processing in PJSIP, events may be **"); + puts("** read by different thread than the test's thread. This may **"); + puts("** cause logs to be saved by the wrong test when multithreaded **"); + puts("** testing is used. The test results are correct, but the log **"); + puts("** may not be accurate. **"); + puts("** For debugging with correct logging, use \"-w 0 --log-no-cache\" **"); + puts("********************************************************************"); +} + static void usage(void) { - 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)"); - puts(" -n,--no-trap Let signals be handled by the OS"); - puts(" -t,--tests testname,... Comma separated list of test to run"); - list_tests(); + puts("Usage:"); + puts(" pjsip-test [OPTIONS] [test_to_run] [test to run] [..]"); + puts(""); + puts("where OPTIONS:"); + puts(""); + puts(" -h,--help Show this screen"); + + ut_usage(); + + puts(" -i,--interractive Key input at the end."); + puts(" -n,--no-trap Let signals be handled by the OS"); + puts(" --log-level N Set log level (0-6)"); + puts(" -s,--system NAME Set system name to NAME"); } #if (PJ_LINUX || PJ_DARWINOS) && defined(PJ_HAS_EXECINFO_H) && PJ_HAS_EXECINFO_H != 0 @@ -67,68 +87,41 @@ int main(int argc, char *argv[]) { int interractive = 0; int retval; - char **opt_arg; int no_trap = 0; - char *testlist = NULL; - - PJ_UNUSED_ARG(argc); - - /* 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, "-n") == 0 || - strcmp(*opt_arg, "--no-trap") == 0) - { - no_trap = 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 if (strcmp(*opt_arg, "-t") == 0 || - strcmp(*opt_arg, "--tests") == 0) - { - ++opt_arg; - if (!*opt_arg) { - usage(); - return 1; - } - testlist = *opt_arg; - } else { - usage(); - return 1; - } - - ++opt_arg; + + warn(); + + if (pj_argparse_get_bool(&argc, argv, "-h") || + pj_argparse_get_bool(&argc, argv, "--help")) + { + usage(); + return 0; } + ut_app_init0(&test_app.ut_app); + + interractive = pj_argparse_get_bool(&argc, argv, "-i"); + no_trap = pj_argparse_get_bool(&argc, argv, "-n"); + if (pj_argparse_get_str(&argc, argv, "-s", (char**)&system_name) || + pj_argparse_get_str(&argc, argv, "--system", (char**)&system_name)) + { + usage(); + return 1; + } + + if (pj_argparse_get_int(&argc, argv, "--log-level", &log_level)) { + usage(); + return 1; + } + + if (ut_parse_args(&test_app.ut_app, &argc, argv)) + return 1; + if (!no_trap) { init_signals(); } - retval = test_main(testlist); + retval = test_main(argc, argv); if (interractive) { char s[10]; diff --git a/pjsip/src/test/regc_test.c b/pjsip/src/test/regc_test.c index 9708208bd2..5f978f8acf 100644 --- a/pjsip/src/test/regc_test.c +++ b/pjsip/src/test/regc_test.c @@ -39,14 +39,14 @@ static struct NULL, NULL, /* prev, next. */ { "mod-send", 8 }, /* Name. */ -1, /* Id */ - PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */ + 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. */ + &mod_send_on_tx_request, /* on_tx_request. */ NULL, /* on_tx_response() */ NULL, /* on_tsx_state() */ }, @@ -57,7 +57,12 @@ static struct static pj_status_t mod_send_on_tx_request(pjsip_tx_data *tdata) { - PJ_UNUSED_ARG(tdata); + const pjsip_from_hdr *from_hdr = (const pjsip_from_hdr*) + pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL); + + if ((tdata->msg->line.req.method.id != PJSIP_REGISTER_METHOD) || + !is_user_equal(from_hdr, "regc-test")) + return PJ_FALSE; if (++send_mod.count > send_mod.count_before_reject) return PJ_ECANCELLED; @@ -120,7 +125,8 @@ static pj_bool_t regs_rx_request(pjsip_rx_data *rdata) int code; pj_status_t status; - if (msg->line.req.method.id != PJSIP_REGISTER_METHOD) + if ((rdata->msg_info.msg->line.req.method.id != PJSIP_REGISTER_METHOD) || + !is_user_equal(rdata->msg_info.from, "regc-test")) return PJ_FALSE; if (!registrar.cfg.respond) @@ -322,6 +328,9 @@ static int do_test(const char *title, pjsip_regc_destroy(regc); return -120; } + /* Add additional ref counter to prevent premature destroy */ + pjsip_tx_data_add_ref(tdata); + status = pjsip_regc_send(regc, tdata); /* That's it, wait until the callback is sent */ @@ -332,6 +341,7 @@ static int do_test(const char *title, if (!client_result.done) { PJ_LOG(3,(THIS_FILE, " error: test has timed out")); pjsip_regc_destroy(regc); + pjsip_tx_data_dec_ref(tdata); return -200; } @@ -346,6 +356,7 @@ static int do_test(const char *title, 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)); + pjsip_tx_data_dec_ref(tdata); return -210; } if (client_result.code != client_cfg->code && @@ -354,31 +365,37 @@ static int do_test(const char *title, { PJ_LOG(3,(THIS_FILE, " error: expecting code=%d, got code=%d", client_cfg->code, client_result.code)); + pjsip_tx_data_dec_ref(tdata); 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)); + pjsip_tx_data_dec_ref(tdata); 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)); + pjsip_tx_data_dec_ref(tdata); 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)); + pjsip_tx_data_dec_ref(tdata); return -260; } if (client_result.have_reg && 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)); + pjsip_tx_data_dec_ref(tdata); return -270; } if (client_result.interval > 0 && client_result.next_reg < 1) { PJ_LOG(3,(THIS_FILE, " error: next_reg=%d, expecting positive number because interval is %d", client_result.next_reg, client_result.interval)); + pjsip_tx_data_dec_ref(tdata); return -280; } @@ -387,6 +404,7 @@ static int do_test(const char *title, *p_regc = regc; } + pjsip_tx_data_dec_ref(tdata); return 0; } diff --git a/pjsip/src/test/test.c b/pjsip/src/test/test.c index cda6d3c7aa..a2f63f7ffc 100644 --- a/pjsip/src/test/test.c +++ b/pjsip/src/test/test.c @@ -25,29 +25,6 @@ #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) - -#if defined(_MSC_VER) || defined(__MINGW32__) -# define strtok_r strtok_s -#endif - pjsip_endpoint *endpt; pj_caching_pool caching_pool; int log_level = 3; @@ -57,85 +34,8 @@ int param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | PJ_LOG_HAS_SENDER | static pj_oshandle_t fd_report; const char *system_name = "Unknown"; static char buf[1024]; - -static struct { - const char *name; - int run_test; -} test_list[] = { - { "uri", 0}, - { "msg", 0}, - { "multipart", 0}, - { "txdata", 0}, - { "tsx_bench", 0}, - { "udp", 0}, - { "loop", 0}, - { "tcp", 0}, - { "resolve", 0}, - { "tsx", 0}, - { "tsx_destroy", 0}, - { "inv_oa", 0}, - { "regc", 0}, -}; -enum tests_to_run { - include_uri_test = 0, - include_msg_test, - include_multipart_test, - include_txdata_test, - include_tsx_bench, - include_udp_test, - include_loop_test, - include_tcp_test, - include_resolve_test, - include_tsx_test, - include_tsx_destroy_test, - include_inv_oa_test, - include_regc_test, -}; -static int run_all_tests = 1; - -static pj_status_t select_tests(char *testlist) -{ - char *token; - char *saveptr; - int maxtok = PJ_ARRAY_SIZE(test_list); - int j; - - if (!testlist) { - return PJ_SUCCESS; - } - run_all_tests = 0; - - for (token = strtok_r(testlist, ",", &saveptr); token != NULL; - token = strtok_r(NULL, ",", &saveptr)) { - - int found = 0; - for (j = 0; j < maxtok; j++) { - if (strcmp(token, test_list[j].name) == 0) { - test_list[j].run_test = 1; - found = 1; - } - } - if (!found) { - fprintf(stderr, "Test '%s' is not valid\n", token); - return PJ_ENOTFOUND; - } - } - - return PJ_SUCCESS; -} - -void list_tests(void) { - int maxtok = PJ_ARRAY_SIZE(test_list); - int j; - - fprintf(stderr, "Valid tests:\n"); - - for (j = 0; j < maxtok; j++) { - fprintf(stderr, " %s\n", test_list[j].name); - } -} - -#define SHOULD_RUN_TEST(ix) (run_all_tests || test_list[ix].run_test) +struct test_app_t test_app; +struct tsx_test_param tsx_test[MAX_TSX_TESTS]; void app_perror(const char *msg, pj_status_t rc) { @@ -168,6 +68,40 @@ void flush_events(unsigned duration) } } +/* Wait until there is no loop transport instance */ +pjsip_transport *wait_loop_transport_clear(int secs) +{ + pj_time_val timeout; + + pj_gettimeofday(&timeout); + timeout.sec += secs; + + for (;;) { + pj_sockaddr_in addr; + pjsip_transport *loop = NULL; + pj_time_val now; + pj_status_t status; + + loop = NULL; + pj_bzero(&addr, sizeof(addr)); + status = pjsip_endpt_acquire_transport(endpt, + PJSIP_TRANSPORT_LOOP_DGRAM, + &addr, sizeof(addr), NULL, + &loop); + if (status!=PJ_SUCCESS) + return NULL; + + pj_gettimeofday(&now); + if (PJ_TIME_VAL_GTE(now, timeout)) { + return loop; + } + + pjsip_transport_dec_ref(loop); + loop = NULL; + flush_events(500); + } +} + pj_status_t register_static_modules(pj_size_t *count, pjsip_module **modules) { PJ_UNUSED_ARG(modules); @@ -309,13 +243,11 @@ static void close_report(void) } -int test_main(char *testlist) +int test_main(int argc, char *argv[]) { pj_status_t rc; 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; @@ -325,187 +257,154 @@ int test_main(char *testlist) #endif /* INCLUDE_TSX_TEST */ int line; - rc = select_tests(testlist); - if (rc != PJ_SUCCESS) { - list_tests(); - return rc; - } - 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; - } + PJ_TEST_SUCCESS(pj_init(), NULL, return 10); + PJ_TEST_SUCCESS(pjlib_util_init(), NULL, return 20); + PJ_TEST_SUCCESS(init_report(), NULL, return 30); - if ((rc=pjlib_util_init()) != PJ_SUCCESS) { - app_perror("pj_init", rc); - return rc; + if (test_app.ut_app.prm_config) { + pj_dump_config(); } - 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," ")); + PJ_TEST_SUCCESS(pjsip_endpt_create(&caching_pool.factory, "endpt", &endpt), + NULL, { + pj_caching_pool_destroy(&caching_pool); + return 40; + }); /* 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; - } + PJ_TEST_SUCCESS(rc = pjsip_tsx_layer_init_module(endpt), + NULL, 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; + PJ_TEST_SUCCESS(rc=ut_app_init1(&test_app.ut_app, &caching_pool.factory), + NULL, goto on_return); #if INCLUDE_URI_TEST - if (SHOULD_RUN_TEST(include_uri_test)) { - DO_TEST(uri_test()); - } + UT_ADD_TEST(&test_app.ut_app, uri_test, 0); #endif #if INCLUDE_MSG_TEST - if (SHOULD_RUN_TEST(include_msg_test)) { - DO_TEST(msg_test()); - DO_TEST(msg_err_test()); - } + UT_ADD_TEST(&test_app.ut_app, msg_test, 0); + UT_ADD_TEST(&test_app.ut_app, msg_err_test, 0); #endif #if INCLUDE_MULTIPART_TEST - if (SHOULD_RUN_TEST(include_multipart_test)) { - DO_TEST(multipart_test()); - } + UT_ADD_TEST(&test_app.ut_app, multipart_test, 0); #endif #if INCLUDE_TXDATA_TEST - if (SHOULD_RUN_TEST(include_txdata_test)) { - DO_TEST(txdata_test()); - } + UT_ADD_TEST(&test_app.ut_app, txdata_test, 0); #endif #if INCLUDE_TSX_BENCH - if (SHOULD_RUN_TEST(include_tsx_bench)) { - DO_TEST(tsx_bench()); - } -#endif - -#if INCLUDE_UDP_TEST - if (SHOULD_RUN_TEST(include_udp_test)) { - DO_TEST(transport_udp_test()); - } + UT_ADD_TEST(&test_app.ut_app, tsx_bench, 0); #endif #if INCLUDE_LOOP_TEST - if (SHOULD_RUN_TEST(include_loop_test)) { - DO_TEST(transport_loop_test()); - } -#endif - -#if INCLUDE_TCP_TEST - if (SHOULD_RUN_TEST(include_tcp_test)) { - DO_TEST(transport_tcp_test()); - } + UT_ADD_TEST(&test_app.ut_app, transport_loop_multi_test, 0); #endif #if INCLUDE_RESOLVE_TEST - if (SHOULD_RUN_TEST(include_resolve_test)) { - DO_TEST(resolve_test()); - } + UT_ADD_TEST(&test_app.ut_app, resolve_test, 0); #endif -#if INCLUDE_LOOP_TEST - /* repeat again after resolver is configured in resolve_test() */ - if (SHOULD_RUN_TEST(include_loop_test)) { - DO_TEST(transport_loop_test()); - } +#if INCLUDE_INV_OA_TEST + UT_ADD_TEST(&test_app.ut_app, inv_offer_answer_test, 0); #endif #if INCLUDE_TSX_TEST - if (SHOULD_RUN_TEST(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; - } + PJ_TEST_SUCCESS(rc=pjsip_udp_transport_start(endpt, NULL, NULL, 1, &tp), + NULL, goto on_return); + 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; - } + PJ_TEST_SUCCESS(rc=pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory), + NULL, goto on_return); + 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; #endif - for (i = 0; i < tsx_test_cnt; ++i) { - DO_TSX_TEST(tsx_basic_test, &tsx_test[i]); - DO_TSX_TEST(tsx_uac_test, &tsx_test[i]); - DO_TSX_TEST(tsx_uas_test, &tsx_test[i]); - } + pj_assert(tsx_test[0].type == PJSIP_TRANSPORT_LOOP_DGRAM); + + for (i = 0; i < tsx_test_cnt; ++i) { + UT_ADD_TEST1(&test_app.ut_app, tsx_basic_test, (void*)(long)i, 0); + UT_ADD_TEST1(&test_app.ut_app, tsx_uac_test, (void*)(long)i, 0); + UT_ADD_TEST1(&test_app.ut_app, tsx_uas_test, (void*)(long)i, 0); } #endif -#if INCLUDE_INV_OA_TEST - if (SHOULD_RUN_TEST(include_inv_oa_test)) { - DO_TEST(inv_offer_answer_test()); - } +#if INCLUDE_LOOP_TEST + UT_ADD_TEST(&test_app.ut_app, transport_loop_test, 0); +#endif + +#if INCLUDE_UDP_TEST + /* Transport tests share same testing codes which are not reentrant */ + UT_ADD_TEST(&test_app.ut_app, transport_udp_test, 0); #endif +#if INCLUDE_TCP_TEST + UT_ADD_TEST(&test_app.ut_app, transport_tcp_test, 0); +#endif + + /* Note: put exclusive tests last */ + + /* + * regc_test() needs exclusive because it modifies pjsip_cfg() + */ #if INCLUDE_REGC_TEST - if (SHOULD_RUN_TEST(include_regc_test)) { - DO_TEST(regc_test()); - } + UT_ADD_TEST(&test_app.ut_app, regc_test, PJ_TEST_EXCLUSIVE | PJ_TEST_KEEP_LAST); +#endif + + /* This needs to be exclusive, because there must NOT be any other + * loop transport otherwise some test will fail (e.g. sending will + * fallback to that transport) + */ +#if INCLUDE_LOOP_TEST + UT_ADD_TEST(&test_app.ut_app, transport_loop_resolve_error_test, + PJ_TEST_EXCLUSIVE | PJ_TEST_KEEP_LAST); #endif /* * Better be last because it recreates the endpt */ #if INCLUDE_TSX_DESTROY_TEST - if (SHOULD_RUN_TEST(include_tsx_destroy_test)) { - DO_TEST(tsx_destroy_test()); - } + UT_ADD_TEST(&test_app.ut_app, tsx_destroy_test, + PJ_TEST_EXCLUSIVE | PJ_TEST_KEEP_LAST); #endif + if (ut_run_tests(&test_app.ut_app, "pjsip tests", argc, argv)) { + rc = 99; + } else { + rc = 0; + } + + ut_app_destroy(&test_app.ut_app); + on_return: flush_events(500); /* Show additional info on the log. e.g: not released memory pool. */ - pj_log_set_level(4); + // Commented out to make the output tidy :D (blp) + //pj_log_set_level(4); /* Dumping memory pool usage */ /* Field peak_used_size is deprecated by #3897 */ diff --git a/pjsip/src/test/test.h b/pjsip/src/test/test.h index 4fd8793c70..7fac3e3c61 100644 --- a/pjsip/src/test/test.h +++ b/pjsip/src/test/test.h @@ -20,6 +20,8 @@ #define __TEST_H__ #include +#include +#include extern pjsip_endpoint *endpt; extern pj_caching_pool caching_pool; @@ -83,9 +85,14 @@ int tsx_bench(void); int tsx_destroy_test(void); int transport_udp_test(void); int transport_loop_test(void); +int transport_loop_multi_test(void); +int transport_loop_resolve_error_test(void); int transport_tcp_test(void); int resolve_test(void); int regc_test(void); +int inv_offer_answer_test(void); + +#define MAX_TSX_TESTS 10 struct tsx_test_param { @@ -93,42 +100,60 @@ struct tsx_test_param int port; char *tp_type; }; +extern struct tsx_test_param tsx_test[MAX_TSX_TESTS]; -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); +int tsx_basic_test(unsigned tid); +int tsx_uac_test(unsigned tid); +int tsx_uas_test(unsigned tid); /* 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, + const char *host_port_transport, int *p_usec_rtt); int transport_rt_test( pjsip_transport_type_e tp_type, pjsip_transport *ref_tp, - char *target_url, + const char *host_port_transport, int *pkt_lost); -int transport_load_test(char *target_url); - -/* Invite session */ -int inv_offer_answer_test(void); +int transport_load_test(pjsip_transport_type_e tp_type, + const char *host_port_transport); /* Test main entry */ -int test_main(char *testlist); +int test_main(int argc, char *argv[]); /* Test utilities. */ -void list_tests(void); 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); - +pjsip_transport *wait_loop_transport_clear(int secs); 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); +/* Utility to check if the user part of From/To is equal to the string */ +PJ_INLINE(pj_bool_t) is_user_equal(const pjsip_fromto_hdr *hdr, const char *user) +{ + const pjsip_sip_uri *sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(hdr->uri); + const pj_str_t *scheme = pjsip_uri_get_scheme(sip_uri); + + if (pj_stricmp2(scheme, "sip") && pj_stricmp2(scheme, "sips")) + return PJ_FALSE; + + return pj_strcmp2(&sip_uri->user, user)==0; +} /* Settings. */ extern int log_level; +#define UT_MAX_TESTS 32 +#include "../../../pjlib/src/pjlib-test/test_util.h" + +struct test_app_t +{ + ut_app_t ut_app; +}; +extern struct test_app_t test_app; + #endif /* __TEST_H__ */ diff --git a/pjsip/src/test/transport_loop_test.c b/pjsip/src/test/transport_loop_test.c index 40175160c5..dbd6f79b28 100644 --- a/pjsip/src/test/transport_loop_test.c +++ b/pjsip/src/test/transport_loop_test.c @@ -23,6 +23,157 @@ #define THIS_FILE "transport_loop_test.c" +static pjsip_transport *cur_loop; +static int loop_test_status; + +static pj_bool_t on_rx_request(pjsip_rx_data *rdata); +static pj_bool_t on_rx_response(pjsip_rx_data *rdata); +static pj_status_t on_tx_message(pjsip_tx_data *tdata); + +static pjsip_module loop_tester_mod = +{ + NULL, NULL, /* prev and next */ + { "transport_loop_test", 19}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_UA_PROXY_LAYER-1,/* Priority */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + &on_rx_request, /* on_rx_request() */ + &on_rx_response, /* on_rx_response() */ + &on_tx_message, /* on_tx_request() */ + &on_tx_message, /* on_tx_response() */ + NULL, /* on_tsx_state() */ +}; + + +static pj_bool_t on_rx_request(pjsip_rx_data *rdata) +{ +#define ERR(rc__) {loop_test_status=rc__; return PJ_TRUE; } + if (!is_user_equal(rdata->msg_info.from, "transport_loop_multi_test")) + return PJ_FALSE; + + PJ_TEST_EQ(rdata->tp_info.transport, cur_loop, NULL, ERR(-100)); + PJ_TEST_SUCCESS(pjsip_endpt_respond_stateless(endpt, rdata, PJSIP_SC_ACCEPTED, + NULL, NULL, NULL), + NULL, ERR(-100)); + return PJ_TRUE; +#undef ERR +} + +static pj_bool_t on_rx_response(pjsip_rx_data *rdata) +{ +#define ERR(rc__) {loop_test_status=rc__; return PJ_TRUE; } + if (!is_user_equal(rdata->msg_info.from, "transport_loop_multi_test")) + return PJ_FALSE; + + PJ_TEST_EQ(rdata->tp_info.transport, cur_loop, NULL, ERR(-150)); + PJ_TEST_EQ(rdata->msg_info.msg->line.status.code, PJSIP_SC_ACCEPTED, NULL, + ERR(-160)); + + loop_test_status = 0; + return PJ_TRUE; +#undef ERR +} + +static pj_status_t on_tx_message(pjsip_tx_data *tdata) +{ + pjsip_from_hdr *from_hdr = (pjsip_from_hdr*) + pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL); + + if (!is_user_equal(from_hdr, "transport_loop_multi_test")) + return PJ_SUCCESS; + + PJ_TEST_EQ(tdata->tp_info.transport, cur_loop, + tdata->msg->type==PJSIP_REQUEST_MSG? + "request transport mismatch" : "response transport mismatch", + loop_test_status=-200); + + return PJ_SUCCESS; +} + +/* Test that request and responses are sent/received on the correct loop + * instance when multiple instances of transport loop are created + */ +int transport_loop_multi_test(void) +{ +#define ERR(rc__) { rc=rc__; goto on_return; } + enum { N = 4, START_PORT=5000, TIMEOUT=1000 }; + pjsip_transport *loops[N]; + int i, rc; + + PJ_TEST_SUCCESS(pjsip_endpt_register_module(endpt, &loop_tester_mod), + NULL, ERR(-5)); + + pj_bzero(loops, sizeof(loops)); + for (i=0; itoken; @@ -40,7 +191,7 @@ static void send_cb(pjsip_send_state *st, pj_ssize_t sent, pj_bool_t *cont) } } -static int loop_resolve_error() +static int loop_resolve_error(pj_bool_t disable_no_selector) { pjsip_transport *loop = NULL; pj_sockaddr_in addr; @@ -50,6 +201,8 @@ static int loop_resolve_error() int i, loop_resolve_status; pj_status_t status; + PJ_LOG(3,(THIS_FILE, "testing loop resolve error")); + loop_resolve_status = 0; pj_bzero(&addr, sizeof(addr)); @@ -60,9 +213,12 @@ static int loop_resolve_error() return -210; } - url = pj_str("sip:bob@unresolved-host"); + url = pj_str("sip:bob@unresolved-host;transport=loop-dgram"); for (i=0; i<2; ++i) { + if (i==0 && disable_no_selector) + continue; + /* variant a: without tp_selector */ status = pjsip_endpt_create_request( endpt, &pjsip_options_method, &url, &url, &url, NULL, NULL, -1, @@ -89,14 +245,20 @@ static int loop_resolve_error() /* Success! (we're expecting error and got immediate error)*/ loop_resolve_status = 0; } else { - flush_events(500); + unsigned j; + + for (j=0; j<40 && loop_resolve_status==PJ_EPENDING; ++j) + flush_events(500); + if (loop_resolve_status!=PJ_EPENDING && loop_resolve_status!=PJ_SUCCESS) { /* Success! (we're expecting error in callback)*/ //PJ_PERROR(3, (THIS_FILE, loop_resolve_status, // " correctly got error")); loop_resolve_status = 0; } else { - PJ_LOG(3,(THIS_FILE, " error: expecting error but status=%d", status)); + PJ_LOG(3,(THIS_FILE, + " error (variant %d): expecting error but loop_resolve_status=%d", + i, loop_resolve_status)); loop_resolve_status = -240; goto on_return; } @@ -107,29 +269,27 @@ static int loop_resolve_error() if (loop) pjsip_transport_dec_ref(loop); return loop_resolve_status; - } -static int datagram_loop_test() +int transport_loop_test() { enum { LOOP = 8 }; - pjsip_transport *loop; + pjsip_transport *loop = NULL; + char host_port_transport[64]; int i, pkt_lost; - pj_sockaddr_in addr; - pj_status_t status; + int status; long ref_cnt; int rtt[LOOP], min_rtt; - PJ_LOG(3,(THIS_FILE, "testing datagram loop transport")); - pj_sockaddr_in_init(&addr, NULL, 0); - /* 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; - } + PJ_TEST_SUCCESS(pjsip_loop_start(endpt, &loop), NULL, return -3); + pjsip_transport_add_ref(loop); + + pj_ansi_snprintf(host_port_transport, sizeof(host_port_transport), + "%.*s:%d;transport=loop-dgram", + (int)loop->local_name.host.slen, + loop->local_name.host.ptr, + loop->local_name.port); /* Get initial reference counter */ ref_cnt = pj_atomic_get(loop->ref_cnt); @@ -137,22 +297,16 @@ static int datagram_loop_test() /* Test basic transport attributes */ status = generic_transport_test(loop); if (status != PJ_SUCCESS) - return status; + goto on_return; /* Basic transport's send/receive loopback test. */ for (i=0; iref_cnt) != ref_cnt) { PJ_LOG(3,(THIS_FILE, " error: ref counter is not %ld (%ld)", ref_cnt, pj_atomic_get(loop->ref_cnt))); - return -51; + status = -51; + goto on_return; } + status = 0; + +on_return: /* Decrement reference. */ pjsip_transport_dec_ref(loop); - - return 0; + return status; } -int transport_loop_test(void) + +/* tgus needs to be exclusive, because there must NOT be any other + * loop transport otherwise some test will fail (e.g. sending will + * fallback to that transport) + */ +int transport_loop_resolve_error_test() { + pjsip_transport *loop; + pj_bool_t disable_no_selector = PJ_FALSE; int status; - status = datagram_loop_test(); - if (status != 0) - return status; + PJ_LOG(3,(THIS_FILE, " Loop transport count: %d", + pjsip_tpmgr_get_transport_count_by_type( + pjsip_endpt_get_tpmgr(endpt), + PJSIP_TRANSPORT_LOOP_DGRAM))); + + /* if there is another transport, wait sometime until it's gone */ + loop = wait_loop_transport_clear(10); + + if (loop) { + /* We are not supposed to have another instance of loop transport, but + * we found one. If there are more than one, test will fail. Otherwise + * test should succeed + */ + PJ_LOG(2,(THIS_FILE, + "Warning: found %d loop transport instances", + pjsip_tpmgr_get_transport_count_by_type( + pjsip_endpt_get_tpmgr(endpt), + PJSIP_TRANSPORT_LOOP_DGRAM))); + disable_no_selector = PJ_TRUE; + pjsip_loop_set_discard(loop, 0, NULL); + pjsip_loop_set_failure(loop, 0, NULL); + pjsip_loop_set_delay(loop, 0); + } else { + PJ_TEST_EQ(loop, NULL, NULL, return -2); + PJ_TEST_SUCCESS(pjsip_loop_start(endpt, &loop), NULL, return -3); + pjsip_transport_add_ref(loop); + } + + /* Resolve error */ + status = loop_resolve_error(disable_no_selector); - return 0; +on_return: + /* Decrement reference. */ + pjsip_transport_dec_ref(loop); + return status; } diff --git a/pjsip/src/test/transport_tcp_test.c b/pjsip/src/test/transport_tcp_test.c index c3da6bd319..4fdc98906f 100644 --- a/pjsip/src/test/transport_tcp_test.c +++ b/pjsip/src/test/transport_tcp_test.c @@ -156,7 +156,7 @@ int transport_tcp_test(void) pjsip_transport *tcp[NUM_TP]; pj_sockaddr_in rem_addr; pj_status_t status; - char url[PJSIP_MAX_URL_SIZE]; + char host_port_param[PJSIP_MAX_URL_SIZE]; char addr[PJ_INET_ADDRSTRLEN]; int rtt[SEND_RECV_LOOP], min_rtt; int pkt_lost; @@ -172,19 +172,16 @@ int transport_tcp_test(void) status = pj_sockaddr_in_init(&rem_addr, &tpfactory[0]->addr_name.host, (pj_uint16_t)tpfactory[0]->addr_name.port); - pj_ansi_snprintf(url, sizeof(url), "sip:alice@%s:%d;transport=tcp", + pj_ansi_snprintf(host_port_param, sizeof(host_port_param), + "%s:%d;transport=tcp", pj_inet_ntop2(pj_AF_INET(), &rem_addr.sin_addr, addr, sizeof(addr)), pj_ntohs(rem_addr.sin_port)); - /* Load test */ - if (transport_load_test(url) != 0) - return -60; - /* Basic transport's send/receive loopback test. */ for (i=0; iref_cnt) != 1) diff --git a/pjsip/src/test/transport_test.c b/pjsip/src/test/transport_test.c index f834d1dec9..6f4fda98aa 100644 --- a/pjsip/src/test/transport_test.c +++ b/pjsip/src/test/transport_test.c @@ -39,10 +39,8 @@ int generic_transport_test(pjsip_transport *tp) if (pj_inet_pton(pj_AF_INET(), &tp->local_name.host, &addr) == PJ_SUCCESS) { - if (addr.s_addr==PJ_INADDR_ANY || addr.s_addr==PJ_INADDR_NONE) { - PJ_LOG(3,(THIS_FILE, " Error: invalid address name")); - return -420; - } + PJ_TEST_TRUE(addr.s_addr!=PJ_INADDR_ANY && addr.s_addr!=PJ_INADDR_NONE, + "invalid address name", return -420); } else { /* It's okay. local_name.host may be a hostname instead of * IP address. @@ -51,17 +49,13 @@ int generic_transport_test(pjsip_transport *tp) } /* Check that port is valid. */ - if (tp->local_name.port <= 0) { - return -430; - } + PJ_TEST_GT(tp->local_name.port, 0, NULL, return -430); /* Check length of address (for now we only check against sockaddr_in). */ - if (tp->addr_len != sizeof(pj_sockaddr_in)) - return -440; + PJ_TEST_EQ(tp->addr_len, sizeof(pj_sockaddr_in), NULL, return -440); /* Check type. */ - if (tp->key.type == PJSIP_TRANSPORT_UNSPECIFIED) - return -450; + PJ_TEST_NEQ(tp->key.type, PJSIP_TRANSPORT_UNSPECIFIED, NULL, return -450); /* That's it. */ return PJ_SUCCESS; @@ -77,11 +71,12 @@ int generic_transport_test(pjsip_transport *tp) * 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!" +#define SEND_RECV_FROM_HDR "Bob " +#define SEND_RECV_CALL_ID_HDR "Transport-SendRecv-Test" +#define RT_FROM_HDR "Bob " +#define CONTACT_HDR "Bob " +#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); @@ -90,12 +85,18 @@ static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata); * (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; + +struct send_recv_test_global_t +{ + int send_status; + int recv_status; + pj_timestamp my_send_time; + pj_timestamp my_recv_time; +}; +static struct send_recv_test_global_t sr_g[PJSIP_TRANSPORT_START_OTHER]; /* Module to receive messages for this test. */ -static pjsip_module my_module = +static pjsip_module send_recv_module = { NULL, NULL, /* prev and next */ { "Transport-Test", 14}, /* Name. */ @@ -113,8 +114,18 @@ static pjsip_module my_module = static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata) { + pjsip_to_hdr *to_hdr = rdata->msg_info.to; + pjsip_sip_uri *target = (pjsip_sip_uri*)pjsip_uri_get_uri(to_hdr->uri); + unsigned tid; + + if (!is_user_equal(rdata->msg_info.from, "transport_send_recv_test")) + return PJ_FALSE; + + tid = (unsigned)pj_strtoul(&target->user); + pj_assert(tid < PJSIP_TRANSPORT_START_OTHER); + /* Check that this is our request. */ - if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) { + if (pj_strcmp2(&rdata->msg_info.cid->id, SEND_RECV_CALL_ID_HDR) == 0) { /* It is! */ /* Send response. */ pjsip_tx_data *tdata; @@ -123,18 +134,18 @@ static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata) status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata); if (status != PJ_SUCCESS) { - recv_status = status; + sr_g[tid].recv_status = status; return PJ_TRUE; } status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr); if (status != PJ_SUCCESS) { - recv_status = status; + sr_g[tid].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; + sr_g[tid].recv_status = status; pjsip_tx_data_dec_ref(tdata); return PJ_TRUE; } @@ -147,9 +158,19 @@ static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata) 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; + pjsip_to_hdr *to_hdr = rdata->msg_info.to; + pjsip_sip_uri *target = (pjsip_sip_uri*)pjsip_uri_get_uri(to_hdr->uri); + unsigned tid; + + if (!is_user_equal(rdata->msg_info.from, "transport_send_recv_test")) + return PJ_FALSE; + + tid = (unsigned)pj_strtoul(&target->user); + pj_assert(tid < PJSIP_TRANSPORT_START_OTHER); + + if (pj_strcmp2(&rdata->msg_info.cid->id, SEND_RECV_CALL_ID_HDR) == 0) { + pj_get_timestamp(&sr_g[tid].my_recv_time); + sr_g[tid].recv_status = PJ_SUCCESS; return PJ_TRUE; } return PJ_FALSE; @@ -159,13 +180,16 @@ static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata) static void send_msg_callback(pjsip_send_state *stateless_data, pj_ssize_t sent, pj_bool_t *cont) { - PJ_UNUSED_ARG(stateless_data); + unsigned tid = (unsigned)(long)stateless_data->token; + pj_assert(tid < PJSIP_TRANSPORT_START_OTHER); if (sent < 1) { /* Obtain the error code. */ - send_status = (int)-sent; + PJ_LOG(3,(THIS_FILE, " Sending %s got callback error %ld", + stateless_data->tdata->info, -sent)); + sr_g[tid].send_status = (int)-sent; } else { - send_status = PJ_SUCCESS; + sr_g[tid].send_status = PJ_SUCCESS; } /* Don't want to continue. */ @@ -176,10 +200,12 @@ static void send_msg_callback(pjsip_send_state *stateless_data, /* Test that we receive loopback message. */ int transport_send_recv_test( pjsip_transport_type_e tp_type, pjsip_transport *ref_tp, - char *target_url, + const char *host_port_transport, int *p_usec_rtt) { + unsigned tid = tp_type; pj_bool_t msg_log_enabled; + char target_url[64]; pj_status_t status; pj_str_t target, from, to, contact, call_id, body; pjsip_method method; @@ -192,23 +218,29 @@ int transport_send_recv_test( pjsip_transport_type_e tp_type, 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 ); + pj_enter_critical_section(); + if (send_recv_module.id == -1) { + status = pjsip_endpt_register_module( endpt, &send_recv_module ); if (status != PJ_SUCCESS) { + pj_leave_critical_section(); app_perror(" error: unable to register module", status); return -500; } } + pj_leave_critical_section(); /* Disable message logging. */ msg_log_enabled = msg_logger_set_enabled(0); + pj_ansi_snprintf(target_url, sizeof(target_url), "sip:%d@%s", + tp_type, host_port_transport); + /* Create a request message. */ target = pj_str(target_url); - from = pj_str(FROM_HDR); + from = pj_str(SEND_RECV_FROM_HDR); to = pj_str(target_url); contact = pj_str(CONTACT_HDR); - call_id = pj_str(CALL_ID_HDR); + call_id = pj_str(SEND_RECV_CALL_ID_HDR); body = pj_str(BODY); pjsip_method_set(&method, PJSIP_OPTIONS_METHOD); @@ -221,20 +253,35 @@ int transport_send_recv_test( pjsip_transport_type_e tp_type, } /* Reset statuses */ - send_status = recv_status = NO_STATUS; + sr_g[tid].send_status = sr_g[tid].recv_status = NO_STATUS; + + /* Need this to make sure we use our loop transport rather than other + * loop transport instances created by other test thread (which they + * can disappear at any time) + */ + if (tp_type==PJSIP_TRANSPORT_LOOP_DGRAM) { + pjsip_tpselector tp_sel; + pj_bzero(&tp_sel, sizeof(tp_sel)); + tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT; + tp_sel.u.transport = ref_tp; + + pjsip_tx_data_set_transport(tdata, &tp_sel); + } /* Start time. */ - pj_get_timestamp(&my_send_time); + pj_get_timestamp(&sr_g[tid].my_send_time); /* Send the message (statelessly). */ - PJ_LOG(5,(THIS_FILE, "Sending request to %.*s", + PJ_LOG(3,(THIS_FILE, "Sending request to %.*s", (int)target.slen, target.ptr)); - status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, + status = pjsip_endpt_send_request_stateless( endpt, tdata, (void*)(long)tid, &send_msg_callback); if (status != PJ_SUCCESS) { /* Immediate error! */ + PJ_LOG(3,(THIS_FILE, " Sending %s to %.*s got immediate error %d", + tdata->info, (int)target.slen, target.ptr, status)); pjsip_tx_data_dec_ref(tdata); - send_status = status; + sr_g[tid].send_status = status; } /* Set the timeout (2 seconds from now) */ @@ -253,19 +300,19 @@ int transport_send_recv_test( pjsip_transport_type_e tp_type, goto on_return; } - if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) { - app_perror(" error sending message", send_status); + if (sr_g[tid].send_status!=NO_STATUS && sr_g[tid].send_status!=PJ_SUCCESS) { + app_perror(" error sending message", sr_g[tid].send_status); status = -550; goto on_return; } - if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) { - app_perror(" error receiving message", recv_status); + if (sr_g[tid].recv_status!=NO_STATUS && sr_g[tid].recv_status!=PJ_SUCCESS) { + app_perror(" error receiving message", sr_g[tid].recv_status); status = -560; goto on_return; } - if (send_status!=NO_STATUS && recv_status!=NO_STATUS) { + if (sr_g[tid].send_status!=NO_STATUS && sr_g[tid].recv_status!=NO_STATUS) { /* Success! */ break; } @@ -276,7 +323,7 @@ int transport_send_recv_test( pjsip_transport_type_e tp_type, if (status == PJ_SUCCESS) { unsigned usec_rt; - usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time); + usec_rt = pj_elapsed_usec(&sr_g[tid].my_send_time, &sr_g[tid].my_recv_time); PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt)); @@ -322,25 +369,46 @@ static pjsip_module rt_module = NULL, /* tsx_handler() */ }; -static struct +enum { - 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; + STOP_SEND = 1, + STOP_RECV = 2, +}; + +static struct rt_global_t { + 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]; + + char rt_target_uri[64]; + int rt_stop; + pj_str_t rt_call_id; + pjsip_transport *rt_transport; + +} g_rt[PJSIP_TRANSPORT_START_OTHER]; 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_to_hdr *to_hdr = rdata->msg_info.to; + pjsip_sip_uri *target = (pjsip_sip_uri*)pjsip_uri_get_uri(to_hdr->uri); + unsigned tid; + + if (!is_user_equal(rdata->msg_info.from, "transport_rt_test")) + return PJ_FALSE; + + tid = (unsigned)pj_strtoul(&target->user); + pj_assert(tid < PJSIP_TRANSPORT_START_OTHER); + + if (!pj_strncmp(&rdata->msg_info.cid->id, &g_rt[tid].rt_call_id, + g_rt[tid].rt_call_id.slen)) + { pjsip_tx_data *tdata; pjsip_response_addr res_addr; pj_status_t status; @@ -368,21 +436,22 @@ static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata) return PJ_FALSE; } -static pj_status_t rt_send_request(int thread_id) +static pj_status_t rt_send_request(unsigned tid, 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; + pjsip_tpselector tp_sel; - pj_mutex_lock(rt_test_data[thread_id].mutex); + pj_mutex_lock(g_rt[tid].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); + target = pj_str(g_rt[tid].rt_target_uri); + from = pj_str(RT_FROM_HDR); + to = pj_str(g_rt[tid].rt_target_uri); contact = pj_str(CONTACT_HDR); - call_id = rt_test_data[thread_id].call_id; + call_id = g_rt[tid].rt_test_data[thread_id].call_id; status = pjsip_endpt_create_request( endpt, &pjsip_options_method, &target, &from, &to, @@ -390,12 +459,19 @@ static pj_status_t rt_send_request(int thread_id) NULL, &tdata ); if (status != PJ_SUCCESS) { app_perror(" error: unable to create request", status); - pj_mutex_unlock(rt_test_data[thread_id].mutex); + pj_mutex_unlock(g_rt[tid].rt_test_data[thread_id].mutex); return -610; } + if (g_rt[tid].rt_transport) { + pj_bzero(&tp_sel, sizeof(tp_sel)); + tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT; + tp_sel.u.transport = g_rt[tid].rt_transport; + pjsip_tx_data_set_transport(tdata, &tp_sel); + + } /* Start time. */ - pj_get_timestamp(&rt_test_data[thread_id].send_time); + pj_get_timestamp(&g_rt[tid].rt_test_data[thread_id].send_time); /* Send the message (statelessly). */ status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, NULL); @@ -403,54 +479,66 @@ static pj_status_t rt_send_request(int thread_id) /* Immediate error! */ app_perror(" error: send request", status); pjsip_tx_data_dec_ref(tdata); - pj_mutex_unlock(rt_test_data[thread_id].mutex); + pj_mutex_unlock(g_rt[tid].rt_test_data[thread_id].mutex); return -620; } /* Update counter. */ - rt_test_data[thread_id].sent_request_count++; + g_rt[tid].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); + if (g_rt[tid].rt_test_data[thread_id].timeout_timer.user_data != NULL) { + pjsip_endpt_cancel_timer(endpt, &g_rt[tid].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*)(pj_ssize_t)1; - pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].timeout_timer, + g_rt[tid].rt_test_data[thread_id].timeout_timer.user_data = (void*)(pj_ssize_t)1; + pjsip_endpt_schedule_timer(endpt, &g_rt[tid].rt_test_data[thread_id].timeout_timer, &timeout_delay); - pj_mutex_unlock(rt_test_data[thread_id].mutex); + pj_mutex_unlock(g_rt[tid].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)) { + pjsip_to_hdr *to_hdr = rdata->msg_info.to; + pjsip_sip_uri *target = (pjsip_sip_uri*)pjsip_uri_get_uri(to_hdr->uri); + unsigned tid; + + if (!is_user_equal(rdata->msg_info.from, "transport_rt_test")) + return PJ_FALSE; + + tid = (unsigned)pj_strtoul(&target->user); + pj_assert(tid < PJSIP_TRANSPORT_START_OTHER); + + if (!pj_strncmp(&rdata->msg_info.cid->id, &g_rt[tid].rt_call_id, + g_rt[tid].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); + pj_mutex_lock(g_rt[tid].rt_test_data[thread_id].mutex); /* Stop timer. */ - pjsip_endpt_cancel_timer(endpt, &rt_test_data[thread_id].timeout_timer); + pjsip_endpt_cancel_timer(endpt, &g_rt[tid].rt_test_data[thread_id].timeout_timer); /* Update counter and end-time. */ - rt_test_data[thread_id].recv_response_count++; + g_rt[tid].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); + pj_sub_timestamp(&recv_time, &g_rt[tid].rt_test_data[thread_id].send_time); + pj_add_timestamp(&g_rt[tid].rt_test_data[thread_id].total_rt_time, &recv_time); - if (!rt_stop) { + if ((g_rt[tid].rt_stop & STOP_SEND)==0) { 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*)(pj_ssize_t)1; - pjsip_endpt_schedule_timer(endpt, &rt_test_data[thread_id].tx_timer, + pj_assert(g_rt[tid].rt_test_data[thread_id].tx_timer.user_data == NULL); + g_rt[tid].rt_test_data[thread_id].tx_timer.user_data = (void*)(pj_ssize_t)1; + pjsip_endpt_schedule_timer(endpt, &g_rt[tid].rt_test_data[thread_id].tx_timer, &tx_delay); } - pj_mutex_unlock(rt_test_data[thread_id].mutex); + pj_mutex_unlock(g_rt[tid].rt_test_data[thread_id].mutex); return PJ_TRUE; } @@ -460,64 +548,76 @@ static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata) 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); + unsigned tid = entry->id >> 16; + unsigned thread_id = entry->id & 0xFFFF; + + pj_assert(tid < PJSIP_TRANSPORT_START_OTHER); + pj_mutex_lock(g_rt[tid].rt_test_data[thread_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; + g_rt[tid].rt_test_data[thread_id].timeout_timer.user_data = NULL; - if (rt_test_data[entry->id].tx_timer.user_data == NULL) { + if (g_rt[tid].rt_test_data[thread_id].tx_timer.user_data == NULL) { pj_time_val delay = { 0, 0 }; - rt_test_data[entry->id].tx_timer.user_data = (void*)(pj_ssize_t)1; - pjsip_endpt_schedule_timer(endpt, &rt_test_data[entry->id].tx_timer, + g_rt[tid].rt_test_data[thread_id].tx_timer.user_data = (void*)(pj_ssize_t)1; + pjsip_endpt_schedule_timer(endpt, &g_rt[tid].rt_test_data[thread_id].tx_timer, &delay); } - pj_mutex_unlock(rt_test_data[entry->id].mutex); + pj_mutex_unlock(g_rt[tid].rt_test_data[thread_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); + unsigned tid = entry->id >> 16; + unsigned thread_id = entry->id & 0xFFFF; + + pj_assert(tid < PJSIP_TRANSPORT_START_OTHER); + pj_mutex_lock(g_rt[tid].rt_test_data[thread_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_assert(g_rt[tid].rt_test_data[thread_id].tx_timer.user_data != NULL); + g_rt[tid].rt_test_data[thread_id].tx_timer.user_data = NULL; + rt_send_request(tid, thread_id); - pj_mutex_unlock(rt_test_data[entry->id].mutex); + pj_mutex_unlock(g_rt[tid].rt_test_data[thread_id].mutex); } static int rt_worker_thread(void *arg) { + unsigned tid; int i; pj_time_val poll_delay = { 0, 10 }; - PJ_UNUSED_ARG(arg); + tid = (unsigned)(long)arg; + pj_assert(tid < PJSIP_TRANSPORT_START_OTHER); /* Sleep to allow main threads to run. */ pj_thread_sleep(10); - while (!rt_stop) { + while ((g_rt[tid].rt_stop & STOP_RECV)==0) { pjsip_endpt_handle_events(endpt, &poll_delay); } /* Exhaust responses. */ - for (i=0; i<100; ++i) + 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, + const char *host_port_transport, int *lost) { - enum { THREADS = 4, INTERVAL = 10 }; - int i; + enum { THREADS = 1, INTERVAL = 120 }; + int i, tid=tp_type; + char target_url[80]; pj_status_t status; pj_pool_t *pool; pj_bool_t logger_enabled; @@ -539,13 +639,16 @@ int transport_rt_test( pjsip_transport_type_e tp_type, logger_enabled = msg_logger_set_enabled(0); /* Register module (if not yet registered) */ + pj_enter_critical_section(); if (rt_module.id == -1) { status = pjsip_endpt_register_module( endpt, &rt_module ); if (status != PJ_SUCCESS) { + pj_leave_critical_section(); app_perror(" error: unable to register module", status); return -600; } } + pj_leave_critical_section(); /* Create pool for this test. */ pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000); @@ -553,9 +656,18 @@ int transport_rt_test( pjsip_transport_type_e tp_type, return -610; /* Initialize static test data. */ - pj_ansi_strxcpy(rt_target_uri, target_url, sizeof(rt_target_uri)); - rt_call_id = pj_str("RT-Call-Id/"); - rt_stop = PJ_FALSE; + pj_ansi_snprintf(target_url, sizeof(target_url), "sip:%d@%s", + tp_type, host_port_transport); + pj_ansi_strxcpy(g_rt[tid].rt_target_uri, target_url, + sizeof(g_rt[tid].rt_target_uri)); + g_rt[tid].rt_call_id = pj_str("RT-Call-Id/"); + g_rt[tid].rt_stop = 0; + + pj_bzero(g_rt[tid].rt_test_data, sizeof(g_rt[tid].rt_test_data)); + + /* Need to use specific loop transport (otherwise we may get transport + * that is being shutdown) */ + g_rt[tid].rt_transport = tp_type==PJSIP_TRANSPORT_LOOP_DGRAM? ref_tp : NULL; /* 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; + pjsip_to_hdr *to_hdr = rdata->msg_info.to; + pjsip_sip_uri *target = (pjsip_sip_uri*)pjsip_uri_get_uri(to_hdr->uri); + unsigned tid; + + if (!is_user_equal(rdata->msg_info.from, "transport_load_test")) + return PJ_FALSE; + + tid = (unsigned)pj_strtoul(&target->user); + pj_assert(tid < PJSIP_TRANSPORT_START_OTHER); + + if (rdata->msg_info.cseq->cseq != g_lt[tid].next_seq) { + PJ_LOG(1,(THIS_FILE, " err: expecting cseq %u, got %u", + g_lt[tid].next_seq, rdata->msg_info.cseq->cseq)); + g_lt[tid].err = PJ_TRUE; + g_lt[tid].next_seq = rdata->msg_info.cseq->cseq + 1; } else - mod_load.next_seq++; + g_lt[tid].next_seq++; return PJ_TRUE; } -int transport_load_test(char *target_url) +int transport_load_test(pjsip_transport_type_e tp_type, + const char *host_port_transport) { +#define ERR(rc__) { rc=rc__; goto on_return; } enum { COUNT = 2000 }; - unsigned i; - pj_status_t status = PJ_SUCCESS; + char target_url[64]; + unsigned i, tid=tp_type; + int rc; + + pj_ansi_snprintf(target_url, sizeof(target_url), "sip:%d@%s", + tp_type, host_port_transport); /* exhaust packets */ - do { - pj_time_val delay = {1, 0}; - i = 0; - pjsip_endpt_handle_events2(endpt, &delay, &i); - } while (i != 0); + flush_events(500); 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; + pj_enter_critical_section(); + if (mod_load_test.id == -1) { + rc = pjsip_endpt_register_module( endpt, &mod_load_test); + if (rc != PJ_SUCCESS) { + pj_leave_critical_section(); + app_perror("error registering module", rc); + return -610; } } - mod_load.err = PJ_FALSE; - mod_load.next_seq = 0; + pj_leave_critical_section(); + g_lt[tid].err = PJ_FALSE; + g_lt[tid].next_seq = 0; - for (i=0; i"); + from = pj_str(""); call_id = pj_str("thecallid"); - status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + PJ_TEST_SUCCESS(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; - } + i, NULL, &tdata ), + NULL, ERR(-620)); - status = pjsip_endpt_send_request_stateless(endpt, tdata, NULL, NULL); - if (status != PJ_SUCCESS) { - app_perror("error sending request", status); - goto on_return; - } - } + PJ_TEST_SUCCESS(pjsip_endpt_send_request_stateless(endpt, tdata, + NULL, NULL), + NULL, ERR(-630)); - 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; + flush_events(20); } + flush_events(1000); + + PJ_TEST_EQ(g_lt[tid].next_seq, COUNT, "message count mismatch", + ERR(-640)); + + rc = 0; + 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; + if (mod_load_test.id != -1) { + /* Don't unregister if there are multiple transport_load_test() */ + pjsip_endpt_unregister_module( endpt, &mod_load_test); + mod_load_test.id = -1; } - PJ_LOG(3,(THIS_FILE, " success")); - return 0; + return rc; } diff --git a/pjsip/src/test/transport_udp_test.c b/pjsip/src/test/transport_udp_test.c index 2c063d4846..958e954e15 100644 --- a/pjsip/src/test/transport_udp_test.c +++ b/pjsip/src/test/transport_udp_test.c @@ -23,87 +23,99 @@ #define THIS_FILE "transport_udp_test.c" -static pj_status_t multi_transport_test(pjsip_transport *tp[], unsigned num_tp) +static pj_status_t multi_transport_test(pjsip_transport *tp[], unsigned max_tp) { - pj_status_t status; - unsigned i = 0; +#define ERR(rc__) { rc=rc__; goto on_return; } + int rc; + unsigned i, num_tp=0; pj_str_t s; - pjsip_transport *udp_tp; + pjsip_transport *other_udp_tp = NULL, *udp_tp; pj_sockaddr_in rem_addr; pjsip_tpselector tp_sel; - for (;iref_cnt) != 1) - return -120; + PJ_TEST_EQ(pj_atomic_get(udp_tp->ref_cnt), 1, NULL, ERR(-120)); - /* Test basic transport attributes */ - status = generic_transport_test(udp_tp); - if (status != PJ_SUCCESS) - return status; - - tp[i] = udp_tp; + tp[num_tp++] = udp_tp; } for (i = 0; i < num_tp; ++i) { - udp_tp = tp[i]; - if (pj_atomic_get(udp_tp->ref_cnt) != 1) - return -130; + PJ_TEST_EQ(pj_atomic_get(tp[i]->ref_cnt), 1, NULL, ERR(-130)); + + /* Test basic transport attributes */ + rc = generic_transport_test(udp_tp); + if (rc != 0) + goto on_return; } /* Acquire transport test without selector. */ pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80); - status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, + PJ_TEST_SUCCESS(pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, &rem_addr, sizeof(rem_addr), - NULL, &udp_tp); - if (status != PJ_SUCCESS) - return -140; + NULL, &udp_tp), + NULL, ERR(-140)); for (i = 0; i < num_tp; ++i) { if (udp_tp == tp[i]) { break; } } - if (i == num_tp) - return -150; + PJ_TEST_TRUE(iref_cnt) != 1) - return -160; + if (udp_tp == other_udp_tp) { + PJ_TEST_GT(pj_atomic_get(udp_tp->ref_cnt), 1, NULL, ERR(-160)); + } else { + PJ_TEST_EQ(pj_atomic_get(udp_tp->ref_cnt), 1, NULL, ERR(-165)); + } /* Acquire transport test with selector. */ pj_bzero(&tp_sel, sizeof(tp_sel)); tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT; tp_sel.u.transport = tp[num_tp-1]; pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80); - status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, + PJ_TEST_SUCCESS( pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, &rem_addr, sizeof(rem_addr), - &tp_sel, &udp_tp); - if (status != PJ_SUCCESS) - return -170; + &tp_sel, &udp_tp), + NULL, ERR(-170)); - if (udp_tp != tp[num_tp-1]) - return -180; + PJ_TEST_EQ(udp_tp, tp[num_tp-1], NULL, ERR(-180)); pjsip_transport_dec_ref(udp_tp); - if (pj_atomic_get(udp_tp->ref_cnt) != 1) - return -190; + PJ_TEST_EQ(pj_atomic_get(udp_tp->ref_cnt), 1, NULL, ERR(-190)); + + rc = 0; + +on_return: + if (other_udp_tp) { + pjsip_transport_dec_ref(other_udp_tp); + } + if (rc != 0) { + for (i=0; ipool, &tsx_key, &tsx->transaction_key); found = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE); @@ -72,7 +86,7 @@ static int tsx_layer_test(void) } /* Double terminate test. */ -static int double_terminate(void) +static int double_terminate(unsigned tid) { pj_str_t target, from, tsx_key; pjsip_tx_data *tdata; @@ -81,8 +95,8 @@ static int double_terminate(void) PJ_LOG(3,(THIS_FILE, " double terminate test")); - target = pj_str(TARGET_URI); - from = pj_str(FROM_URI); + target = pj_str(g[tid].TARGET_URI); + from = pj_str(g[tid].FROM_URI); /* Create request. */ status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, @@ -100,6 +114,16 @@ static int double_terminate(void) return -20; } + if (g[tid].tp) { + pjsip_tpselector tp_sel; + + pj_bzero(&tp_sel, sizeof(tp_sel)); + tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT; + tp_sel.u.transport = g[tid].tp; + + pjsip_tsx_set_transport(tsx, &tp_sel); + } + /* Save transaction key for later. */ pj_strdup_with_null(tdata->pool, &tsx_key, &tsx->transaction_key); @@ -135,26 +159,44 @@ static int double_terminate(void) return PJ_SUCCESS; } -int tsx_basic_test(struct tsx_test_param *param) +int tsx_basic_test(unsigned tid) { + struct tsx_test_param *param = &tsx_test[tid]; + pjsip_transport *loop = NULL; int status; - pj_ansi_snprintf(TARGET_URI, sizeof(TARGET_URI), - "sip:bob@127.0.0.1:%d;transport=%s", + g[tid].tp = NULL; + + if (param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + PJ_TEST_SUCCESS(pjsip_loop_start(endpt, &loop), NULL, return -10); + pjsip_transport_add_ref(loop); + g[tid].tp = loop; + } + pj_ansi_snprintf(g[tid].TARGET_URI, sizeof(g[tid].TARGET_URI), + "sip:tsx_basic_test@127.0.0.1:%d;transport=%s", param->port, param->tp_type); - pj_ansi_snprintf(FROM_URI, sizeof(FROM_URI), - "sip:alice@127.0.0.1:%d;transport=%s", + pj_ansi_snprintf(g[tid].FROM_URI, sizeof(g[tid].FROM_URI), + "sip:tsx_basic_test@127.0.0.1:%d;transport=%s", param->port, param->tp_type); - status = tsx_layer_test(); + status = tsx_layer_test(tid); if (status != 0) - return status; + goto on_return; - status = double_terminate(); + status = double_terminate(tid); if (status != 0) - return status; + goto on_return; - return 0; + status = 0; + +on_return: + if (loop) { + /* Order must be shutdown then dec_ref so it gets destroyed */ + pjsip_transport_shutdown(loop); + pjsip_transport_dec_ref(loop); + flush_events(500); + } + return status; } /**************************************************************************/ diff --git a/pjsip/src/test/tsx_bench.c b/pjsip/src/test/tsx_bench.c index 30b2aa2209..8c0d8bf85b 100644 --- a/pjsip/src/test/tsx_bench.c +++ b/pjsip/src/test/tsx_bench.c @@ -20,7 +20,7 @@ #include #include -#define THIS_FILE "tsx_uas_test.c" +#define THIS_FILE "tsx_bench.c" static pjsip_module mod_tsx_user; @@ -32,22 +32,19 @@ static int uac_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) pjsip_transaction **tsx; pj_timestamp t1, t2, elapsed; pjsip_via_hdr *via; - pj_status_t status; + int rc; /* 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_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, + PJ_TEST_SUCCESS(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; - } + &request), + NULL, return -110); via = (pjsip_via_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_VIA, NULL); @@ -62,9 +59,9 @@ static int uac_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) elapsed.u64 = 0; pj_get_timestamp(&t1); for (i=0; ibranch_param.slen = 0; } @@ -73,7 +70,7 @@ static int uac_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) pj_add_timestamp(&elapsed, &t2); p_elapsed->u64 = elapsed.u64; - status = PJ_SUCCESS; + rc = 0; on_error: for (i=0; i"); + 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, + PJ_TEST_SUCCESS( 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; - } + &request), + NULL, return -210); /* Create Via */ via = pjsip_via_hdr_create(request->pool); @@ -141,15 +135,10 @@ static int uas_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) rdata.msg_info.cid = (pjsip_cid_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_CALL_ID, 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; - } - + PJ_TEST_SUCCESS(pjsip_loop_start(endpt, &loop), NULL, + { pjsip_tx_data_dec_ref(request); return -220; }); + pjsip_transport_add_ref(loop); + rdata.tp_info.transport = loop; /* Create transaction array */ tsx = (pjsip_transaction**) pj_pool_zalloc(request->pool, working_set * sizeof(pjsip_transaction*)); @@ -167,17 +156,15 @@ static int uas_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) pj_ansi_snprintf(branch_buf+PJSIP_RFC3261_BRANCH_LEN, sizeof(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_TEST_SUCCESS(pjsip_tsx_create_uas(&mod_tsx_user, &rdata, &tsx[i]), + NULL, { rc=-230; 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; + rc = 0; on_error: for (i=0; itp_type is loop. */ + pjsip_transport *loop; + + struct my_timer timer; + +} g[MAX_TSX_TESTS]; 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); @@ -118,13 +142,17 @@ static pjsip_module tsx_user = &tsx_user_on_tsx_state, /* on_tsx_state() */ }; -/* Module to receive the loop-backed request. */ +/* Module to receive the loop-backed request and also process tx msgs. */ static pjsip_module msg_receiver = { NULL, NULL, /* prev and next */ { "Msg-Receiver", 12}, /* Name. */ -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ + /* Note: + * Priority needs to be more important than UA layer, because UA layer + * silently absorbs ACK with To tag. + */ + PJSIP_MOD_PRIORITY_UA_PROXY_LAYER-1,/* Priority */ NULL, /* load() */ NULL, /* start() */ NULL, /* stop() */ @@ -136,21 +164,59 @@ static pjsip_module msg_receiver = 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; +/* Init uac test */ +static int init_test(unsigned tid) +{ + pj_enter_critical_section(); + if (tsx_user.id == -1) { + PJ_TEST_SUCCESS(pjsip_endpt_register_module(endpt, &tsx_user), NULL, + { pj_leave_critical_section(); return -30; }); + } -/* Loop transport instance. */ -static pjsip_transport *loop; + if (msg_receiver.id == -1) { + PJ_TEST_SUCCESS(pjsip_endpt_register_module(endpt, &msg_receiver), NULL, + { pj_leave_critical_section(); return -40; }); + } + pj_leave_critical_section(); + + pj_assert(g[tid].loop==NULL); + + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + PJ_TEST_SUCCESS(pjsip_loop_start(endpt, &g[tid].loop), + NULL, return -50); + pjsip_transport_add_ref(g[tid].loop); + } + return PJ_SUCCESS; +} -/* General timer entry to be used by tests. */ -static struct my_timer +/* Finish test */ +static void finish_test(unsigned tid) { - pj_timer_entry entry; - char key_buf[1024]; - pj_str_t tsx_key; -} timer; + /* Note: don't unregister modules on_tsx_state() may be called when + * transaction layer is shutdown later, which will cause + * get_tsx_tid() to be called and it needs the module id. + */ + if (g[tid].loop) { + /* Order must be shutdown then dec_ref so it gets destroyed */ + pjsip_transport_shutdown(g[tid].loop); + pjsip_transport_dec_ref(g[tid].loop); + g[tid].loop = 0; + } +} + +/* Get test ID from transaction instance */ +static unsigned get_tsx_tid(const pjsip_transaction *tsx) +{ + pj_assert(tsx_user.id >= 0); + return (unsigned)(long)tsx->mod_data[tsx_user.id]; +} + +/* Set test ID to transaction instance */ +static void set_tsx_tid(pjsip_transaction *tsx, unsigned tid) +{ + pj_assert(tsx_user.id >= 0); + tsx->mod_data[tsx_user.id] = (void*)(long)tid; +} /* * This is the handler to receive state changed notification from the @@ -159,34 +225,63 @@ static struct my_timer */ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) { - if (pj_stricmp2(&tsx->branch, TEST1_BRANCH_ID)==0) { + unsigned tid = get_tsx_tid(tsx); + + /* + PJ_LOG(3,(THIS_FILE, + " on_tsx_state state: %s, event: %s (%s)", + pjsip_tsx_state_str(tsx->state), + pjsip_event_str(e->type), + pjsip_event_str(e->body.tsx_state.type) + )); + */ + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM && + e->type==PJSIP_EVENT_TSX_STATE) + { + if (e->body.tsx_state.type==PJSIP_EVENT_RX_MSG) { + PJ_TEST_EQ( e->body.tsx_state.src.rdata->tp_info.transport, + g[tid].loop, NULL, { + g[tid].test_complete = -704; + return; + }); + } else if (e->body.tsx_state.type==PJSIP_EVENT_TX_MSG && + e->body.tsx_state.src.tdata->dest_info.addr.count) { + PJ_TEST_EQ( e->body.tsx_state.src.tdata->tp_info.transport, + g[tid].loop, NULL, { + g[tid].test_complete = -706; + return; + }); + } + } + + if (pj_strnicmp2(&tsx->branch, TEST1_BRANCH_ID, BRANCH_LEN)==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; + if (g[tid].test_complete == 0) + g[tid].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; + g[tid].test_complete = -710; } /* If transport is reliable, then there must not be any * retransmissions. */ - if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { - if (recv_count != 1) { + if (g[tid].tp_flag & PJSIP_TRANSPORT_RELIABLE) { + if (g[tid].recv_count != 1) { PJ_LOG(3,(THIS_FILE, " error: there were %d (re)transmissions", - recv_count)); - test_complete = -715; + g[tid].recv_count)); + g[tid].test_complete = -715; } } else { /* Check the number of (re)transmissions, which must be @@ -197,29 +292,29 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) * fires first which causes recv_count fall short (by one). */ //if (tsx->method.id==PJSIP_INVITE_METHOD && recv_count != 7) { - if (tsx->method.id==PJSIP_INVITE_METHOD && recv_count < 6) { + if (tsx->method.id==PJSIP_INVITE_METHOD && g[tid].recv_count < 6) { PJ_LOG(3,(THIS_FILE, " error: there were %d (re)transmissions", - recv_count)); - test_complete = -716; + g[tid].recv_count)); + g[tid].test_complete = -716; } else //if (tsx->method.id==PJSIP_OPTIONS_METHOD && recv_count != 11) { - if (tsx->method.id==PJSIP_OPTIONS_METHOD && recv_count < 10) { + if (tsx->method.id==PJSIP_OPTIONS_METHOD && g[tid].recv_count < 10) { PJ_LOG(3,(THIS_FILE, " error: there were %d (re)transmissions", - recv_count)); - test_complete = -717; + g[tid].recv_count)); + g[tid].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; + g[tid].test_complete = -718; } } } - } else if (pj_stricmp2(&tsx->branch, TEST2_BRANCH_ID)==0) { + } else if (pj_strnicmp2(&tsx->branch, TEST2_BRANCH_ID, BRANCH_LEN)==0) { /* * Transaction with TEST2_BRANCH_ID should terminate with transport error. */ @@ -233,14 +328,14 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) " error: status code is %d instead of %d or %d", tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR, PJSIP_SC_BAD_GATEWAY)); - test_complete = -720; + g[tid].test_complete = -720; } - if (test_complete == 0) - test_complete = 1; + if (g[tid].test_complete == 0) + g[tid].test_complete = 1; } - } else if (pj_stricmp2(&tsx->branch, TEST3_BRANCH_ID)==0) { + } else if (pj_strnicmp2(&tsx->branch, TEST3_BRANCH_ID, BRANCH_LEN)==0) { /* * This test terminates the transaction while resolver is still * running. @@ -257,15 +352,15 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: status code is %d instead of %d", tsx->status_code, PJSIP_SC_REQUEST_TERMINATED)); - test_complete = -730; + g[tid].test_complete = -730; } - if (test_complete == 0) - test_complete = 1; + if (g[tid].test_complete == 0) + g[tid].test_complete = 1; } - } else if (pj_stricmp2(&tsx->branch, TEST4_BRANCH_ID)==0) { + } else if (pj_strnicmp2(&tsx->branch, TEST4_BRANCH_ID, BRANCH_LEN)==0) { /* * This test simulates transport failure after several * retransmissions. @@ -277,7 +372,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: status code is %d instead of %d", tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR)); - test_complete = -730; + g[tid].test_complete = -730; } /* Must have correct retransmission count. */ @@ -285,15 +380,15 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: retransmit cnt is %d instead of %d", tsx->retransmit_count, TEST4_RETRANSMIT_CNT)); - test_complete = -731; + g[tid].test_complete = -731; } - if (test_complete == 0) - test_complete = 1; + if (g[tid].test_complete == 0) + g[tid].test_complete = 1; } - } else if (pj_stricmp2(&tsx->branch, TEST5_BRANCH_ID)==0) { + } else if (pj_strnicmp2(&tsx->branch, TEST5_BRANCH_ID, BRANCH_LEN)==0) { /* * This test simulates transport failure after several * retransmissions. @@ -305,7 +400,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: status code is %d instead of %d", tsx->status_code, PJSIP_SC_REQUEST_TERMINATED)); - test_complete = -733; + g[tid].test_complete = -733; } /* Must have correct retransmission count. */ @@ -313,15 +408,15 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: retransmit cnt is %d instead of %d", tsx->retransmit_count, TEST5_RETRANSMIT_CNT)); - test_complete = -734; + g[tid].test_complete = -734; } - if (test_complete == 0) - test_complete = 1; + if (g[tid].test_complete == 0) + g[tid].test_complete = 1; } - } else if (pj_stricmp2(&tsx->branch, TEST6_BRANCH_ID)==0) { + } else if (pj_strnicmp2(&tsx->branch, TEST6_BRANCH_ID, BRANCH_LEN)==0) { /* * Successfull non-INVITE transaction. */ @@ -332,7 +427,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: status code is %d instead of %d", tsx->status_code, 202)); - test_complete = -736; + g[tid].test_complete = -736; } /* Must have correct retransmission count. */ @@ -340,18 +435,18 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: retransmit cnt is %d instead of %d", tsx->retransmit_count, 0)); - test_complete = -737; + g[tid].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; + g[tid].test_complete = -738; } - if (test_complete == 0) { - test_complete = 1; + if (g[tid].test_complete == 0) { + g[tid].test_complete = 1; pjsip_tsx_terminate(tsx, 202); } @@ -359,12 +454,12 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* Previous state must be COMPLETED. */ if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - test_complete = -7381; + g[tid].test_complete = -7381; } } - } else if (pj_stricmp2(&tsx->branch, TEST7_BRANCH_ID)==0) { + } else if (pj_strnicmp2(&tsx->branch, TEST7_BRANCH_ID, BRANCH_LEN)==0) { /* * Successfull non-INVITE transaction. */ @@ -376,7 +471,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) " 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; + g[tid].test_complete = -739; } /* Status code must be 202. */ @@ -384,7 +479,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: status code is %d instead of %d", tsx->status_code, 202)); - test_complete = -740; + g[tid].test_complete = -740; } /* Must have correct retransmission count. */ @@ -392,18 +487,18 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: retransmit cnt is %d instead of %d", tsx->retransmit_count, 0)); - test_complete = -741; + g[tid].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; + g[tid].test_complete = -741; } - if (test_complete == 0) { - test_complete = 1; + if (g[tid].test_complete == 0) { + g[tid].test_complete = 1; pjsip_tsx_terminate(tsx, 202); } @@ -411,13 +506,13 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* Previous state must be COMPLETED. */ if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - test_complete = -742; + g[tid].test_complete = -742; } } - } else if (pj_stricmp2(&tsx->branch, TEST8_BRANCH_ID)==0) { + } else if (pj_strnicmp2(&tsx->branch, TEST8_BRANCH_ID, BRANCH_LEN)==0) { /* * Failed INVITE transaction. */ @@ -428,7 +523,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: status code is %d instead of %d", tsx->status_code, 301)); - test_complete = -745; + g[tid].test_complete = -745; } /* Must have correct retransmission count. */ @@ -436,14 +531,14 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: retransmit cnt is %d instead of %d", tsx->retransmit_count, 0)); - test_complete = -746; + g[tid].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; + g[tid].test_complete = -747; } /* last_tx MUST be the INVITE request @@ -454,16 +549,19 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) { PJ_LOG(3,(THIS_FILE, " error: last_tx is not INVITE")); - test_complete = -748; + g[tid].test_complete = -748; } } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - test_complete = 1; + g[tid].test_complete = 1; /* Previous state must be COMPLETED. */ if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - test_complete = -750; + PJ_LOG(3,(THIS_FILE, + " error: expecting last state=COMLETED instead of %d", + e->body.tsx_state.prev_state)); + g[tid].test_complete = -750; } /* Status code must be 301. */ @@ -471,13 +569,13 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: status code is %d instead of %d", tsx->status_code, 301)); - test_complete = -751; + g[tid].test_complete = -751; } } - } else if (pj_stricmp2(&tsx->branch, TEST9_BRANCH_ID)==0) { + } else if (pj_strnicmp2(&tsx->branch, TEST9_BRANCH_ID, BRANCH_LEN)==0) { /* * Failed INVITE transaction with provisional response. */ @@ -485,7 +583,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* Previous state must be PJSIP_TSX_STATE_PROCEEDING. */ if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) { - test_complete = -760; + g[tid].test_complete = -760; } /* Status code must be 302. */ @@ -493,7 +591,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: status code is %d instead of %d", tsx->status_code, 302)); - test_complete = -761; + g[tid].test_complete = -761; } /* Must have correct retransmission count. */ @@ -501,14 +599,14 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: retransmit cnt is %d instead of %d", tsx->retransmit_count, 0)); - test_complete = -762; + g[tid].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; + g[tid].test_complete = -763; } /* last_tx MUST be INVITE. @@ -519,17 +617,17 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) { PJ_LOG(3,(THIS_FILE, " error: last_tx is not INVITE")); - test_complete = -764; + g[tid].test_complete = -764; } } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - test_complete = 1; + g[tid].test_complete = 1; /* Previous state must be COMPLETED. */ if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) { - test_complete = -767; + g[tid].test_complete = -767; } /* Status code must be 302. */ @@ -537,7 +635,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: status code is %d instead of %d", tsx->status_code, 302)); - test_complete = -768; + g[tid].test_complete = -768; } } @@ -594,7 +692,34 @@ static void terminate_tsx_callback( pj_timer_heap_t *timer_heap, */ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) { - if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST1_BRANCH_ID) == 0) { + pjsip_to_hdr *to_hdr = rdata->msg_info.to; + pjsip_sip_uri *target = (pjsip_sip_uri*)pjsip_uri_get_uri(to_hdr->uri); + pjsip_to_hdr *from_hdr = rdata->msg_info.from; + pjsip_sip_uri *from_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(from_hdr->uri); + unsigned tid; + + if (pj_strcmp2(&from_uri->user, "tsx_uac_test")) { + /* Not our message */ + return PJ_FALSE; + } + + tid = (unsigned)pj_strtoul(&target->user); + + /* + PJ_LOG(3,(THIS_FILE, " on_rx_request %s (recv_count: %d) on %s, branch: %.*s", + pjsip_rx_data_get_info(rdata), + g[tid].recv_count, rdata->tp_info.transport->info, + (int)rdata->msg_info.via->branch_param.slen, + rdata->msg_info.via->branch_param.ptr)); + */ + + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + PJ_TEST_EQ(rdata->tp_info.transport, g[tid].loop, NULL, + {g[tid].test_complete = -602; return PJ_TRUE;}); + } + + if (pj_strnicmp2(&rdata->msg_info.via->branch_param, TEST1_BRANCH_ID, + BRANCH_LEN) == 0) { /* * The TEST1_BRANCH_ID test performs the verifications for transaction * retransmission mechanism. It will not answer the incoming request @@ -611,14 +736,14 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) PJ_LOG(3,(THIS_FILE, " error: received unexpected method %.*s", (int)msg->line.req.method.name.slen, msg->line.req.method.name.ptr)); - test_complete = -600; + g[tid].test_complete = -600; return PJ_TRUE; } - if (recv_count == 0) { - recv_count++; + if (g[tid].recv_count == 0) { + g[tid].recv_count++; //pj_gettimeofday(&recv_last); - recv_last = rdata->pkt_info.timestamp; + g[tid].recv_last = rdata->pkt_info.timestamp; } else { pj_time_val now; unsigned msec_expected, msec_elapsed; @@ -626,11 +751,11 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) //pj_gettimeofday(&now); now = rdata->pkt_info.timestamp; - PJ_TIME_VAL_SUB(now, recv_last); + PJ_TIME_VAL_SUB(now, g[tid].recv_last); msec_elapsed = now.sec*1000 + now.msec; - ++recv_count; - msec_expected = (1<<(recv_count-2))*pjsip_cfg()->tsx.t1; + ++g[tid].recv_count; + msec_expected = (1<<(g[tid].recv_count-2))*pjsip_cfg()->tsx.t1; if (msg->line.req.method.id != PJSIP_INVITE_METHOD) { if (msec_expected > pjsip_cfg()->tsx.t2) @@ -644,53 +769,55 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) 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; + g[tid].recv_count-1, msec_expected, msec_elapsed)); + g[tid].test_complete = -610; } - if (recv_count > max_received) { + if (g[tid].recv_count > max_received) { PJ_LOG(3,(THIS_FILE, " error: too many messages (%d) received", - recv_count)); - test_complete = -620; + g[tid].recv_count)); + g[tid].test_complete = -620; } //pj_gettimeofday(&recv_last); - recv_last = rdata->pkt_info.timestamp; + g[tid].recv_last = rdata->pkt_info.timestamp; } return PJ_TRUE; } else - if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID) == 0) { + if (pj_strnicmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID, + BRANCH_LEN) == 0) { /* * The TEST4_BRANCH_ID test simulates transport failure after several * retransmissions. */ - recv_count++; + g[tid].recv_count++; - if (recv_count == TEST4_RETRANSMIT_CNT) { + if (g[tid].recv_count == TEST4_RETRANSMIT_CNT) { /* Simulate transport failure. */ - pjsip_loop_set_failure(loop, 2, NULL); + pjsip_loop_set_failure(g[tid].loop, 2, NULL); - } else if (recv_count > TEST4_RETRANSMIT_CNT) { + } else if (g[tid].recv_count > TEST4_RETRANSMIT_CNT) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -631; + g[tid].recv_count)); + g[tid].test_complete = -631; } return PJ_TRUE; } else - if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID) == 0) { + if (pj_strnicmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID, + BRANCH_LEN) == 0) { /* * The TEST5_BRANCH_ID test simulates user terminating the transaction * after several retransmissions. */ - recv_count++; + g[tid].recv_count++; - if (recv_count == TEST5_RETRANSMIT_CNT+1) { + if (g[tid].recv_count == TEST5_RETRANSMIT_CNT+1) { pj_str_t key; pjsip_transaction *tsx; @@ -702,44 +829,46 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) pj_grp_lock_release(tsx->grp_lock); } else { PJ_LOG(3,(THIS_FILE, " error: uac transaction not found!")); - test_complete = -633; + g[tid].test_complete = -633; } - } else if (recv_count > TEST5_RETRANSMIT_CNT+1) { + } else if (g[tid].recv_count > TEST5_RETRANSMIT_CNT+1) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -634; + g[tid].recv_count)); + g[tid].test_complete = -634; } return PJ_TRUE; } else - if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID) == 0) { + if (pj_strnicmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID, + BRANCH_LEN) == 0) { /* * The TEST6_BRANCH_ID test successfull non-INVITE transaction. */ pj_status_t status; - recv_count++; + g[tid].recv_count++; - if (recv_count > 1) { + if (g[tid].recv_count > 1) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -635; + g[tid].recv_count)); + g[tid].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; + g[tid].test_complete = -636; } return PJ_TRUE; } else - if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST7_BRANCH_ID) == 0) { + if (pj_strnicmp2(&rdata->msg_info.via->branch_param, TEST7_BRANCH_ID, + BRANCH_LEN) == 0) { /* * The TEST7_BRANCH_ID test successfull non-INVITE transaction * with provisional response. @@ -750,12 +879,12 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) pjsip_tx_data *tdata; pj_time_val delay = { 2, 0 }; - recv_count++; + g[tid].recv_count++; - if (recv_count > 1) { + if (g[tid].recv_count > 1) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -640; + g[tid].recv_count)); + g[tid].test_complete = -640; return PJ_TRUE; } @@ -781,42 +910,43 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) 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); + g[tid].timer.entry.cb = &send_response_callback; + g[tid].timer.entry.user_data = r; + pjsip_endpt_schedule_timer(endpt, &g[tid].timer.entry, &delay); return (status == PJ_SUCCESS); } else - if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST8_BRANCH_ID) == 0) { + if (pj_strnicmp2(&rdata->msg_info.via->branch_param, TEST8_BRANCH_ID, + BRANCH_LEN) == 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++; + g[tid].recv_count++; if (method->id == PJSIP_INVITE_METHOD) { - if (recv_count > 1) { + if (g[tid].recv_count > 1) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -635; + g[tid].recv_count)); + g[tid].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; + g[tid].test_complete = -636; } } else if (method->id == PJSIP_ACK_METHOD) { - if (recv_count == 2) { + if (g[tid].recv_count == 2) { pj_str_t key; pj_time_val delay = { 5, 0 }; @@ -828,30 +958,31 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) PJSIP_ROLE_UAC, &pjsip_invite_method, rdata); - pj_strcpy(&timer.tsx_key, &key); - timer.entry.id = 301; - timer.entry.cb = &terminate_tsx_callback; + pj_strcpy(&g[tid].timer.tsx_key, &key); + g[tid].timer.entry.id = 301; + g[tid].timer.entry.cb = &terminate_tsx_callback; - pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); + pjsip_endpt_schedule_timer(endpt, &g[tid].timer.entry, &delay); } - if (recv_count > 2) { + if (g[tid].recv_count > 2) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -638; + g[tid].recv_count)); + g[tid].test_complete = -638; } } else { PJ_LOG(3,(THIS_FILE," error: not expecting %s", pjsip_rx_data_get_info(rdata))); - test_complete = -639; + g[tid].test_complete = -639; } } else - if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST9_BRANCH_ID) == 0) { + if (pj_strnicmp2(&rdata->msg_info.via->branch_param, TEST9_BRANCH_ID, + BRANCH_LEN) == 0) { /* * The TEST9_BRANCH_ID test failed INVITE transaction with * provisional response. @@ -861,7 +992,7 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) method = &rdata->msg_info.msg->line.req.method; - recv_count++; + g[tid].recv_count++; if (method->id == PJSIP_INVITE_METHOD) { @@ -870,10 +1001,10 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) pjsip_tx_data *tdata; pj_time_val delay = { 2, 0 }; - if (recv_count > 1) { + if (g[tid].recv_count > 1) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -650; + g[tid].recv_count)); + g[tid].test_complete = -650; return PJ_TRUE; } @@ -901,13 +1032,13 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) 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); + g[tid].timer.entry.cb = &send_response_callback; + g[tid].timer.entry.user_data = r; + pjsip_endpt_schedule_timer(endpt, &g[tid].timer.entry, &delay); } else if (method->id == PJSIP_ACK_METHOD) { - if (recv_count == 2) { + if (g[tid].recv_count == 2) { pj_str_t key; pj_time_val delay = { 5, 0 }; @@ -919,24 +1050,24 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) PJSIP_ROLE_UAC, &pjsip_invite_method, rdata); - pj_strcpy(&timer.tsx_key, &key); - timer.entry.id = 302; - timer.entry.cb = &terminate_tsx_callback; + pj_strcpy(&g[tid].timer.tsx_key, &key); + g[tid].timer.entry.id = 302; + g[tid].timer.entry.cb = &terminate_tsx_callback; - pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); + pjsip_endpt_schedule_timer(endpt, &g[tid].timer.entry, &delay); } - if (recv_count > 2) { + if (g[tid].recv_count > 2) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", - recv_count)); - test_complete = -638; + g[tid].recv_count)); + g[tid].test_complete = -638; } } else { PJ_LOG(3,(THIS_FILE," error: not expecting %s", pjsip_rx_data_get_info(rdata))); - test_complete = -639; + g[tid].test_complete = -639; } @@ -950,26 +1081,28 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) /* * 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, +static int perform_tsx_test(unsigned tid, 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; + char branch_buf[BRANCH_LEN+20]; pj_time_val timeout; pj_status_t status; PJ_UNUSED_ARG(dummy); + PJ_TEST_EQ(strlen(branch_param), BRANCH_LEN, NULL, return -99); PJ_LOG(3,(THIS_FILE, " please standby, this will take at most %d seconds..", test_time)); /* Reset test. */ - recv_count = 0; - test_complete = 0; + g[tid].recv_count = 0; + g[tid].test_complete = 0; /* Init headers. */ target = pj_str(target_uri); @@ -981,12 +1114,16 @@ static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, NULL, &tdata); if (status != PJ_SUCCESS) { app_perror(" Error: unable to create request", status); - return -100; + return -105; } - /* Set the branch param for test 1. */ + /* Set the branch param. Note that other tsx_uac_test() instances may + * be running simultaneously, thus the branch ID needs to be made unique + * by adding tid */ via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); - via->branch_param = pj_str(branch_param); + pj_ansi_snprintf(branch_buf, sizeof(branch_buf), + "%s-%02d", branch_param, tid); + pj_strdup2(tdata->pool, &via->branch_param, branch_buf); /* Add additional reference to tdata to prevent transaction from * deleting it. @@ -1000,7 +1137,18 @@ static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, pjsip_tx_data_dec_ref(tdata); return -110; } + set_tsx_tid(tsx, tid); + + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + pjsip_tpselector tp_sel; + pj_assert(g[tid].loop); + pj_bzero(&tp_sel, sizeof(tp_sel)); + tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT; + tp_sel.u.transport = g[tid].loop; + pjsip_tsx_set_transport(tsx, &tp_sel); + } + /* Get transaction key. */ pj_strdup(tdata->pool, &tsx_key, &tsx->transaction_key); @@ -1020,7 +1168,7 @@ static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, timeout.sec += test_time; /* Wait until test complete. */ - while (!test_complete) { + while (!g[tid].test_complete) { pj_time_val now, poll_delay = {0, 10}; pjsip_endpt_handle_events(endpt, &poll_delay); @@ -1033,7 +1181,7 @@ static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, } } - if (test_complete < 0) { + if (g[tid].test_complete < 0) { tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); if (tsx) { pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); @@ -1041,7 +1189,7 @@ static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, flush_events(1000); } pjsip_tx_data_dec_ref(tdata); - return test_complete; + return g[tid].test_complete; } else { pj_time_val now; @@ -1068,10 +1216,11 @@ static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, } /* Check tdata reference counter. */ - if (pj_atomic_get(tdata->ref_cnt) != 1) { + if (pj_atomic_get(tdata->ref_cnt) > 1) { PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %ld", pj_atomic_get(tdata->ref_cnt))); - pjsip_tx_data_dec_ref(tdata); + while (pj_atomic_get(tdata->ref_cnt) > 1) + pjsip_tx_data_dec_ref(tdata); return -150; } @@ -1091,7 +1240,7 @@ static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, ** ***************************************************************************** */ -static int tsx_uac_retransmit_test(void) +static int tsx_uac_retransmit_test(unsigned tid) { int status = 0, enabled; int i; @@ -1111,7 +1260,6 @@ static int tsx_uac_retransmit_test(void) 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. */ @@ -1126,19 +1274,23 @@ static int tsx_uac_retransmit_test(void) sub_test[i].delay)); /* Configure transport */ - pjsip_loop_set_failure(loop, 0, NULL); - pjsip_loop_set_recv_delay(loop, sub_test[i].delay, NULL); + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + pjsip_loop_set_failure(g[tid].loop, 0, NULL); + pjsip_loop_set_recv_delay(g[tid].loop, sub_test[i].delay, NULL); + } /* Do the test. */ - status = perform_tsx_test(-500, TARGET_URI, FROM_URI, - TEST1_BRANCH_ID, + status = perform_tsx_test(tid, -500, g[tid].TARGET_URI, + g[tid].FROM_URI, TEST1_BRANCH_ID, 35, sub_test[i].method); if (status != 0) break; } /* Restore transport. */ - pjsip_loop_set_recv_delay(loop, 0, NULL); + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + pjsip_loop_set_recv_delay(g[tid].loop, 0, NULL); + } /* Restore msg logger. */ msg_logger_set_enabled(enabled); @@ -1158,20 +1310,24 @@ static int tsx_uac_retransmit_test(void) ** ***************************************************************************** */ -static int tsx_resolve_error_test(void) +static int tsx_resolve_error_test(unsigned tid) { + char target[80]; int status = 0; PJ_LOG(3,(THIS_FILE, " test2: resolve error test")); + pj_ansi_snprintf(target, sizeof(target), + "sip:%d@unresolved-host;transport=%s", + tid, g[tid].test_param->tp_type); + /* * 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, + status = perform_tsx_test(tid, -800, target, + g[tid].FROM_URI, TEST2_BRANCH_ID, 20, &pjsip_options_method); if (status != 0) return status; @@ -1182,20 +1338,24 @@ static int tsx_resolve_error_test(void) 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) { + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + int prev_fail = 0; + unsigned prev_delay = 0; + /* Set loop transport to return delayed error. */ - pjsip_loop_set_failure(loop, 2, NULL); - pjsip_loop_set_send_callback_delay(loop, 10, NULL); + pjsip_loop_set_failure(g[tid].loop, 2, &prev_fail); + pjsip_loop_set_send_callback_delay(g[tid].loop, 10, &prev_delay); - status = perform_tsx_test(-800, TARGET_URI, FROM_URI, - TEST2_BRANCH_ID, 2, + status = perform_tsx_test(tid, -800, g[tid].TARGET_URI, + g[tid].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); + pjsip_loop_set_failure(g[tid].loop, prev_fail, NULL); + pjsip_loop_set_send_callback_delay(g[tid].loop, prev_delay, NULL); + + if (status != 0) + return status; } return status; @@ -1210,7 +1370,7 @@ static int tsx_resolve_error_test(void) ** ***************************************************************************** */ -static int tsx_terminate_resolving_test(void) +static int tsx_terminate_resolving_test(unsigned tid) { unsigned prev_delay; pj_status_t status; @@ -1218,14 +1378,18 @@ static int tsx_terminate_resolving_test(void) PJ_LOG(3,(THIS_FILE, " test3: terminate while resolving test")); /* Configure transport delay. */ - pjsip_loop_set_send_callback_delay(loop, 100, &prev_delay); + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + pjsip_loop_set_send_callback_delay(g[tid].loop, 100, &prev_delay); + } /* Start the test. */ - status = perform_tsx_test(-900, TARGET_URI, FROM_URI, + status = perform_tsx_test(tid, -900, g[tid].TARGET_URI, g[tid].FROM_URI, TEST3_BRANCH_ID, 2, &pjsip_options_method); /* Restore delay. */ - pjsip_loop_set_send_callback_delay(loop, prev_delay, NULL); + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + pjsip_loop_set_send_callback_delay(g[tid].loop, prev_delay, NULL); + } return status; } @@ -1241,7 +1405,7 @@ static int tsx_terminate_resolving_test(void) ** ***************************************************************************** */ -static int tsx_retransmit_fail_test(void) +static int tsx_retransmit_fail_test(unsigned tid) { int i; unsigned delay[] = {0, 10}; @@ -1257,13 +1421,13 @@ static int tsx_retransmit_fail_test(void) " variant %c: transport delay %d ms", ('a'+i), delay[i])); /* Configure transport delay. */ - pjsip_loop_set_send_callback_delay(loop, delay[i], NULL); + pjsip_loop_set_send_callback_delay(g[tid].loop, delay[i], NULL); /* Restore transport failure mode. */ - pjsip_loop_set_failure(loop, 0, 0); + pjsip_loop_set_failure(g[tid].loop, 0, 0); /* Start the test. */ - status = perform_tsx_test(-1000, TARGET_URI, FROM_URI, + status = perform_tsx_test(tid, -1000, g[tid].TARGET_URI, g[tid].FROM_URI, TEST4_BRANCH_ID, 6, &pjsip_options_method); if (status != 0) @@ -1272,10 +1436,10 @@ static int tsx_retransmit_fail_test(void) } /* Restore delay. */ - pjsip_loop_set_send_callback_delay(loop, 0, NULL); + pjsip_loop_set_send_callback_delay(g[tid].loop, 0, NULL); /* Restore transport failure mode. */ - pjsip_loop_set_failure(loop, 0, 0); + pjsip_loop_set_failure(g[tid].loop, 0, 0); return status; } @@ -1287,14 +1451,14 @@ static int tsx_retransmit_fail_test(void) ** ***************************************************************************** */ -static int tsx_terminate_after_retransmit_test(void) +static int tsx_terminate_after_retransmit_test(unsigned tid) { int status; PJ_LOG(3,(THIS_FILE, " test5: terminate after retransmissions")); /* Do the test. */ - status = perform_tsx_test(-1100, TARGET_URI, FROM_URI, + status = perform_tsx_test(tid, -1100, g[tid].TARGET_URI, g[tid].FROM_URI, TEST5_BRANCH_ID, 6, &pjsip_options_method); @@ -1312,7 +1476,8 @@ static int tsx_terminate_after_retransmit_test(void) ** ***************************************************************************** */ -static int perform_generic_test( const char *title, +static int perform_generic_test( unsigned tid, + const char *title, char *branch_id, const pjsip_method *method) { @@ -1320,27 +1485,30 @@ static int perform_generic_test( const char *title, 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) { + if (g[tid].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]); + pjsip_loop_set_failure(g[tid].loop, 0, 0); + pjsip_loop_set_delay(g[tid].loop, delay[i]); } - status = perform_tsx_test(-1200, TARGET_URI, FROM_URI, + status = perform_tsx_test(tid, -1200, g[tid].TARGET_URI, g[tid].FROM_URI, branch_id, 10, method); if (status != 0) return status; - if (test_param->type != PJSIP_TRANSPORT_LOOP_DGRAM) + if (g[tid].test_param->type != PJSIP_TRANSPORT_LOOP_DGRAM) break; } - pjsip_loop_set_delay(loop, 0); + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + pjsip_loop_set_delay(g[tid].loop, 0); + } /* Done. */ return status; @@ -1353,117 +1521,97 @@ static int perform_generic_test( const char *title, ** ***************************************************************************** */ -int tsx_uac_test(struct tsx_test_param *param) +int tsx_uac_test(unsigned tid) { - pj_sockaddr_in addr; - pj_status_t status; +#define ERR(rc__) { status=rc__; goto on_return; } + struct tsx_test_param *param = &tsx_test[tid]; + int status; - timer.tsx_key.ptr = timer.key_buf; + g[tid].timer.tsx_key.ptr = g[tid].timer.key_buf; - test_param = param; + g[tid].test_param = param; /* Get transport flag */ - tp_flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)test_param->type); - - pj_ansi_snprintf(TARGET_URI, sizeof(TARGET_URI), "sip:bob@127.0.0.1:%d;transport=%s", - param->port, param->tp_type); - pj_ansi_snprintf(FROM_URI, sizeof(FROM_URI), "sip:alice@127.0.0.1:%d;transport=%s", + g[tid].tp_flag = pjsip_transport_get_flag_from_type( + (pjsip_transport_type_e)g[tid].test_param->type); + + pj_ansi_snprintf(g[tid].TARGET_URI, sizeof(g[tid].TARGET_URI), + "sip:%d@127.0.0.1:%d;transport=%s", + tid, param->port, param->tp_type); + pj_ansi_snprintf(g[tid].FROM_URI, sizeof(g[tid].FROM_URI), + "sip:tsx_uac_test@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; - } + if ((status=init_test(tid)) != 0) + return status; - /* TEST1_BRANCH_ID: Basic retransmit and timeout test. */ - status = tsx_uac_retransmit_test(); + status = tsx_uac_retransmit_test(tid); if (status != 0) - return status; + goto on_return; /* TEST2_BRANCH_ID: Resolve error test. */ - status = tsx_resolve_error_test(); + status = tsx_resolve_error_test(tid); if (status != 0) - return status; + goto on_return; /* TEST3_BRANCH_ID: UAC terminate while resolving test. */ - status = tsx_terminate_resolving_test(); + status = tsx_terminate_resolving_test(tid); if (status != 0) - return status; + goto on_return; /* 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 (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + status = tsx_retransmit_fail_test(tid); if (status != 0) - return status; + goto on_return; } /* 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 ((g[tid].tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_terminate_after_retransmit_test(tid); if (status != 0) - return status; + goto on_return; } /* TEST6_BRANCH_ID: Successfull non-invite transaction */ - status = perform_generic_test("test6: successfull non-invite transaction", + status = perform_generic_test(tid, + "test6: successfull non-invite transaction", TEST6_BRANCH_ID, &pjsip_options_method); if (status != 0) - return status; + goto on_return; /* TEST7_BRANCH_ID: Successfull non-invite transaction */ - status = perform_generic_test("test7: successfull non-invite transaction " + status = perform_generic_test(tid, + "test7: successfull non-invite transaction " "with provisional response", TEST7_BRANCH_ID, &pjsip_options_method); if (status != 0) - return status; + goto on_return; /* TEST8_BRANCH_ID: Failed invite transaction */ - status = perform_generic_test("test8: failed invite transaction", + status = perform_generic_test(tid, + "test8: failed invite transaction", TEST8_BRANCH_ID, &pjsip_invite_method); + if (status != 0) - return status; + goto on_return; /* TEST9_BRANCH_ID: Failed invite transaction with provisional response */ - status = perform_generic_test("test9: failed invite transaction with " + status = perform_generic_test(tid, + "test9: failed invite transaction with " "provisional response", TEST9_BRANCH_ID, &pjsip_invite_method); if (status != 0) - return status; + goto on_return; - pjsip_transport_dec_ref(loop); +on_return: + finish_test(tid); 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; + return status; +#undef ERR } diff --git a/pjsip/src/test/tsx_uas_test.c b/pjsip/src/test/tsx_uas_test.c index 815cbe069e..d6f23cf1ab 100644 --- a/pjsip/src/test/tsx_uas_test.c +++ b/pjsip/src/test/tsx_uas_test.c @@ -94,20 +94,22 @@ ** **/ -#define TEST1_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test1") -#define TEST2_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test2") -#define TEST3_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test3") -#define TEST4_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test4") -#define TEST5_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test5") -#define TEST6_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test6") -#define TEST7_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test7") -#define TEST8_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test8") -#define TEST9_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test9") +#define TEST1_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test01") +#define TEST2_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test02") +#define TEST3_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test03") +#define TEST4_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test04") +#define TEST5_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test05") +#define TEST6_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test06") +#define TEST7_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test07") +#define TEST8_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test08") +#define TEST9_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test09") #define TEST10_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test10") #define TEST11_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test11") #define TEST12_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test12") //#define TEST13_BRANCH_ID (PJSIP_RFC3261_BRANCH_ID "-UAS-Test13") +#define BRANCH_LEN (7+11) + #define TEST1_STATUS_CODE 200 #define TEST2_STATUS_CODE 301 #define TEST3_PROVISIONAL_CODE PJSIP_SC_QUEUED @@ -124,19 +126,41 @@ #define TEST6_RESPONSE_COUNT 3 #define TEST7_STATUS_CODE 301 #define TEST8_STATUS_CODE 302 -#define TEST9_STATUS_CODE 301 +#define TEST9_STATUS_CODE 301 /* Must be non-2xx */ #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" +/* Since several tsx_uas_test() may run concurrently, keep the global vars + * in array indexed according to the test index (tid) + */ +static struct tsx_uas_test_global_t +{ + char TARGET_URI[128]; + char FROM_URI[128]; + struct tsx_test_param *test_param; + unsigned tp_flag; + + /* Static vars, which will be reset on each test. */ + int recv_count; + pj_time_val recv_last; + pj_bool_t test_complete; + + /* Loop transport instance. */ + pjsip_transport *loop; + + /* UAS transaction key. */ + char key_buf[64]; + pj_str_t tsx_key; + + /* General timer entry to be used by tests. */ + //pj_timer_entry timer; -static char TARGET_URI[128]; -static char FROM_URI[128]; -static struct tsx_test_param *test_param; -static unsigned tp_flag; + pj_bool_t modules_registered; +} g[MAX_TSX_TESTS]; #define TEST_TIMEOUT_ERROR -30 @@ -152,7 +176,7 @@ static pjsip_module tsx_user = NULL, NULL, /* prev and next */ { "Tsx-UAS-User", 12}, /* Name. */ -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ + PJSIP_MOD_PRIORITY_UA_PROXY_LAYER-1,/* Priority */ NULL, /* load() */ NULL, /* start() */ NULL, /* stop() */ @@ -170,7 +194,7 @@ static pjsip_module msg_sender = NULL, NULL, /* prev and next */ { "Msg-Sender", 10}, /* Name. */ -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */ + PJSIP_MOD_PRIORITY_UA_PROXY_LAYER-1,/* Priority */ NULL, /* load() */ NULL, /* start() */ NULL, /* stop() */ @@ -182,22 +206,6 @@ static pjsip_module msg_sender = 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 { @@ -205,6 +213,104 @@ struct response pjsip_tx_data *tdata; }; +/* Get test ID from transaction instance */ +static unsigned get_tsx_tid(const pjsip_transaction *tsx) +{ + pj_assert(tsx_user.id >= 0); + return (unsigned)(long)tsx->mod_data[tsx_user.id]; +} + + +static void init_tsx(pjsip_transaction *tsx, unsigned tid) +{ + pj_assert(tsx_user.id >= 0); + tsx->mod_data[tsx_user.id] = (void*)(long)tid; + + /* Must select specific transport to use for loop */ + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + pjsip_tpselector tp_sel; + + pj_assert(g[tid].loop); + pj_bzero(&tp_sel, sizeof(tp_sel)); + tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT; + tp_sel.u.transport = g[tid].loop; + pjsip_tsx_set_transport(tsx, &tp_sel); + } +} + +static int modules_reg_cnt; + +/* Register modules, taking care of multiple re-registration attempts */ +static pj_status_t register_modules(unsigned tid) +{ + int old_reg_cnt; + pj_status_t status; + + pj_enter_critical_section(); + old_reg_cnt = modules_reg_cnt++; + pj_leave_critical_section(); + + if (old_reg_cnt==0) { + PJ_TEST_SUCCESS(status=pjsip_endpt_register_module(endpt, &tsx_user), + NULL, goto on_error); + PJ_TEST_SUCCESS(status=pjsip_endpt_register_module(endpt, &msg_sender), + NULL, { + pjsip_endpt_unregister_module(endpt, &tsx_user); + goto on_error; + }); + } else { + unsigned i; + /* Make sure modules are registered, wait if necessary */ + for (i=0; i<20 && (tsx_user.id<0 || msg_sender.id<0); ++i) + pj_thread_sleep(50); + + if (tsx_user.id<0 || msg_sender.id<0) { + PJ_TEST_SUCCESS(status = PJSIP_ENOTINITIALIZED, + "other thread failed to register module", + goto on_error); + } + } + + g[tid].modules_registered = 1; + return PJ_SUCCESS; + +on_error: + pj_enter_critical_section(); + modules_reg_cnt--; + pj_leave_critical_section(); + + return status; +} + +/* Unregister modules, taking care of premature unregistration attempt */ +static void unregister_modules(unsigned tid) +{ + int new_reg_cnt; + + if (!g[tid].modules_registered) + return; + + g[tid].modules_registered = 0; + + // Note: + // on_tsx_state() can be called much later during pjsip shutdown + // i.e. when transaction layer is being destroyed. If we unregister + // the modules, get_tsx_tid() will fail with assertion. + // So just let the module registered. + return; + + pj_enter_critical_section(); + new_reg_cnt = --modules_reg_cnt; + pj_leave_critical_section(); + + if (new_reg_cnt == 0) { + PJ_TEST_SUCCESS(pjsip_endpt_unregister_module(endpt, &tsx_user), + "error ignored", {}); + PJ_TEST_SUCCESS(pjsip_endpt_unregister_module(endpt, &msg_sender), + "error ignored", {}); + } +} + /* Timer callback to send response. */ static void send_response_timer( pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry) @@ -241,12 +347,13 @@ static void send_response( pjsip_rx_data *rdata, { pj_status_t status; pjsip_tx_data *tdata; + unsigned tid = get_tsx_tid(tsx); 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; + g[tid].test_complete = -196; return; } @@ -255,13 +362,14 @@ static void send_response( pjsip_rx_data *rdata, pjsip_tx_data_dec_ref(tdata); // Some tests do expect failure! //app_perror(" error: unable to send response", status); - //test_complete = -197; + //g[tid].test_complete = -197; return; } } /* Schedule timer to send response for the specified UAS transaction */ -static void schedule_send_response( pjsip_rx_data *rdata, +static void schedule_send_response( unsigned tid, + pjsip_rx_data *rdata, const pj_str_t *tsx_key_, int status_code, int msec_delay ) @@ -276,7 +384,7 @@ static void schedule_send_response( pjsip_rx_data *rdata, &tdata); if (status != PJ_SUCCESS) { app_perror(" error: unable to create response", status); - test_complete = -198; + g[tid].test_complete = -198; return; } @@ -296,18 +404,18 @@ static void schedule_send_response( pjsip_rx_data *rdata, if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); app_perror(" error: unable to schedule timer", status); - test_complete = -199; + g[tid].test_complete = -199; return; } } /* Find and terminate tsx with the specified key. */ -static void terminate_our_tsx(int status_code) +static void terminate_our_tsx(unsigned tid, int status_code) { pjsip_transaction *tsx; - tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); + tsx = pjsip_tsx_layer_find_tsx(&g[tid].tsx_key, PJ_TRUE); if (!tsx) { PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction")); return; @@ -337,7 +445,7 @@ static void schedule_terminate_tsx( pjsip_transaction *tsx, delay.msec = msec_delay; pj_time_val_normalize(&delay); - pj_assert(pj_strcmp(&tsx->transaction_key, &tsx_key)==0); + pj_assert(pj_strcmp(&tsx->transaction_key, &g[tid].tsx_key)==0); timer.user_data = NULL; timer.id = status_code; timer.cb = &terminate_tsx_timer; @@ -353,8 +461,28 @@ static void schedule_terminate_tsx( pjsip_transaction *tsx, */ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) { - if (pj_stricmp2(&tsx->branch, TEST1_BRANCH_ID)==0 || - pj_stricmp2(&tsx->branch, TEST2_BRANCH_ID)==0) + unsigned tid = get_tsx_tid(tsx); + + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM && + e->type==PJSIP_EVENT_TSX_STATE) + { + if (e->body.tsx_state.type==PJSIP_EVENT_RX_MSG) { + PJ_TEST_EQ( e->body.tsx_state.src.rdata->tp_info.transport, + g[tid].loop, NULL, { + g[tid].test_complete = -704; + return; + }); + } else if (e->body.tsx_state.type==PJSIP_EVENT_TX_MSG) { + PJ_TEST_EQ( e->body.tsx_state.src.tdata->tp_info.transport, + g[tid].loop, NULL, { + g[tid].test_complete = -706; + return; + }); + } + } + + if (pj_strnicmp2(&tsx->branch, TEST1_BRANCH_ID, BRANCH_LEN)==0 || + pj_strnicmp2(&tsx->branch, TEST2_BRANCH_ID, BRANCH_LEN)==0) { /* * TEST1_BRANCH_ID tests that non-INVITE transaction transmits final @@ -363,23 +491,23 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) * * TEST2_BRANCH_ID does similar test for non-2xx final response. */ - int status_code = (pj_stricmp2(&tsx->branch, TEST1_BRANCH_ID)==0) ? + int status_code = (pj_strnicmp2(&tsx->branch, TEST1_BRANCH_ID, BRANCH_LEN)==0) ? TEST1_STATUS_CODE : TEST2_STATUS_CODE; if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - test_complete = 1; + g[tid].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; + g[tid].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; + g[tid].test_complete = -101; } } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { @@ -387,30 +515,30 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* 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; + g[tid].test_complete = -102; } } } else - if (pj_stricmp2(&tsx->branch, TEST3_BRANCH_ID)==0) { + if (pj_strnicmp2(&tsx->branch, TEST3_BRANCH_ID, BRANCH_LEN)==0) { /* * TEST3_BRANCH_ID tests sending provisional response. */ if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - test_complete = 1; + g[tid].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; + g[tid].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; + g[tid].test_complete = -111; } } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) { @@ -418,19 +546,19 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* 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; + g[tid].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; + g[tid].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; + g[tid].test_complete = -114; } } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { @@ -438,25 +566,25 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* 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; + g[tid].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; + g[tid].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; + g[tid].test_complete = -117; } } } else - if (pj_stricmp2(&tsx->branch, TEST4_BRANCH_ID)==0) { + if (pj_strnicmp2(&tsx->branch, TEST4_BRANCH_ID, BRANCH_LEN)==0) { /* * TEST4_BRANCH_ID tests receiving retransmissions in TRYING state. */ @@ -470,26 +598,26 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) " error: incorrect status code %d " "(expecting %d)", tsx->status_code, TEST4_STATUS_CODE)); - test_complete = -120; + g[tid].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; + g[tid].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; + g[tid].test_complete = -122; } } else - if (pj_stricmp2(&tsx->branch, TEST5_BRANCH_ID)==0) { + if (pj_strnicmp2(&tsx->branch, TEST5_BRANCH_ID, BRANCH_LEN)==0) { /* * TEST5_BRANCH_ID tests receiving retransmissions in PROCEEDING state */ @@ -501,13 +629,13 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* 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; + g[tid].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; + g[tid].test_complete = -131; } } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) { @@ -515,18 +643,18 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* Check status code. */ if (tsx->status_code != TEST5_PROVISIONAL_CODE) { PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -132; + g[tid].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; + g[tid].test_complete = -133; } } else - if (pj_stricmp2(&tsx->branch, TEST6_BRANCH_ID)==0) { + if (pj_strnicmp2(&tsx->branch, TEST6_BRANCH_ID, BRANCH_LEN)==0) { /* * TEST6_BRANCH_ID tests receiving retransmissions in COMPLETED state */ @@ -540,13 +668,13 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJ_LOG(3,(THIS_FILE, " error: incorrect status code %d " "(expecting %d)", tsx->status_code, TEST6_STATUS_CODE)); - test_complete = -140; + g[tid].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; + g[tid].test_complete = -141; } } else if (tsx->state != PJSIP_TSX_STATE_PROCEEDING && @@ -555,14 +683,14 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) { PJ_LOG(3,(THIS_FILE, " error: unexpected state %s (142)", pjsip_tsx_state_str(tsx->state))); - test_complete = -142; + g[tid].test_complete = -142; } } else - if (pj_stricmp2(&tsx->branch, TEST7_BRANCH_ID)==0 || - pj_stricmp2(&tsx->branch, TEST8_BRANCH_ID)==0) + if (pj_strnicmp2(&tsx->branch, TEST7_BRANCH_ID, BRANCH_LEN)==0 || + pj_strnicmp2(&tsx->branch, TEST8_BRANCH_ID, BRANCH_LEN)==0) { /* * TEST7_BRANCH_ID and TEST8_BRANCH_ID test retransmission of @@ -570,7 +698,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) */ int code; - if (pj_stricmp2(&tsx->branch, TEST7_BRANCH_ID) == 0) + if (pj_strnicmp2(&tsx->branch, TEST7_BRANCH_ID, BRANCH_LEN) == 0) code = TEST7_STATUS_CODE; else code = TEST8_STATUS_CODE; @@ -580,27 +708,28 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - if (test_complete == 0) - test_complete = 1; + if (g[tid].test_complete == 0) + g[tid].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; + PJ_LOG(3,(THIS_FILE, " error: incorrect status code %d", + tsx->status_code)); + g[tid].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; + g[tid].test_complete = -151; } /* Check the number of retransmissions */ - if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { + if (g[tid].tp_flag & PJSIP_TRANSPORT_RELIABLE) { if (tsx->retransmit_count != 0) { PJ_LOG(3,(THIS_FILE, " error: should not retransmit")); - test_complete = -1510; + g[tid].test_complete = -1510; } } else { @@ -610,7 +739,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) " error: incorrect retransmit count %d " "(expecting 10)", tsx->retransmit_count)); - test_complete = -1510; + g[tid].test_complete = -1510; } } @@ -620,25 +749,25 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* Check that status code is status_code. */ if (tsx->status_code != code) { PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -152; + g[tid].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; + g[tid].test_complete = -153; } } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) { PJ_LOG(3,(THIS_FILE, " error: unexpected state (154)")); - test_complete = -154; + g[tid].test_complete = -154; } } else - if (pj_stricmp2(&tsx->branch, TEST9_BRANCH_ID)==0) { + if (pj_strnicmp2(&tsx->branch, TEST9_BRANCH_ID, BRANCH_LEN)==0) { /* * TEST9_BRANCH_ID tests that retransmission of INVITE final response * must cease when ACK is received. @@ -649,33 +778,29 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - if (test_complete == 0) - test_complete = 1; + if (g[tid].test_complete == 0) + g[tid].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; - } + PJ_TEST_EQ(tsx->status_code, TEST9_STATUS_CODE, NULL, + g[tid].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; - } + PJ_TEST_EQ(e->body.tsx_state.prev_state, PJSIP_TSX_STATE_CONFIRMED, + NULL, g[tid].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; + g[tid].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; + g[tid].test_complete = -163; } @@ -684,31 +809,31 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* 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; + g[tid].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; + g[tid].test_complete = -165; } } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) { PJ_LOG(3,(THIS_FILE, " error: unexpected state (166)")); - test_complete = -166; + g[tid].test_complete = -166; } } else - if (pj_stricmp2(&tsx->branch, TEST10_BRANCH_ID)==0 || - pj_stricmp2(&tsx->branch, TEST12_BRANCH_ID)==0) + if (pj_strnicmp2(&tsx->branch, TEST10_BRANCH_ID, BRANCH_LEN)==0 || + pj_strnicmp2(&tsx->branch, TEST12_BRANCH_ID, BRANCH_LEN)==0) { if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - if (!test_complete) - test_complete = 1; + if (!g[tid].test_complete) + g[tid].test_complete = 1; if (tsx->status_code != PJSIP_SC_REQUEST_TIMEOUT) { PJ_LOG(3,(THIS_FILE," error: incorrect status code" @@ -716,16 +841,16 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJSIP_SC_REQUEST_TIMEOUT, // PJSIP_SC_TSX_TRANSPORT_ERROR, tsx->status_code)); - test_complete = -170; + g[tid].test_complete = -170; } } } else - if (pj_stricmp2(&tsx->branch, TEST11_BRANCH_ID)==0) + if (pj_strnicmp2(&tsx->branch, TEST11_BRANCH_ID, BRANCH_LEN)==0) { if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { - if (!test_complete) - test_complete = 1; + if (!g[tid].test_complete) + g[tid].test_complete = 1; if (tsx->status_code != PJSIP_SC_REQUEST_TIMEOUT && tsx->status_code != PJSIP_SC_OK) @@ -735,7 +860,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) PJSIP_SC_REQUEST_TIMEOUT, // PJSIP_SC_TSX_TRANSPORT_ERROR, tsx->status_code)); - test_complete = -170; + g[tid].test_complete = -170; } } } @@ -745,9 +870,12 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) static void save_key(pjsip_transaction *tsx) { pj_str_t key; + unsigned tid = get_tsx_tid(tsx); + g[tid].tsx_key.ptr = g[tid].key_buf; + g[tid].tsx_key.slen = 0; pj_strdup(tsx->pool, &key, &tsx->transaction_key); - pj_strcpy(&tsx_key, &key); + pj_strcpy(&g[tid].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; + pjsip_to_hdr *to_hdr = rdata->msg_info.to; + pjsip_sip_uri *target = (pjsip_sip_uri*)pjsip_uri_get_uri(to_hdr->uri); + pjsip_from_hdr *from_hdr = rdata->msg_info.from; + pjsip_sip_uri *from_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(from_hdr->uri); + unsigned tid; + + if (pj_strcmp2(&from_uri->user, "tsx_uas_test")) { + /* Not our message */ + return PJ_FALSE; + } - if (pj_stricmp2(&branch_param, TEST1_BRANCH_ID) == 0 || - pj_stricmp2(&branch_param, TEST2_BRANCH_ID) == 0) + tid = (unsigned)pj_strtol(&target->user); + + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + PJ_TEST_EQ(rdata->tp_info.transport, g[tid].loop, NULL, + {g[tid].test_complete = -602; return PJ_TRUE;}); + } + + if (pj_strnicmp2(&branch_param, TEST1_BRANCH_ID, BRANCH_LEN) == 0 || + pj_strnicmp2(&branch_param, TEST2_BRANCH_ID, BRANCH_LEN) == 0) { /* * TEST1_BRANCH_ID tests that non-INVITE transaction transmits 2xx @@ -771,7 +916,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) * * TEST2_BRANCH_ID performs similar test for non-2xx final response. */ - int status_code = (pj_stricmp2(&branch_param, TEST1_BRANCH_ID) == 0) ? + int status_code = (pj_strnicmp2(&branch_param, TEST1_BRANCH_ID, BRANCH_LEN) == 0) ? TEST1_STATUS_CODE : TEST2_STATUS_CODE; if (msg->type == PJSIP_REQUEST_MSG) { @@ -783,9 +928,10 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); if (status != PJ_SUCCESS) { app_perror(" error: unable to create transaction", status); - test_complete = -110; + g[tid].test_complete = -110; return PJ_TRUE; } + init_tsx(tsx, tid); pjsip_tsx_recv_msg(tsx, rdata); save_key(tsx); @@ -794,24 +940,25 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) } else { /* Verify the response received. */ - ++recv_count; + ++g[tid].recv_count; /* Verify status code. */ if (msg->line.status.code != status_code) { PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); - test_complete = -113; + g[tid].test_complete = -113; } /* Verify that no retransmissions is received. */ - if (recv_count > 1) { + if (g[tid].recv_count > 1) { PJ_LOG(3,(THIS_FILE, " error: retransmission received")); - test_complete = -114; + g[tid].test_complete = -114; } } return PJ_TRUE; - } else if (pj_stricmp2(&branch_param, TEST3_BRANCH_ID) == 0) { + } else if (pj_strnicmp2(&branch_param, TEST3_BRANCH_ID, + BRANCH_LEN) == 0) { /* TEST3_BRANCH_ID tests provisional response. */ @@ -824,45 +971,46 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); if (status != PJ_SUCCESS) { app_perror(" error: unable to create transaction", status); - test_complete = -116; + g[tid].test_complete = -116; return PJ_TRUE; } + init_tsx(tsx, tid); pjsip_tsx_recv_msg(tsx, rdata); save_key(tsx); send_response(rdata, tsx, TEST3_PROVISIONAL_CODE); - schedule_send_response(rdata, &tsx->transaction_key, + schedule_send_response(tid, rdata, &tsx->transaction_key, TEST3_STATUS_CODE, 2000); } else { /* Verify the response received. */ - ++recv_count; + ++g[tid].recv_count; - if (recv_count == 1) { + if (g[tid].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; + g[tid].test_complete = -123; } - } else if (recv_count == 2) { + } else if (g[tid].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; + g[tid].test_complete = -124; } } else { PJ_LOG(3,(THIS_FILE, " error: retransmission received")); - test_complete = -125; + g[tid].test_complete = -125; } } return PJ_TRUE; - } else if (pj_stricmp2(&branch_param, TEST4_BRANCH_ID) == 0 || - pj_stricmp2(&branch_param, TEST5_BRANCH_ID) == 0 || - pj_stricmp2(&branch_param, TEST6_BRANCH_ID) == 0) + } else if (pj_strnicmp2(&branch_param, TEST4_BRANCH_ID, BRANCH_LEN) == 0 || + pj_strnicmp2(&branch_param, TEST5_BRANCH_ID, BRANCH_LEN) == 0 || + pj_strnicmp2(&branch_param, TEST6_BRANCH_ID, BRANCH_LEN) == 0) { /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state. */ @@ -878,19 +1026,19 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); if (status != PJ_SUCCESS) { app_perror(" error: unable to create transaction", status); - test_complete = -130; + g[tid].test_complete = -130; return PJ_TRUE; } - + init_tsx(tsx, tid); pjsip_tsx_recv_msg(tsx, rdata); save_key(tsx); - if (pj_stricmp2(&branch_param, TEST4_BRANCH_ID) == 0) { + if (pj_strnicmp2(&branch_param, TEST4_BRANCH_ID, BRANCH_LEN) == 0) { - } else if (pj_stricmp2(&branch_param, TEST5_BRANCH_ID) == 0) { + } else if (pj_strnicmp2(&branch_param, TEST5_BRANCH_ID, BRANCH_LEN) == 0) { send_response(rdata, tsx, TEST5_PROVISIONAL_CODE); - } else if (pj_stricmp2(&branch_param, TEST6_BRANCH_ID) == 0) { + } else if (pj_strnicmp2(&branch_param, TEST6_BRANCH_ID, BRANCH_LEN) == 0) { PJ_LOG(4,(THIS_FILE, " sending provisional response")); send_response(rdata, tsx, TEST6_PROVISIONAL_CODE); PJ_LOG(4,(THIS_FILE, " sending final response")); @@ -900,35 +1048,35 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) } else { /* Verify the response received. */ - PJ_LOG(4,(THIS_FILE, " received response number %d", recv_count)); + PJ_LOG(4,(THIS_FILE, " received response number %d", g[tid].recv_count)); - ++recv_count; + ++g[tid].recv_count; - if (pj_stricmp2(&branch_param, TEST4_BRANCH_ID) == 0) { + if (pj_strnicmp2(&branch_param, TEST4_BRANCH_ID, BRANCH_LEN) == 0) { PJ_LOG(3,(THIS_FILE, " error: not expecting response!")); - test_complete = -132; + g[tid].test_complete = -132; - } else if (pj_stricmp2(&branch_param, TEST5_BRANCH_ID) == 0) { + } else if (pj_strnicmp2(&branch_param, TEST5_BRANCH_ID, BRANCH_LEN) == 0) { if (rdata->msg_info.msg->line.status.code!=TEST5_PROVISIONAL_CODE) { PJ_LOG(3,(THIS_FILE, " error: incorrect status code!")); - test_complete = -133; + g[tid].test_complete = -133; } - if (recv_count > TEST5_RESPONSE_COUNT) { + if (g[tid].recv_count > TEST5_RESPONSE_COUNT) { PJ_LOG(3,(THIS_FILE, " error: not expecting response!")); - test_complete = -134; + g[tid].test_complete = -134; } - } else if (pj_stricmp2(&branch_param, TEST6_BRANCH_ID) == 0) { + } else if (pj_strnicmp2(&branch_param, TEST6_BRANCH_ID, BRANCH_LEN) == 0) { int code = rdata->msg_info.msg->line.status.code; - switch (recv_count) { + switch (g[tid].recv_count) { case 1: if (code != TEST6_PROVISIONAL_CODE) { PJ_LOG(3,(THIS_FILE, " error: invalid code!")); - test_complete = -135; + g[tid].test_complete = -135; } break; case 2: @@ -936,12 +1084,12 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) if (code != TEST6_STATUS_CODE) { PJ_LOG(3,(THIS_FILE, " error: invalid code %d " "(expecting %d)", code, TEST6_STATUS_CODE)); - test_complete = -136; + g[tid].test_complete = -136; } break; default: PJ_LOG(3,(THIS_FILE, " error: not expecting response")); - test_complete = -137; + g[tid].test_complete = -137; break; } } @@ -949,10 +1097,9 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) return PJ_TRUE; - } else if (pj_stricmp2(&branch_param, TEST7_BRANCH_ID) == 0 || - pj_stricmp2(&branch_param, TEST8_BRANCH_ID) == 0) + } else if (pj_strnicmp2(&branch_param, TEST7_BRANCH_ID, BRANCH_LEN) == 0 || + pj_strnicmp2(&branch_param, TEST8_BRANCH_ID, BRANCH_LEN) == 0) { - /* * TEST7_BRANCH_ID and TEST8_BRANCH_ID test the retransmission * of INVITE final response @@ -965,14 +1112,14 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); if (status != PJ_SUCCESS) { app_perror(" error: unable to create transaction", status); - test_complete = -140; + g[tid].test_complete = -140; return PJ_TRUE; } - + init_tsx(tsx, tid); pjsip_tsx_recv_msg(tsx, rdata); save_key(tsx); - if (pj_stricmp2(&branch_param, TEST7_BRANCH_ID) == 0) { + if (pj_strnicmp2(&branch_param, TEST7_BRANCH_ID, BRANCH_LEN) == 0) { send_response(rdata, tsx, TEST7_STATUS_CODE); @@ -985,21 +1132,22 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) } else { int code; - ++recv_count; + ++g[tid].recv_count; - if (pj_stricmp2(&branch_param, TEST7_BRANCH_ID) == 0) + if (pj_strnicmp2(&branch_param, TEST7_BRANCH_ID, BRANCH_LEN) == 0) code = TEST7_STATUS_CODE; else code = TEST8_STATUS_CODE; - if (recv_count==1) { + if (g[tid].recv_count==1) { if (rdata->msg_info.msg->line.status.code != code) { - PJ_LOG(3,(THIS_FILE," error: invalid status code")); - test_complete = -141; + PJ_LOG(3,(THIS_FILE," error: invalid status code %d", + rdata->msg_info.msg->line.status.code)); + g[tid].test_complete = -141; } - recv_last = rdata->pkt_info.timestamp; + g[tid].recv_last = rdata->pkt_info.timestamp; } else { @@ -1008,10 +1156,10 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) now = rdata->pkt_info.timestamp; - PJ_TIME_VAL_SUB(now, recv_last); + PJ_TIME_VAL_SUB(now, g[tid].recv_last); msec = now.sec*1000 + now.msec; - msec_expected = (1 << (recv_count-2)) * pjsip_cfg()->tsx.t1; + msec_expected = (1 << (g[tid].recv_count-2)) * pjsip_cfg()->tsx.t1; if (msec_expected > pjsip_cfg()->tsx.t2) msec_expected = pjsip_cfg()->tsx.t2; @@ -1020,22 +1168,22 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) " error: incorrect retransmission " "time (%d ms expected, %d ms received", msec_expected, msec)); - test_complete = -142; + g[tid].test_complete = -142; } - if (recv_count > 11) { + if (g[tid].recv_count > 11) { PJ_LOG(3,(THIS_FILE," error: too many responses (%d)", - recv_count)); - test_complete = -143; + g[tid].recv_count)); + g[tid].test_complete = -143; } - recv_last = rdata->pkt_info.timestamp; + g[tid].recv_last = rdata->pkt_info.timestamp; } } return PJ_TRUE; - } else if (pj_stricmp2(&branch_param, TEST9_BRANCH_ID) == 0) { + } else if (pj_strnicmp2(&branch_param, TEST9_BRANCH_ID, BRANCH_LEN) == 0) { /* * TEST9_BRANCH_ID tests that the retransmission of INVITE final @@ -1050,10 +1198,10 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); if (status != PJ_SUCCESS) { app_perror(" error: unable to create transaction", status); - test_complete = -150; + g[tid].test_complete = -150; return PJ_TRUE; } - + init_tsx(tsx, tid); pjsip_tsx_recv_msg(tsx, rdata); save_key(tsx); send_response(rdata, tsx, TEST9_STATUS_CODE); @@ -1061,18 +1209,16 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) } else { - ++recv_count; + ++g[tid].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; - } + PJ_TEST_EQ(rdata->msg_info.msg->line.status.code, TEST9_STATUS_CODE, + NULL, g[tid].test_complete = -151); - if (recv_count==1) { + if (g[tid].recv_count==1) { - recv_last = rdata->pkt_info.timestamp; + g[tid].recv_last = rdata->pkt_info.timestamp; - } else if (recv_count < 5) { + } else if (g[tid].recv_count < 5) { /* Let UAS retransmit some messages before we send ACK. */ pj_time_val now; @@ -1080,10 +1226,10 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) now = rdata->pkt_info.timestamp; - PJ_TIME_VAL_SUB(now, recv_last); + PJ_TIME_VAL_SUB(now, g[tid].recv_last); msec = now.sec*1000 + now.msec; - msec_expected = (1 << (recv_count-2)) * pjsip_cfg()->tsx.t1; + msec_expected = (1 << (g[tid].recv_count-2)) * pjsip_cfg()->tsx.t1; if (msec_expected > pjsip_cfg()->tsx.t2) msec_expected = pjsip_cfg()->tsx.t2; @@ -1092,12 +1238,12 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) " error: incorrect retransmission " "time (%d ms expected, %d ms received", msec_expected, msec)); - test_complete = -152; + g[tid].test_complete = -152; } - recv_last = rdata->pkt_info.timestamp; + g[tid].recv_last = rdata->pkt_info.timestamp; - } else if (recv_count == 5) { + } else if (g[tid].recv_count == 5) { pjsip_tx_data *tdata; pjsip_sip_uri *uri; pjsip_via_hdr *via; @@ -1114,41 +1260,53 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) &tdata); if (status != PJ_SUCCESS) { app_perror(" error: unable to create ACK", status); - test_complete = -153; + g[tid].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"); + pj_strdup2(tdata->pool, &uri->transport_param, + g[tid].test_param->tp_type); + uri->port = g[tid].test_param->port; via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); - via->branch_param = pj_str(TEST9_BRANCH_ID); + pj_strdup(tdata->pool, &via->branch_param, + &rdata->msg_info.via->branch_param); + + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + pjsip_tpselector tp_sel; + + pj_bzero(&tp_sel, sizeof(tp_sel)); + tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT; + tp_sel.u.transport = g[tid].loop; + pjsip_tx_data_set_transport(tdata, &tp_sel); + } 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; + g[tid].test_complete = -154; } } else { PJ_LOG(3,(THIS_FILE," error: too many responses (%d)", - recv_count)); - test_complete = -155; + g[tid].recv_count)); + g[tid].test_complete = -155; } } return PJ_TRUE; - } else if (pj_stricmp2(&branch_param, TEST10_BRANCH_ID) == 0 || - pj_stricmp2(&branch_param, TEST11_BRANCH_ID) == 0 || - pj_stricmp2(&branch_param, TEST12_BRANCH_ID) == 0) + } else if (pj_strnicmp2(&branch_param, TEST10_BRANCH_ID, BRANCH_LEN) == 0 || + pj_strnicmp2(&branch_param, TEST11_BRANCH_ID, BRANCH_LEN) == 0 || + pj_strnicmp2(&branch_param, TEST12_BRANCH_ID, BRANCH_LEN) == 0) { int test_num, code1, code2; - if (pj_stricmp2(&branch_param, TEST10_BRANCH_ID) == 0) + if (pj_strnicmp2(&branch_param, TEST10_BRANCH_ID, BRANCH_LEN) == 0) test_num=10, code1 = 100, code2 = 0; - else if (pj_stricmp2(&branch_param, TEST11_BRANCH_ID) == 0) + else if (pj_strnicmp2(&branch_param, TEST11_BRANCH_ID, BRANCH_LEN) == 0) test_num=11, code1 = 100, code2 = 200; else test_num=12, code1 = 200, code2 = 0; @@ -1163,17 +1321,17 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); if (status != PJ_SUCCESS) { app_perror(" error: unable to create transaction", status); - test_complete = -150; + g[tid].test_complete = -150; return PJ_TRUE; } - + init_tsx(tsx, tid); pjsip_tsx_recv_msg(tsx, rdata); save_key(tsx); - schedule_send_response(rdata, &tsx_key, code1, 1000); + schedule_send_response(tid, rdata, &g[tid].tsx_key, code1, 1000); if (code2) - schedule_send_response(rdata, &tsx_key, code2, 2000); + schedule_send_response(tid, rdata, &g[tid].tsx_key, code2, 2000); } else { @@ -1188,7 +1346,8 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) /* * The generic test framework, used by most of the tests. */ -static int perform_test( char *target_uri, char *from_uri, +static int perform_test( unsigned tid, + char *target_uri, char *from_uri, char *branch_param, int test_time, const pjsip_method *method, int request_cnt, int request_interval_msec, @@ -1197,10 +1356,14 @@ static int perform_test( char *target_uri, char *from_uri, pjsip_tx_data *tdata; pj_str_t target, from; pjsip_via_hdr *via; + char branch_buf[BRANCH_LEN+20]; pj_time_val timeout, next_send; int sent_cnt; + pjsip_tpselector tp_sel; pj_status_t status; + PJ_TEST_EQ(strlen(branch_param), BRANCH_LEN, NULL, return -99); + if (test_time > 0) { PJ_LOG(3,(THIS_FILE, " please standby, this will take at most %d seconds..", @@ -1208,9 +1371,9 @@ static int perform_test( char *target_uri, char *from_uri, } /* Reset test. */ - recv_count = 0; - test_complete = 0; - tsx_key.slen = 0; + g[tid].recv_count = 0; + g[tid].test_complete = 0; + g[tid].tsx_key.slen = 0; /* Init headers. */ target = pj_str(target_uri); @@ -1225,9 +1388,22 @@ static int perform_test( char *target_uri, char *from_uri, return -10; } - /* Set the branch param for test 1. */ + /* Set the branch param. Note that other tsx_uas_test() instances may + * be running simultaneously, thus the branch ID needs to be made unique + * by adding tid */ via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); - via->branch_param = pj_str(branch_param); + pj_ansi_snprintf(branch_buf, sizeof(branch_buf), + "%s-%02d", branch_param, tid); + pj_strdup2(tdata->pool, &via->branch_param, branch_buf); + + /* Must select specific transport to use */ + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + pj_assert(g[tid].loop); + pj_bzero(&tp_sel, sizeof(tp_sel)); + tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT; + tp_sel.u.transport = g[tid].loop; + pjsip_tx_data_set_transport(tdata, &tp_sel); + } /* Schedule first send. */ sent_cnt = 0; @@ -1239,7 +1415,7 @@ static int perform_test( char *target_uri, char *from_uri, timeout.sec += test_time; /* Wait until test complete. */ - while (!test_complete) { + while (!g[tid].test_complete) { pj_time_val now, poll_delay = {0, 10}; pjsip_endpt_handle_events(endpt, &poll_delay); @@ -1279,24 +1455,24 @@ static int perform_test( char *target_uri, char *from_uri, } } - if (test_complete < 0) { + if (g[tid].test_complete < 0) { pjsip_transaction *tsx; - tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE); + tsx = pjsip_tsx_layer_find_tsx(&g[tid].tsx_key, PJ_TRUE); if (tsx) { pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); pj_grp_lock_release(tsx->grp_lock); flush_events(1000); } pjsip_tx_data_dec_ref(tdata); - return test_complete; + return g[tid].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) { + if (pjsip_tsx_layer_find_tsx(&g[tid].tsx_key, PJ_FALSE) != NULL) { PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed")); pjsip_tx_data_dec_ref(tdata); return -40; @@ -1325,7 +1501,7 @@ static int perform_test( char *target_uri, char *from_uri, ** ***************************************************************************** */ -static int tsx_basic_final_response_test(void) +static int tsx_basic_final_response_test(unsigned tid) { unsigned duration; int status; @@ -1335,16 +1511,16 @@ static int tsx_basic_final_response_test(void) /* Test duration must be greater than 32 secs if unreliable transport * is used. */ - duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; + duration = (g[tid].tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; - status = perform_test(TARGET_URI, FROM_URI, TEST1_BRANCH_ID, + status = perform_test(tid, g[tid].TARGET_URI, g[tid].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, + status = perform_test(tid, g[tid].TARGET_URI, g[tid].FROM_URI, TEST2_BRANCH_ID, duration, &pjsip_options_method, 1, 0, 0); if (status != 0) return status; @@ -1359,17 +1535,17 @@ static int tsx_basic_final_response_test(void) ** ***************************************************************************** */ -static int tsx_basic_provisional_response_test(void) +static int tsx_basic_provisional_response_test(unsigned tid) { unsigned duration; int status; PJ_LOG(3,(THIS_FILE," test3: basic sending 2xx final response")); - duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; + duration = (g[tid].tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; duration += 2; - status = perform_test(TARGET_URI, FROM_URI, TEST3_BRANCH_ID, duration, + status = perform_test(tid, g[tid].TARGET_URI, g[tid].FROM_URI, TEST3_BRANCH_ID, duration, &pjsip_options_method, 1, 0, 0); return status; @@ -1384,7 +1560,8 @@ static int tsx_basic_provisional_response_test(void) ** ***************************************************************************** */ -static int tsx_retransmit_last_response_test(const char *title, +static int tsx_retransmit_last_response_test(unsigned tid, + const char *title, char *branch_id, int request_cnt, int status_code) @@ -1393,7 +1570,7 @@ static int tsx_retransmit_last_response_test(const char *title, PJ_LOG(3,(THIS_FILE," %s", title)); - status = perform_test(TARGET_URI, FROM_URI, branch_id, 5, + status = perform_test(tid, g[tid].TARGET_URI, g[tid].FROM_URI, branch_id, 5, &pjsip_options_method, request_cnt, 1000, 1); if (status && status != TEST_TIMEOUT_ERROR) @@ -1403,11 +1580,11 @@ static int tsx_retransmit_last_response_test(const char *title, return -31; } - terminate_our_tsx(status_code); + terminate_our_tsx(tid, status_code); flush_events(100); - if (test_complete != 1) - return test_complete; + if (g[tid].test_complete != 1) + return g[tid].test_complete; flush_events(100); return 0; @@ -1420,14 +1597,14 @@ static int tsx_retransmit_last_response_test(const char *title, ** ***************************************************************************** */ -static int tsx_final_response_retransmission_test(void) +static int tsx_final_response_retransmission_test(unsigned tid) { int status; PJ_LOG(3,(THIS_FILE, " test7: INVITE non-2xx final response retransmission")); - status = perform_test(TARGET_URI, FROM_URI, TEST7_BRANCH_ID, + status = perform_test(tid, g[tid].TARGET_URI, g[tid].FROM_URI, TEST7_BRANCH_ID, 33, /* Test duration must be greater than 32 secs */ &pjsip_invite_method, 1, 0, 0); if (status != 0) @@ -1436,7 +1613,7 @@ static int tsx_final_response_retransmission_test(void) PJ_LOG(3,(THIS_FILE, " test8: INVITE 2xx final response retransmission")); - status = perform_test(TARGET_URI, FROM_URI, TEST8_BRANCH_ID, + status = perform_test(tid, g[tid].TARGET_URI, g[tid].FROM_URI, TEST8_BRANCH_ID, 33, /* Test duration must be greater than 32 secs */ &pjsip_invite_method, 1, 0, 0); if (status != 0) @@ -1453,14 +1630,14 @@ static int tsx_final_response_retransmission_test(void) ** ***************************************************************************** */ -static int tsx_ack_test(void) +static int tsx_ack_test(unsigned tid) { 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, + status = perform_test(tid, g[tid].TARGET_URI, g[tid].FROM_URI, TEST9_BRANCH_ID, 20, /* allow 5 retransmissions */ &pjsip_invite_method, 1, 0, 0); if (status != 0) @@ -1481,7 +1658,7 @@ static int tsx_ack_test(void) ** ***************************************************************************** */ -int tsx_transport_failure_test(void) +static int tsx_transport_failure_test(unsigned tid) { struct test_desc { @@ -1515,10 +1692,10 @@ int tsx_transport_failure_test(void) 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); + pjsip_loop_set_failure(g[tid].loop, 0, NULL); + pjsip_loop_set_delay(g[tid].loop, tests[i].transport_delay); - status = perform_test(TARGET_URI, FROM_URI, tests[i].branch_id, + status = perform_test(tid, g[tid].TARGET_URI, g[tid].FROM_URI, tests[i].branch_id, 0, &pjsip_invite_method, 1, 0, 1); if (status && status != TEST_TIMEOUT_ERROR) return status; @@ -1532,24 +1709,24 @@ int tsx_transport_failure_test(void) pj_time_val_normalize(&fail_time); do { - pj_time_val interval = { 0, 1 }; + pj_time_val interval = { 0, 10 }; pj_gettimeofday(&now); pjsip_endpt_handle_events(endpt, &interval); } while (PJ_TIME_VAL_LT(now, fail_time)); - pjsip_loop_set_failure(loop, 1, NULL); + pjsip_loop_set_failure(g[tid].loop, 1, NULL); PJ_LOG(5,(THIS_FILE, " transport loop fail mode set")); end_test = now; end_test.sec += 33; do { - pj_time_val interval = { 0, 1 }; + pj_time_val interval = { 0, 10 }; pj_gettimeofday(&now); pjsip_endpt_handle_events(endpt, &interval); - } while (!test_complete && PJ_TIME_VAL_LT(now, end_test)); + } while (!g[tid].test_complete && PJ_TIME_VAL_LT(now, end_test)); - if (test_complete != tests[i].result) { + if (g[tid].test_complete != tests[i].result) { PJ_LOG(3,(THIS_FILE, " error: expecting timeout")); return -41; } @@ -1564,98 +1741,99 @@ int tsx_transport_failure_test(void) ** ***************************************************************************** */ -int tsx_uas_test(struct tsx_test_param *param) +int tsx_uas_test(unsigned tid) { - 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); +#define ERR(rc__) { status=rc__; goto on_return; } + struct tsx_test_param *param = &tsx_test[tid]; + int status; - pj_ansi_snprintf(TARGET_URI, sizeof(TARGET_URI), "sip:bob@127.0.0.1:%d;transport=%s", - param->port, param->tp_type); - pj_ansi_snprintf(FROM_URI, sizeof(FROM_URI), "sip:alice@127.0.0.1:%d;transport=%s", - param->port, param->tp_type); + g[tid].test_param = param; + g[tid].tp_flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)param->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; + /* Create loop transport */ + g[tid].loop = NULL; + if (g[tid].test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + PJ_TEST_SUCCESS(pjsip_loop_start(endpt, &g[tid].loop), + NULL, return -50); + pjsip_transport_add_ref(g[tid].loop); } + + pj_ansi_snprintf(g[tid].TARGET_URI, sizeof(g[tid].TARGET_URI), + "sip:%d@127.0.0.1:%d;transport=%s", + tid, param->port, param->tp_type); + pj_ansi_snprintf(g[tid].FROM_URI, sizeof(g[tid].FROM_URI), + "sip:tsx_uas_test@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + /* 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; + if ((status=register_modules(tid)) != PJ_SUCCESS) { + if (g[tid].loop) { + pjsip_transport_dec_ref(g[tid].loop); + g[tid].loop = NULL; + } + return -20; } /* TEST1_BRANCH_ID: Basic 2xx final response. * TEST2_BRANCH_ID: Basic non-2xx final response. */ - status = tsx_basic_final_response_test(); + status = tsx_basic_final_response_test(tid); if (status != 0) - return status; + goto on_return; /* TEST3_BRANCH_ID: with provisional response */ - status = tsx_basic_provisional_response_test(); + status = tsx_basic_provisional_response_test(tid); if (status != 0) - return status; + goto on_return; /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state */ - status = tsx_retransmit_last_response_test(TEST4_TITLE, + status = tsx_retransmit_last_response_test(tid, TEST4_TITLE, TEST4_BRANCH_ID, TEST4_REQUEST_COUNT, TEST4_STATUS_CODE); if (status != 0) - return status; + goto on_return; /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state */ - status = tsx_retransmit_last_response_test(TEST5_TITLE, + status = tsx_retransmit_last_response_test(tid, TEST5_TITLE, TEST5_BRANCH_ID, TEST5_REQUEST_COUNT, TEST5_STATUS_CODE); if (status != 0) - return status; + goto on_return; /* 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, + if ((g[tid].tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_retransmit_last_response_test(tid, TEST6_TITLE, TEST6_BRANCH_ID, TEST6_REQUEST_COUNT, TEST6_STATUS_CODE); if (status != 0) - return status; + goto on_return; } /* 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(); + status = tsx_final_response_retransmission_test(tid); if (status != 0) - return status; + goto on_return; /* 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 ((g[tid].tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_ack_test(tid); if (status != 0) - return status; + goto on_return; } /* TEST10_BRANCH_ID: test transport failure in TRYING state. @@ -1665,27 +1843,22 @@ int tsx_uas_test(struct tsx_test_param *param) */ /* Only valid for loop-dgram */ if (param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { - status = tsx_transport_failure_test(); + status = tsx_transport_failure_test(tid); if (status != 0) - return status; + goto on_return; } + status = 0; - /* 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; - } - +on_return: - if (loop) - pjsip_transport_dec_ref(loop); + if (g[tid].loop) { + /* Order must be shutdown then dec_ref so it gets destroyed */ + pjsip_transport_shutdown(g[tid].loop); + pjsip_transport_dec_ref(g[tid].loop); + g[tid].loop = NULL; + } - return 0; + unregister_modules(tid); + return status; } diff --git a/pjsip/src/test/txdata_test.c b/pjsip/src/test/txdata_test.c index ee0ce4d47f..b06f9b8615 100644 --- a/pjsip/src/test/txdata_test.c +++ b/pjsip/src/test/txdata_test.c @@ -636,7 +636,7 @@ static int create_request_bench(pj_timestamp *p_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_from = pj_str("\"Local User\" "); pj_str_t str_to = pj_str("\"Remote User\" "); pj_str_t str_contact = str_from; @@ -695,7 +695,7 @@ static int create_response_bench(pj_timestamp *p_elapsed) /* 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_from = pj_str("\"Local User\" "); pj_str_t str_to = pj_str("\"Remote User\" "); pj_str_t str_contact = str_from; diff --git a/tests/pjsua/runall.py b/tests/pjsua/runall.py index c0b0231dc4..7648f8bd3f 100644 --- a/tests/pjsua/runall.py +++ b/tests/pjsua/runall.py @@ -222,7 +222,7 @@ if (i < retry_num + 1): continue if with_log: - lines = open(logname, "r", encoding='utf-8').readlines() + lines = open(logname, "r", encoding='utf-8', errors='ignore').readlines() print(''.join(lines)) print("Log file: '" + logname + "'.") fails_cnt += 1 diff --git a/third_party/BaseClasses/renbase.cpp b/third_party/BaseClasses/renbase.cpp index b354b5fb6d..8ea70c953f 100644 --- a/third_party/BaseClasses/renbase.cpp +++ b/third_party/BaseClasses/renbase.cpp @@ -17,6 +17,10 @@ #pragma warning(disable:4355) +#if defined(_MSC_VER) +# pragma comment(lib, "winmm.lib") +#endif + // Helper function for clamping time differences int inline TimeDiff(REFERENCE_TIME rt) {