From 251d751518b214655c12d8d1b6ce370a75854af9 Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Thu, 17 Feb 2022 13:05:23 +0900 Subject: [PATCH] Initialize git Signed-off-by: Sangchul Lee --- .gitignore | 205 - .gitlab-ci.yml | 258 - AUTHORS | 4 - COPYING | 4 - COPYING.LGPL | 510 -- COPYING.MPL | 469 -- ChangeLog | 0 Makefile.am | 64 - NEWS | 307 -- README | 71 - TODO | 14 - agent/Makefile.am | 135 - agent/address.c | 397 -- agent/address.h | 307 -- agent/agent-priv.h | 337 -- agent/agent.c | 6954 --------------------------- agent/agent.h | 1709 ------- agent/candidate.c | 426 -- agent/candidate.h | 290 -- agent/component.c | 1642 ------- agent/component.h | 319 -- agent/conncheck.c | 4886 ------------------- agent/conncheck.h | 130 - agent/debug.c | 176 - agent/debug.h | 105 - agent/discovery.c | 1353 ------ agent/discovery.h | 170 - agent/inputstream.c | 496 -- agent/inputstream.h | 87 - agent/interfaces.c | 723 --- agent/interfaces.h | 82 - agent/iostream.c | 352 -- agent/iostream.h | 91 - agent/meson.build | 49 - agent/outputstream.c | 663 --- agent/outputstream.h | 87 - agent/pseudotcp.c | 2646 ---------- agent/pseudotcp.h | 599 --- agent/stream.c | 181 - agent/stream.h | 119 - autogen.sh | 38 - common.mk | 11 - configure.ac | 417 -- docs/Makefile.am | 4 - docs/design.txt | 215 - docs/reference/Makefile.am | 2 - docs/reference/libnice/Makefile.am | 117 - docs/reference/libnice/libnice-docs.xml | 122 - docs/reference/libnice/libnice-sections.txt | 370 -- docs/reference/libnice/meson.build | 76 - docs/reference/libnice/states.gv | 25 - docs/reference/libnice/states.png | Bin 48732 -> 0 bytes examples/Makefile.am | 35 - examples/meson.build | 8 - examples/sdp-example.c | 284 -- examples/simple-example.c | 439 -- examples/threaded-example.c | 461 -- gst/Makefile.am | 58 - gst/gstnice.c | 71 - gst/gstnice.h | 40 - gst/gstnicesink.c | 584 --- gst/gstnicesink.h | 95 - gst/gstnicesrc.c | 470 -- gst/gstnicesrc.h | 87 - gst/meson.build | 23 - m4/as-compiler-flag.m4 | 64 - m4/ax_check_openssl.m4 | 124 - m4/introspection.m4 | 96 - meson.build | 320 -- meson_options.txt | 17 - nice/Makefile.am | 66 - nice/gen-def.py | 19 - nice/gen-map.py | 25 - nice/libnice.sym | 164 - nice/libnice.ver | 11 - nice/meson.build | 67 - nice/nice.h | 46 - nice/nice.pc.in | 13 - nice/test-symbols.sh | 21 - random/Makefile.am | 27 - random/meson.build | 15 - random/random-glib.c | 108 - random/random-glib.h | 56 - random/random.c | 132 - random/random.h | 79 - random/test.c | 70 - scripts/check-symbols.sh | 43 - scripts/lcov.mk | 28 - scripts/lcov.sh | 4 - scripts/make-symbol-list.sh | 6 - scripts/valgrind-test-driver | 162 - socket/Makefile.am | 45 - socket/http.c | 653 --- socket/http.h | 54 - socket/meson.build | 18 - socket/pseudossl.c | 330 -- socket/pseudossl.h | 67 - socket/socket-priv.h | 119 - socket/socket.c | 455 -- socket/socket.h | 161 - socket/socks5.c | 499 -- socket/socks5.h | 54 - socket/tcp-active.c | 269 -- socket/tcp-active.h | 51 - socket/tcp-bsd.c | 488 -- socket/tcp-bsd.h | 61 - socket/tcp-passive.c | 341 -- socket/tcp-passive.h | 56 - socket/udp-bsd.c | 384 -- socket/udp-bsd.h | 52 - socket/udp-turn-over-tcp.c | 465 -- socket/udp-turn-over-tcp.h | 54 - socket/udp-turn.c | 2275 --------- socket/udp-turn.h | 86 - stun/Makefile.am | 50 - stun/constants.h | 203 - stun/debug.c | 124 - stun/debug.h | 102 - stun/meson.build | 41 - stun/rand.c | 93 - stun/rand.h | 50 - stun/stun5389.c | 115 - stun/stun5389.h | 68 - stun/stunagent.c | 739 --- stun/stunagent.h | 521 -- stun/stuncrc32.c | 162 - stun/stuncrc32.h | 59 - stun/stunhmac.c | 217 - stun/stunhmac.h | 70 - stun/stunmessage.c | 761 --- stun/stunmessage.h | 1017 ---- stun/tests/Makefile.am | 30 - stun/tests/check-bind.sh | 57 - stun/tests/meson.build | 18 - stun/tests/test-bind.c | 472 -- stun/tests/test-conncheck.c | 312 -- stun/tests/test-format.c | 270 -- stun/tests/test-hmac.c | 90 - stun/tests/test-parse.c | 738 --- stun/tests/test-turn.c | 264 - stun/tools/Makefile.am | 31 - stun/tools/meson.build | 10 - stun/tools/stunbdc.c | 198 - stun/tools/stund.c | 331 -- stun/tools/stund.h | 46 - stun/usages/bind.c | 594 --- stun/usages/bind.h | 165 - stun/usages/ice.c | 410 -- stun/usages/ice.h | 240 - stun/usages/timer.c | 159 - stun/usages/timer.h | 250 - stun/usages/turn.c | 455 -- stun/usages/turn.h | 301 -- stun/utils.c | 132 - stun/utils.h | 79 - stun/win32_common.h | 74 - subprojects/glib.wrap | 5 - tests/Makefile.am | 152 - tests/check-test-fullmode-with-stun.sh | 36 - tests/docker/centos7-autotools/Dockerfile | 21 - tests/docker/centos7-meson/Dockerfile | 27 - tests/libnice.supp | 613 --- tests/meson.build | 98 - tests/test-add-remove-stream.c | 82 - tests/test-address.c | 237 - tests/test-bsd.c | 414 -- tests/test-build-io-stream.c | 465 -- tests/test-credentials.c | 204 - tests/test-different-number-streams.c | 218 - tests/test-drop-invalid.c | 548 --- tests/test-fallback.c | 575 --- tests/test-fullmode-with-stun.c | 51 - tests/test-fullmode.c | 1131 ----- tests/test-gstreamer.c | 336 -- tests/test-icetcp.c | 496 -- tests/test-interfaces.c | 107 - tests/test-io-stream-cancelling.c | 149 - tests/test-io-stream-closing-read.c | 138 - tests/test-io-stream-closing-write.c | 138 - tests/test-io-stream-common.c | 562 --- tests/test-io-stream-common.h | 114 - tests/test-io-stream-pollable.c | 185 - tests/test-io-stream-thread.c | 159 - tests/test-new-trickle.c | 806 ---- tests/test-nomination.c | 266 - tests/test-priority.c | 103 - tests/test-pseudotcp-fin.c | 1278 ----- tests/test-pseudotcp-fuzzy.c | 468 -- tests/test-pseudotcp-random.sh | 19 - tests/test-pseudotcp.c | 295 -- tests/test-restart.c | 495 -- tests/test-send-recv.c | 1346 ------ tests/test-socket-is-based-on.c | 125 - tests/test-tcp.c | 160 - tests/test-thread.c | 360 -- tests/test-trickle.c | 424 -- tests/test-turn.c | 400 -- tests/test-udp-turn-fragmentation.c | 228 - tests/test.c | 124 - 199 files changed, 64565 deletions(-) delete mode 100644 .gitignore delete mode 100644 .gitlab-ci.yml delete mode 100644 AUTHORS delete mode 100644 COPYING delete mode 100644 COPYING.LGPL delete mode 100644 COPYING.MPL delete mode 100644 ChangeLog delete mode 100644 Makefile.am delete mode 100644 NEWS delete mode 100644 README delete mode 100644 TODO delete mode 100644 agent/Makefile.am delete mode 100644 agent/address.c delete mode 100644 agent/address.h delete mode 100644 agent/agent-priv.h delete mode 100644 agent/agent.c delete mode 100644 agent/agent.h delete mode 100644 agent/candidate.c delete mode 100644 agent/candidate.h delete mode 100644 agent/component.c delete mode 100644 agent/component.h delete mode 100644 agent/conncheck.c delete mode 100644 agent/conncheck.h delete mode 100644 agent/debug.c delete mode 100644 agent/debug.h delete mode 100644 agent/discovery.c delete mode 100644 agent/discovery.h delete mode 100644 agent/inputstream.c delete mode 100644 agent/inputstream.h delete mode 100644 agent/interfaces.c delete mode 100644 agent/interfaces.h delete mode 100644 agent/iostream.c delete mode 100644 agent/iostream.h delete mode 100644 agent/meson.build delete mode 100644 agent/outputstream.c delete mode 100644 agent/outputstream.h delete mode 100644 agent/pseudotcp.c delete mode 100644 agent/pseudotcp.h delete mode 100644 agent/stream.c delete mode 100644 agent/stream.h delete mode 100755 autogen.sh delete mode 100644 common.mk delete mode 100644 configure.ac delete mode 100644 docs/Makefile.am delete mode 100644 docs/design.txt delete mode 100644 docs/reference/Makefile.am delete mode 100644 docs/reference/libnice/Makefile.am delete mode 100644 docs/reference/libnice/libnice-docs.xml delete mode 100644 docs/reference/libnice/libnice-sections.txt delete mode 100644 docs/reference/libnice/meson.build delete mode 100644 docs/reference/libnice/states.gv delete mode 100644 docs/reference/libnice/states.png delete mode 100644 examples/Makefile.am delete mode 100644 examples/meson.build delete mode 100644 examples/sdp-example.c delete mode 100644 examples/simple-example.c delete mode 100644 examples/threaded-example.c delete mode 100644 gst/Makefile.am delete mode 100644 gst/gstnice.c delete mode 100644 gst/gstnice.h delete mode 100644 gst/gstnicesink.c delete mode 100644 gst/gstnicesink.h delete mode 100644 gst/gstnicesrc.c delete mode 100644 gst/gstnicesrc.h delete mode 100644 gst/meson.build delete mode 100644 m4/as-compiler-flag.m4 delete mode 100644 m4/ax_check_openssl.m4 delete mode 100644 m4/introspection.m4 delete mode 100644 meson.build delete mode 100644 meson_options.txt delete mode 100644 nice/Makefile.am delete mode 100644 nice/gen-def.py delete mode 100644 nice/gen-map.py delete mode 100644 nice/libnice.sym delete mode 100644 nice/libnice.ver delete mode 100644 nice/meson.build delete mode 100644 nice/nice.h delete mode 100644 nice/nice.pc.in delete mode 100755 nice/test-symbols.sh delete mode 100644 random/Makefile.am delete mode 100644 random/meson.build delete mode 100644 random/random-glib.c delete mode 100644 random/random-glib.h delete mode 100644 random/random.c delete mode 100644 random/random.h delete mode 100644 random/test.c delete mode 100755 scripts/check-symbols.sh delete mode 100644 scripts/lcov.mk delete mode 100755 scripts/lcov.sh delete mode 100755 scripts/make-symbol-list.sh delete mode 100755 scripts/valgrind-test-driver delete mode 100644 socket/Makefile.am delete mode 100644 socket/http.c delete mode 100644 socket/http.h delete mode 100644 socket/meson.build delete mode 100644 socket/pseudossl.c delete mode 100644 socket/pseudossl.h delete mode 100644 socket/socket-priv.h delete mode 100644 socket/socket.c delete mode 100644 socket/socket.h delete mode 100644 socket/socks5.c delete mode 100644 socket/socks5.h delete mode 100644 socket/tcp-active.c delete mode 100644 socket/tcp-active.h delete mode 100644 socket/tcp-bsd.c delete mode 100644 socket/tcp-bsd.h delete mode 100644 socket/tcp-passive.c delete mode 100644 socket/tcp-passive.h delete mode 100644 socket/udp-bsd.c delete mode 100644 socket/udp-bsd.h delete mode 100644 socket/udp-turn-over-tcp.c delete mode 100644 socket/udp-turn-over-tcp.h delete mode 100644 socket/udp-turn.c delete mode 100644 socket/udp-turn.h delete mode 100644 stun/Makefile.am delete mode 100644 stun/constants.h delete mode 100644 stun/debug.c delete mode 100644 stun/debug.h delete mode 100644 stun/meson.build delete mode 100644 stun/rand.c delete mode 100644 stun/rand.h delete mode 100644 stun/stun5389.c delete mode 100644 stun/stun5389.h delete mode 100644 stun/stunagent.c delete mode 100644 stun/stunagent.h delete mode 100644 stun/stuncrc32.c delete mode 100644 stun/stuncrc32.h delete mode 100644 stun/stunhmac.c delete mode 100644 stun/stunhmac.h delete mode 100644 stun/stunmessage.c delete mode 100644 stun/stunmessage.h delete mode 100644 stun/tests/Makefile.am delete mode 100755 stun/tests/check-bind.sh delete mode 100644 stun/tests/meson.build delete mode 100644 stun/tests/test-bind.c delete mode 100644 stun/tests/test-conncheck.c delete mode 100644 stun/tests/test-format.c delete mode 100644 stun/tests/test-hmac.c delete mode 100644 stun/tests/test-parse.c delete mode 100644 stun/tests/test-turn.c delete mode 100644 stun/tools/Makefile.am delete mode 100644 stun/tools/meson.build delete mode 100644 stun/tools/stunbdc.c delete mode 100644 stun/tools/stund.c delete mode 100644 stun/tools/stund.h delete mode 100644 stun/usages/bind.c delete mode 100644 stun/usages/bind.h delete mode 100644 stun/usages/ice.c delete mode 100644 stun/usages/ice.h delete mode 100644 stun/usages/timer.c delete mode 100644 stun/usages/timer.h delete mode 100644 stun/usages/turn.c delete mode 100644 stun/usages/turn.h delete mode 100644 stun/utils.c delete mode 100644 stun/utils.h delete mode 100644 stun/win32_common.h delete mode 100644 subprojects/glib.wrap delete mode 100644 tests/Makefile.am delete mode 100755 tests/check-test-fullmode-with-stun.sh delete mode 100644 tests/docker/centos7-autotools/Dockerfile delete mode 100644 tests/docker/centos7-meson/Dockerfile delete mode 100644 tests/libnice.supp delete mode 100644 tests/meson.build delete mode 100644 tests/test-add-remove-stream.c delete mode 100644 tests/test-address.c delete mode 100644 tests/test-bsd.c delete mode 100644 tests/test-build-io-stream.c delete mode 100644 tests/test-credentials.c delete mode 100644 tests/test-different-number-streams.c delete mode 100644 tests/test-drop-invalid.c delete mode 100644 tests/test-fallback.c delete mode 100644 tests/test-fullmode-with-stun.c delete mode 100644 tests/test-fullmode.c delete mode 100644 tests/test-gstreamer.c delete mode 100644 tests/test-icetcp.c delete mode 100644 tests/test-interfaces.c delete mode 100644 tests/test-io-stream-cancelling.c delete mode 100644 tests/test-io-stream-closing-read.c delete mode 100644 tests/test-io-stream-closing-write.c delete mode 100644 tests/test-io-stream-common.c delete mode 100644 tests/test-io-stream-common.h delete mode 100644 tests/test-io-stream-pollable.c delete mode 100644 tests/test-io-stream-thread.c delete mode 100644 tests/test-new-trickle.c delete mode 100644 tests/test-nomination.c delete mode 100644 tests/test-priority.c delete mode 100644 tests/test-pseudotcp-fin.c delete mode 100644 tests/test-pseudotcp-fuzzy.c delete mode 100755 tests/test-pseudotcp-random.sh delete mode 100644 tests/test-pseudotcp.c delete mode 100644 tests/test-restart.c delete mode 100644 tests/test-send-recv.c delete mode 100644 tests/test-socket-is-based-on.c delete mode 100644 tests/test-tcp.c delete mode 100644 tests/test-thread.c delete mode 100644 tests/test-trickle.c delete mode 100644 tests/test-turn.c delete mode 100644 tests/test-udp-turn-fragmentation.c delete mode 100644 tests/test.c diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 47c587d..0000000 --- a/.gitignore +++ /dev/null @@ -1,205 +0,0 @@ -*.lo -*.loT -*.o -*.la -*.gcda -*.gcno -Makefile -Makefile.in -.deps -.libs -*~ -*# -.#* -*.stamp -*.trs -*.log -m4/gtk-doc.m4 -m4/libtool.m4 -m4/ltoptions.m4 -m4/ltsugar.m4 -m4/ltversion.m4 -m4/lt~obsolete.m4 - -aclocal.m4 -autom4te.cache -autoregen.sh -config.guess -config.h -config.h.in -config.log -config.status -config.sub -configure -compile -depcomp -diff -gtk-doc.make -INSTALL -install-sh -libtool -ltmain.sh -missing -stamp-h.in -stamp-h1 -test-driver - -# top level stuff -debian - -# address/ stuff -address/libaddress.la -address/test - -# agent/ stuff -agent/libagent.la -agent/test -agent/test-add-remove-stream -agent/test-recv -agent/test-stun -agent/test-priority -agent/test-send -agent/test-poll -agent/test-mainloop -agent/stund.pid -agent/test-fallback -agent/test-fullmode -agent/test-restart -agent/test-thread -agent/Nice-*.gir -agent/Nice-*.typelib -agent/agent-enum-types.c -agent/agent-enum-types.h - - -# stun/ stuff -stun/stunbdc -stun/stund -stun/unknown.c -stun/libstun.la -stun/tools/stunbdc -stun/tools/stund -stun/test-attribute-dump -stun/test-attribute-dump-unknown -stun/test-attribute-pack -stun/test-attribute-pack-unknown -stun/test-attribute-unpack -stun/test-attribute-unpack-unknown -stun/test-attribute-unpack-wrong-length -stun/test-message-dump -stun/test-message-dump-unknown -stun/test-message-pack -stun/test-message-unpack -stun/tests/test-bind -stun/tests/test-conncheck -stun/tests/test-format -stun/tests/test-hmac -stun/tests/test-parse -stun/usages/.dirstamp - -# local/ stuff -local/liblocal.la -local/list-local-interfaces - -# udp/ stuff -udp/libudp.la -udp/udp-client -udp/udp-echo-server -udp/test-fake -udp/test-bsd - -# nice/ stuff -nice/libnice.la -nice/libnice.pc -nice/ice-test-client -nice/ice-test-server -nice/jingle-test-server -nice/test-readline -nice/test-util -nice/nice.pc -nice/libnice.symbols -nice/libnice-symbols-test.c - -# random/ stuff -random/librandom.la -random/test - -# gst/ stuff -gst/libgstnice.la -gst/jingle-gst-test-server - -# tests/ stuff -tests/rand -tests/rand-copy -tests/test -tests/test-add-remove-stream -tests/test-address -tests/test-bsd -tests/test-build-io-stream -tests/test-fallback -tests/test-fullmode -tests/test-icetcp -tests/test-io-stream-cancelling -tests/test-io-stream-closing-read -tests/test-io-stream-closing-write -tests/test-io-stream-thread -tests/test-io-stream-pollable -tests/test-send-recv -tests/test-mainloop -tests/test-new-trickle -tests/test-priority -tests/test-pseudotcp -tests/test-pseudotcp-fin -tests/test-pseudotcp-fuzzy -tests/test-pseudotcp-fin -tests/test-restart -tests/test-tcp -tests/test-thread -tests/test-trickle -tests/test-nomination -tests/test-credentials -tests/test-different-number-streams -tests/test-drop-invalid -tests/test-gstreamer -tests/test-socket-is-based-on -tests/test-turn -tests/test-udp-turn-fragmentation - -# examples/ stuff -examples/simple-example -examples/threaded-example -examples/sdp-example - -# docs/ stuff -docs/reference/libnice/gtkdoc-check.test -docs/reference/libnice/libnice-decl-list.txt -docs/reference/libnice/libnice-decl.txt -docs/reference/libnice/libnice-overrides.txt -docs/reference/libnice/libnice-undeclared.txt -docs/reference/libnice/libnice-undocumented.txt -docs/reference/libnice/libnice-unused.txt -docs/reference/libnice/libnice.args -docs/reference/libnice/libnice.hierarchy -docs/reference/libnice/libnice.interfaces -docs/reference/libnice/libnice.prerequisites -docs/reference/libnice/libnice.signals -docs/reference/libnice/libnice.types -docs/reference/libnice/html -docs/reference/libnice/tmpl -docs/reference/libnice/xml - -# win32 stuff -win32/vs9/libnice.def -win32/vs9/*.user -win32/vs9/libnice.ncb -win32/vs9/libnice.suo -win32/vs9/libnice/ -glib/ -*.exe -ar-lib - -# Code coverage -lcov/ - -# Meson builddir -_build/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index d72afd5..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,258 +0,0 @@ -stages: - - build - - test - - deploy - -build autotools: - stage: build - image: registry.freedesktop.org/libnice/libnice/centos7/autotools-build - except: - - schedules - script: - - ifconfig - - export BUILD_ID="libnice-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID" - - export PREFIX="$(pwd)/prefix-$BUILD_ID" - - export MAKEFLAGS="-j4" - - mkdir "$PREFIX" - - ./autogen.sh --prefix="$PREFIX" --enable-compile-warnings=error --enable-gtk-doc --enable-introspection - - make - - make install - artifacts: - untracked: true - -test autotools: - stage: test - image: registry.freedesktop.org/libnice/libnice/centos7/autotools-build - except: - - schedules - needs: - - build autotools - script: - - ifconfig - - make check - artifacts: - when: always - paths: - - config.log - - nice/test-suite.log - - random/test-suite.log - - tests/test-suite.log - - stun/tests/test-suite.log - - docs/reference/libnice/test-suite.log - -test autotools valgrind: - extends: test autotools - script: - - ifconfig - - make check-valgrind - -distcheck autotools: - stage: test - image: registry.freedesktop.org/libnice/libnice/centos7/autotools-build - except: - - schedules - needs: - - build autotools - script: - - ifconfig - - make distcheck - artifacts: - paths: - - libnice-*.tar.gz - -build meson: - stage: build - image: registry.freedesktop.org/libnice/libnice/centos7/meson-build - variables: - PREFIX: "${CI_PROJECT_DIR}/libnice-prefix" - except: - - schedules - before_script: - - mkdir -p "${CI_PROJECT_DIR}" - script: - ## && true to make gitlab-ci happy - - source scl_source enable rh-python36 && true - - meson --werror --warnlevel 2 -Dgtk_doc=enabled --prefix=$PREFIX build/ - - ninja-build -C build/ - artifacts: - paths: - - build/ - -build msys2: - image: 'registry.freedesktop.org/gstreamer/gst-ci/amd64/windows:v10' - stage: 'build' - allow_failure: true - tags: - - 'docker' - - 'windows' - - '1809' - variables: - MESON_ARGS: > - --prefix=${CI_PROJECT_DIR}/libnice-prefix - # Make sure any failure in PowerShell scripts is fatal - ErrorActionPreference: 'Stop' - WarningPreference: 'Stop' - before_script: - - pip3 install -U meson - script: - # Make sure powershell exists on errors - # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-6 - - $ErrorActionPreference = "Stop" - - # For some reason docker build hangs if this is included in the image, needs more troubleshooting - - $env:PATH += ';C:\msys64\usr\bin;C:\msys64\mingw64\bin;C:\msys64\mingw32\bin' - - C:\msys64\usr\bin\bash -c "pacman-key --init && pacman-key --populate msys2 && pacman-key --refresh-keys || true" - - C:\msys64\usr\bin\bash -c "pacman -Syuu --noconfirm" - - C:\msys64\usr\bin\bash -c "pacman -Sy --noconfirm --needed mingw-w64-x86_64-toolchain ninja" - - # For some reason, options are separated by newline instead of space, so we - # have to replace them first. - - $env:MESON_ARGS = $env:MESON_ARGS.replace("`n"," ") - - - $env:PATH += ";C:\msys64\usr\bin;C:\msys64\mingw64/bin;C:\msys64\mingw32/bin" - - # For some reason, options are separated by newline instead of space, so we - # have to replace them first. - - $env:CI_PROJECT_DIR = $env:CI_PROJECT_DIR.replace('\','/') - - $env:MESON_ARGS = $env:MESON_ARGS.replace('\','/') - - # Build and run the tests. - # This is part of the same job due to a bug in the gitlab-runner - # that prevents us from exporting artifacts with docker-windows - # executors. It has since been fixed in gitlab 12.1, but - # we are blocked from upgrading currently. - # - # Gitlab Runner issue: https://gitlab.com/gitlab-org/gitlab-runner/issues/4291 - # Blocked upgrade issue: https://gitlab.freedesktop.org/gstreamer/gst-ci/issues/6#note_192780 - - C:\msys64\usr\bin\bash -c "meson build $env:MESON_ARGS && - ninja -C build && - meson test -C build --print-errorlogs --suite libnice" - artifacts: - when: on_failure - paths: - - build/meson-logs/ - - build/build.ninja - -.build msvc: - extends: build msys2 - allow_failure: false - variables: - GLIB_VERSION: 2.64.2 - script: - # For some reason, options are separated by newline instead of space, so we - # have to replace them first. - - $env:MESON_ARGS = $env:MESON_ARGS.replace("`n"," ") - - # Build and run the tests. - # This is part of the same job due to a bug in the gitlab-runner - # that prevents us from exporting artifacts with docker-windows - # executors. It has since been fixed in gitlab 12.1, but - # we are blocked from upgrading currently. - # - # Gitlab Runner issue: https://gitlab.com/gitlab-org/gitlab-runner/issues/4291 - # Blocked upgrade issue: https://gitlab.freedesktop.org/gstreamer/gst-ci/issues/6#note_192780 - - New-Item -Path subprojects -Name openssl.wrap -Value "[wrap-git]`r`ndirectory=openssl`r`nurl=https://gitlab.freedesktop.org/libnice/openssl-binaries-for-ci.git`r`nrevision=1.1.1c`r`n" - - cmd.exe /C "C:\BuildTools\Common7\Tools\VsDevCmd.bat -host_arch=amd64 -arch=$env:ARCH && - meson subprojects download && - meson wrap promote subprojects\glib-$env:GLIB_VERSION\subprojects\libffi.wrap && - meson wrap promote subprojects\glib-$env:GLIB_VERSION\subprojects\zlib.wrap && - meson wrap promote subprojects\glib-$env:GLIB_VERSION\subprojects\proxy-libintl.wrap && - meson subprojects download" - - cmd.exe /C "C:\BuildTools\Common7\Tools\VsDevCmd.bat -host_arch=amd64 -arch=$env:ARCH && - meson build $env:MESON_ARGS && - ninja -C build && - meson test -C build --print-errorlogs --suite libnice" - -build msvc amd64: - extends: .build msvc - variables: - ARCH: 'amd64' - -build msvc x86: - extends: .build msvc - variables: - ARCH: 'x86' - -test meson: - stage: test - image: registry.freedesktop.org/libnice/libnice/centos7/meson-build - needs: - - build meson - except: - - schedules - script: - - ifconfig - - source scl_source enable rh-python36 && true - - meson test -C build/ --setup debug - artifacts: - when: on_failure - paths: - - build/meson-logs/ - - -test valgrind meson: - extends: test meson - script: - - ifconfig - - source scl_source enable rh-python36 && true - - meson configure build -Dgtk_doc=disabled - - meson test -C build/ --setup valgrind --print-errorlogs - - -doc-and-install meson: - stage: test - image: registry.freedesktop.org/libnice/libnice/centos7/meson-build - needs: - - build meson - except: - - schedules - variables: - PREFIX: "${CI_PROJECT_DIR}/libnice-prefix" - script: - - source scl_source enable rh-python36 && true - - ninja-build -C build/ libnice-doc - - ninja-build -C build/ install - - ls -lR ${PREFIX} - artifacts: - paths: - - build/docs/reference/libnice/html/ - -submit-to-coverity: - stage: test - image: registry.freedesktop.org/libnice/libnice/centos7/meson-build - variables: - COVERITY_PROJECT: libnice - PREFIX: "${CI_PROJECT_DIR}/libnice-prefix" - only: - - schedules - - web - dependencies: [] - before_script: - - mkdir -p "${CI_PROJECT_DIR}" - script: - - curl -v https://scan.coverity.com/download/linux64 -o coverity_tool.tgz --form token="${COVERITY_TOKEN}" --form project="${COVERITY_PROJECT}" && tar xf coverity_tool.tgz && rm coverity_tool.tgz - - mv cov-analysis-linux64-* cov-analysis-linux64 - - source scl_source enable rh-python36 && true - - meson --werror --warnlevel 2 -Dgtk_doc=disabled -Dinstrospection=disabled --prefix=$PREFIX cov-build/ - - export PATH="$PATH:${CI_PROJECT_DIR}/cov-analysis-linux64/bin" - - echo $PATH - - cov-build --dir cov-int ninja-build -C cov-build - - tar czvf libnice.tgz cov-int - - curl --form token=$COVERITY_TOKEN --form email=olivier.crete@ocrete.ca --form file=@libnice.tgz --form version="${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}" --form description="CI weekly run" https://scan.coverity.com/builds?project=libnice - - -documentation: - stage: deploy - dependencies: - - doc-and-install meson - only: - - latest-release - artifacts: - paths: - - public - expire_in: 1 year -# Needs gitlab 12.8, we're on 12.7 now -# trigger: libnice/libnice- - script: - - mkdir public/ - - mv build/docs/reference/libnice/html/ public/libnice/ diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index ea3be82..0000000 --- a/AUTHORS +++ /dev/null @@ -1,4 +0,0 @@ -Dafydd Harries -Rémi Denis-Courmont -Kai Vehmanen -Youness Alaoui diff --git a/COPYING b/COPYING deleted file mode 100644 index 994c3c4..0000000 --- a/COPYING +++ /dev/null @@ -1,4 +0,0 @@ -The Nice Glib ICE library is licensed under both the Mozilla Public License -version 1.1 and the GNU Lesser General Public License version 2.1. For the -full text of these licenses, see the files COPYING.MPL and COPYING.LGPL -respectively. diff --git a/COPYING.LGPL b/COPYING.LGPL deleted file mode 100644 index 2d2d780..0000000 --- a/COPYING.LGPL +++ /dev/null @@ -1,510 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations -below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it -becomes a de-facto standard. To achieve this, non-free programs must -be allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control -compilation and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at least - three years, to give the same user the materials specified in - Subsection 6a, above, for a charge no more than the cost of - performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply, and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License -may add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms -of the ordinary General Public License). - - To apply these terms, attach the following notices to the library. -It is safest to attach them to the start of each source file to most -effectively convey the exclusion of warranty; and each file should -have at least the "copyright" line and a pointer to where the full -notice is found. - - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or -your school, if any, to sign a "copyright disclaimer" for the library, -if necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James - Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/COPYING.MPL b/COPYING.MPL deleted file mode 100644 index a889bce..0000000 --- a/COPYING.MPL +++ /dev/null @@ -1,469 +0,0 @@ - MOZILLA PUBLIC LICENSE - Version 1.1 - - --------------- - -1. Definitions. - - 1.0.1. "Commercial Use" means distribution or otherwise making the - Covered Code available to a third party. - - 1.1. "Contributor" means each entity that creates or contributes to - the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Code, prior Modifications used by a Contributor, and the Modifications - made by that particular Contributor. - - 1.3. "Covered Code" means the Original Code or Modifications or the - combination of the Original Code and Modifications, in each case - including portions thereof. - - 1.4. "Electronic Distribution Mechanism" means a mechanism generally - accepted in the software development community for the electronic - transfer of data. - - 1.5. "Executable" means Covered Code in any form other than Source - Code. - - 1.6. "Initial Developer" means the individual or entity identified - as the Initial Developer in the Source Code notice required by Exhibit - A. - - 1.7. "Larger Work" means a work which combines Covered Code or - portions thereof with code not governed by the terms of this License. - - 1.8. "License" means this document. - - 1.8.1. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means any addition to or deletion from the - substance or structure of either the Original Code or any previous - Modifications. When Covered Code is released as a series of files, a - Modification is: - A. Any addition to or deletion from the contents of a file - containing Original Code or previous Modifications. - - B. Any new file that contains any part of the Original Code or - previous Modifications. - - 1.10. "Original Code" means Source Code of computer software code - which is described in the Source Code notice required by Exhibit A as - Original Code, and which, at the time of its release under this - License is not already Covered Code governed by this License. - - 1.10.1. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.11. "Source Code" means the preferred form of the Covered Code for - making modifications to it, including all modules it contains, plus - any associated interface definition files, scripts used to control - compilation and installation of an Executable, or source code - differential comparisons against either the Original Code or another - well known, available Covered Code of the Contributor's choice. The - Source Code can be in a compressed or archival form, provided the - appropriate decompression or de-archiving software is widely available - for no charge. - - 1.12. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, this - License or a future version of this License issued under Section 6.1. - For legal entities, "You" includes any entity which controls, is - controlled by, or is under common control with You. For purposes of - this definition, "control" means (a) the power, direct or indirect, - to cause the direction or management of such entity, whether by - contract or otherwise, or (b) ownership of more than fifty percent - (50%) of the outstanding shares or beneficial ownership of such - entity. - -2. Source Code License. - - 2.1. The Initial Developer Grant. - The Initial Developer hereby grants You a world-wide, royalty-free, - non-exclusive license, subject to third party intellectual property - claims: - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Code (or portions thereof) with or without Modifications, and/or - as part of a Larger Work; and - - (b) under Patents Claims infringed by the making, using or - selling of Original Code, to make, have made, use, practice, - sell, and offer for sale, and/or otherwise dispose of the - Original Code (or portions thereof). - - (c) the licenses granted in this Section 2.1(a) and (b) are - effective on the date Initial Developer first distributes - Original Code under the terms of this License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: 1) for code that You delete from the Original Code; 2) - separate from the Original Code; or 3) for infringements caused - by: i) the modification of the Original Code or ii) the - combination of the Original Code with other software or devices. - - 2.2. Contributor Grant. - Subject to third party intellectual property claims, each Contributor - hereby grants You a world-wide, royalty-free, non-exclusive license - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor, to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof) either on an - unmodified basis, with other Modifications, as Covered Code - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or - selling of Modifications made by that Contributor either alone - and/or in combination with its Contributor Version (or portions - of such combination), to make, use, sell, offer for sale, have - made, and/or otherwise dispose of: 1) Modifications made by that - Contributor (or portions thereof); and 2) the combination of - Modifications made by that Contributor with its Contributor - Version (or portions of such combination). - - (c) the licenses granted in Sections 2.2(a) and 2.2(b) are - effective on the date Contributor first makes Commercial Use of - the Covered Code. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: 1) for any code that Contributor has deleted from the - Contributor Version; 2) separate from the Contributor Version; - 3) for infringements caused by: i) third party modifications of - Contributor Version or ii) the combination of Modifications made - by that Contributor with other software (except as part of the - Contributor Version) or other devices; or 4) under Patent Claims - infringed by Covered Code in the absence of Modifications made by - that Contributor. - -3. Distribution Obligations. - - 3.1. Application of License. - The Modifications which You create or to which You contribute are - governed by the terms of this License, including without limitation - Section 2.2. The Source Code version of Covered Code may be - distributed only under the terms of this License or a future version - of this License released under Section 6.1, and You must include a - copy of this License with every copy of the Source Code You - distribute. You may not offer or impose any terms on any Source Code - version that alters or restricts the applicable version of this - License or the recipients' rights hereunder. However, You may include - an additional document offering the additional rights described in - Section 3.5. - - 3.2. Availability of Source Code. - Any Modification which You create or to which You contribute must be - made available in Source Code form under the terms of this License - either on the same media as an Executable version or via an accepted - Electronic Distribution Mechanism to anyone to whom you made an - Executable version available; and if made available via Electronic - Distribution Mechanism, must remain available for at least twelve (12) - months after the date it initially became available, or at least six - (6) months after a subsequent version of that particular Modification - has been made available to such recipients. You are responsible for - ensuring that the Source Code version remains available even if the - Electronic Distribution Mechanism is maintained by a third party. - - 3.3. Description of Modifications. - You must cause all Covered Code to which You contribute to contain a - file documenting the changes You made to create that Covered Code and - the date of any change. You must include a prominent statement that - the Modification is derived, directly or indirectly, from Original - Code provided by the Initial Developer and including the name of the - Initial Developer in (a) the Source Code, and (b) in any notice in an - Executable version or related documentation in which You describe the - origin or ownership of the Covered Code. - - 3.4. Intellectual Property Matters - (a) Third Party Claims. - If Contributor has knowledge that a license under a third party's - intellectual property rights is required to exercise the rights - granted by such Contributor under Sections 2.1 or 2.2, - Contributor must include a text file with the Source Code - distribution titled "LEGAL" which describes the claim and the - party making the claim in sufficient detail that a recipient will - know whom to contact. If Contributor obtains such knowledge after - the Modification is made available as described in Section 3.2, - Contributor shall promptly modify the LEGAL file in all copies - Contributor makes available thereafter and shall take other steps - (such as notifying appropriate mailing lists or newsgroups) - reasonably calculated to inform those who received the Covered - Code that new knowledge has been obtained. - - (b) Contributor APIs. - If Contributor's Modifications include an application programming - interface and Contributor has knowledge of patent licenses which - are reasonably necessary to implement that API, Contributor must - also include this information in the LEGAL file. - - (c) Representations. - Contributor represents that, except as disclosed pursuant to - Section 3.4(a) above, Contributor believes that Contributor's - Modifications are Contributor's original creation(s) and/or - Contributor has sufficient rights to grant the rights conveyed by - this License. - - 3.5. Required Notices. - You must duplicate the notice in Exhibit A in each file of the Source - Code. If it is not possible to put such notice in a particular Source - Code file due to its structure, then You must include such notice in a - location (such as a relevant directory) where a user would be likely - to look for such a notice. If You created one or more Modification(s) - You may add your name as a Contributor to the notice described in - Exhibit A. You must also duplicate this License in any documentation - for the Source Code where You describe recipients' rights or ownership - rights relating to Covered Code. You may choose to offer, and to - charge a fee for, warranty, support, indemnity or liability - obligations to one or more recipients of Covered Code. However, You - may do so only on Your own behalf, and not on behalf of the Initial - Developer or any Contributor. You must make it absolutely clear than - any such warranty, support, indemnity or liability obligation is - offered by You alone, and You hereby agree to indemnify the Initial - Developer and every Contributor for any liability incurred by the - Initial Developer or such Contributor as a result of warranty, - support, indemnity or liability terms You offer. - - 3.6. Distribution of Executable Versions. - You may distribute Covered Code in Executable form only if the - requirements of Section 3.1-3.5 have been met for that Covered Code, - and if You include a notice stating that the Source Code version of - the Covered Code is available under the terms of this License, - including a description of how and where You have fulfilled the - obligations of Section 3.2. The notice must be conspicuously included - in any notice in an Executable version, related documentation or - collateral in which You describe recipients' rights relating to the - Covered Code. You may distribute the Executable version of Covered - Code or ownership rights under a license of Your choice, which may - contain terms different from this License, provided that You are in - compliance with the terms of this License and that the license for the - Executable version does not attempt to limit or alter the recipient's - rights in the Source Code version from the rights set forth in this - License. If You distribute the Executable version under a different - license You must make it absolutely clear that any terms which differ - from this License are offered by You alone, not by the Initial - Developer or any Contributor. You hereby agree to indemnify the - Initial Developer and every Contributor for any liability incurred by - the Initial Developer or such Contributor as a result of any such - terms You offer. - - 3.7. Larger Works. - You may create a Larger Work by combining Covered Code with other code - not governed by the terms of this License and distribute the Larger - Work as a single product. In such a case, You must make sure the - requirements of this License are fulfilled for the Covered Code. - -4. Inability to Comply Due to Statute or Regulation. - - If it is impossible for You to comply with any of the terms of this - License with respect to some or all of the Covered Code due to - statute, judicial order, or regulation then You must: (a) comply with - the terms of this License to the maximum extent possible; and (b) - describe the limitations and the code they affect. Such description - must be included in the LEGAL file described in Section 3.4 and must - be included with all distributions of the Source Code. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Application of this License. - - This License applies to code to which the Initial Developer has - attached the notice in Exhibit A and to related Covered Code. - -6. Versions of the License. - - 6.1. New Versions. - Netscape Communications Corporation ("Netscape") may publish revised - and/or new versions of the License from time to time. Each version - will be given a distinguishing version number. - - 6.2. Effect of New Versions. - Once Covered Code has been published under a particular version of the - License, You may always continue to use it under the terms of that - version. You may also choose to use such Covered Code under the terms - of any subsequent version of the License published by Netscape. No one - other than Netscape has the right to modify the terms applicable to - Covered Code created under this License. - - 6.3. Derivative Works. - If You create or use a modified version of this License (which you may - only do in order to apply it to code which is not already Covered Code - governed by this License), You must (a) rename Your license so that - the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", - "MPL", "NPL" or any confusingly similar phrase do not appear in your - license (except to note that your license differs from this License) - and (b) otherwise make it clear that Your version of the license - contains terms which differ from the Mozilla Public License and - Netscape Public License. (Filling in the name of the Initial - Developer, Original Code or Contributor in the notice described in - Exhibit A shall not of themselves be deemed to be modifications of - this License.) - -7. DISCLAIMER OF WARRANTY. - - COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, - WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF - DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. - THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE - IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, - YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE - COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER - OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF - ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -8. TERMINATION. - - 8.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to cure - such breach within 30 days of becoming aware of the breach. All - sublicenses to the Covered Code which are properly granted shall - survive any termination of this License. Provisions which, by their - nature, must remain in effect beyond the termination of this License - shall survive. - - 8.2. If You initiate litigation by asserting a patent infringement - claim (excluding declatory judgment actions) against Initial Developer - or a Contributor (the Initial Developer or Contributor against whom - You file such action is referred to as "Participant") alleging that: - - (a) such Participant's Contributor Version directly or indirectly - infringes any patent, then any and all rights granted by such - Participant to You under Sections 2.1 and/or 2.2 of this License - shall, upon 60 days notice from Participant terminate prospectively, - unless if within 60 days after receipt of notice You either: (i) - agree in writing to pay Participant a mutually agreeable reasonable - royalty for Your past and future use of Modifications made by such - Participant, or (ii) withdraw Your litigation claim with respect to - the Contributor Version against such Participant. If within 60 days - of notice, a reasonable royalty and payment arrangement are not - mutually agreed upon in writing by the parties or the litigation claim - is not withdrawn, the rights granted by Participant to You under - Sections 2.1 and/or 2.2 automatically terminate at the expiration of - the 60 day notice period specified above. - - (b) any software, hardware, or device, other than such Participant's - Contributor Version, directly or indirectly infringes any patent, then - any rights granted to You by such Participant under Sections 2.1(b) - and 2.2(b) are revoked effective as of the date You first made, used, - sold, distributed, or had made, Modifications made by that - Participant. - - 8.3. If You assert a patent infringement claim against Participant - alleging that such Participant's Contributor Version directly or - indirectly infringes any patent where such claim is resolved (such as - by license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 8.4. In the event of termination under Sections 8.1 or 8.2 above, - all end user license agreements (excluding distributors and resellers) - which have been validly granted by You or any distributor hereunder - prior to termination shall survive termination. - -9. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL - DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, - OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR - ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY - CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, - WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER - COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN - INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF - LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY - RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW - PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE - EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO - THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. - -10. U.S. GOVERNMENT END USERS. - - The Covered Code is a "commercial item," as that term is defined in - 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" and "commercial computer software documentation," as such - terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 - C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), - all U.S. Government End Users acquire Covered Code with only those - rights set forth herein. - -11. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - California law provisions (except to the extent applicable law, if - any, provides otherwise), excluding its conflict-of-law provisions. - With respect to disputes in which at least one party is a citizen of, - or an entity chartered or registered to do business in the United - States of America, any litigation relating to this License shall be - subject to the jurisdiction of the Federal Courts of the Northern - District of California, with venue lying in Santa Clara County, - California, with the losing party responsible for costs, including - without limitation, court costs and reasonable attorneys' fees and - expenses. The application of the United Nations Convention on - Contracts for the International Sale of Goods is expressly excluded. - Any law or regulation which provides that the language of a contract - shall be construed against the drafter shall not apply to this - License. - -12. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - -13. MULTIPLE-LICENSED CODE. - - Initial Developer may designate portions of the Covered Code as - "Multiple-Licensed". "Multiple-Licensed" means that the Initial - Developer permits you to utilize portions of the Covered Code under - Your choice of the NPL or the alternative licenses, if any, specified - by the Initial Developer in the file described in Exhibit A. - -EXHIBIT A -Mozilla Public License. - - ``The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is the Nice GLib ICE library. - - The Initial Developers of the Original Code are Collabora Ltd and Nokia - Corporation. All Rights Reserved. - - Contributor(s): ______________________________________. - - Alternatively, the contents of this file may be used under the terms - of the _____ license (the "[___] License"), in which case the - provisions of [______] License are applicable instead of those - above. If you wish to allow use of your version of this file only - under the terms of the [____] License and not to allow others to use - your version of this file under the MPL, indicate your decision by - deleting the provisions above and replace them with the notice and - other provisions required by the [___] License. If you do not delete - the provisions above, a recipient may use your version of this file - under either the MPL or the [___] License." - - [NOTE: The text of this Exhibit A may differ slightly from the text of - the notices in the Source Code files of the Original Code. You should - use the text of this Exhibit A rather than the text found in the - Original Code Source Code for Your Modifications.] - diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index e69de29..0000000 diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 37c3a9a..0000000 --- a/Makefile.am +++ /dev/null @@ -1,64 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2006, 2007 Collabora Ltd. -# (C) 2006, 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. - -include common.mk - -ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} - -SUBDIRS = \ - stun \ - socket \ - random \ - agent \ - nice \ - gst \ - tests \ - docs \ - examples - -DISTCHECK_CONFIGURE_FLAGS = --disable-assert -enable-gtk-doc --enable-introspection - -EXTRA_DIST = \ - COPYING.LGPL \ - COPYING.MPL \ - autogen.sh \ - common.mk \ - scripts/lcov.mk \ - scripts/lcov.sh \ - scripts/valgrind-test-driver \ - m4/introspection.m4 \ - meson.build \ - meson_options.txt - -MAINTAINERCLEANFILES = ar-lib - -dist_check_SCRIPTS = \ - scripts/check-symbols.sh \ - scripts/make-symbol-list.sh - -lcov: - find -name '*.gcda' -delete - $(MAKE) $(AM_MAKEFLAGS) check - find -type d -name '.libs' | while read d ; do \ - mv -fv $$d/*.gc* $$d/.. 2>/dev/null || true ; \ - done - $(MAKE) lcov-report - -lcov-report: - mkdir -p lcov - lcov -d . -c > lcov/lcov.info - lcov -l lcov/lcov.info 2>/dev/null | \ - egrep '(^/usr|/test.*\.c)' | \ - cut -d: -f1 > lcov/lcov.remove - lcov -r lcov/lcov.info `cat lcov/lcov.remove` 2>/dev/null > lcov/lcov.info.clean - genhtml -o lcov lcov/lcov.info.clean - -clean-local: - rm -rf doc - -.PHONY: doc lcov-report lcov diff --git a/NEWS b/NEWS deleted file mode 100644 index a44a2fc..0000000 --- a/NEWS +++ /dev/null @@ -1,307 +0,0 @@ -libnice 0.1.17 (2020-05-22) -=========================== -Add API to retrieve the underlying BSD sockets -Support systems with multiple loopback devices -Ignore non-running network interfaces -Ignore multiple interface prefixes -Now tries to nominate matching pairs across components and streams -Retry TURN deallocation on timeout, requires not destoying the NiceAgent right after the stream -Use different port for every host candidate -Make timeouts and retransmissions more in line with the RFCs -Find OpenSSL without pkg-config, for Windows -Complete meson support -GLib required version update to 2.54 -Removed deprecated GLib APIs -Many ICE compatibility and performance improvements -Many bug fixes - -libnice 0.1.16 (2019-05-09) -=========================== -Add API to make it easier to implement ICE trickle -Add async closing of agent, to cleanly close TURN allocations -Add Google non-standard NOMINATION STUN attribute -Fix tests on Windows -Fix some racy tests - -libnice 0.1.15 (2018-12-27) -=========================== -Add support for Regular Nomination -Removal of the global lock over all agents -Add method to compare candidate targets -Added optional Meson build system, future releases will remove autotools -Renamed all members of PseudoTcpState enum (compile-time API change) -Now drops all packets from addresses that have not been validated by an ICE check -Multiple improvements to ICE interoperability -Improved RFC compliance -Improved OC2007 compatibility mode alternate-server support - -libnice 0.1.14 (2017-04-03) -=========================== -Improved RFC compliance -Split verbose logs into a separate option -Numerous bug fixes -Use GnuTLS for hash functions -Implement NewReno in PseudoTCP -Requires GLib 2.44 GnuTLS 2.12 - -libnice 0.1.13 (2015-04-28) -=========================== -Fix build on non-Windows platforms that don't have getifaddrs() -Fix build regression on Windows - -libnice 0.1.12 (2015-04-22) -=========================== -Fix regression in SDP parser -Make examples work on Windows -Bug fixes on nicesrc - -libnice 0.1.11 (2015-04-20) -=========================== -API: nice_agent_set_local_credentials() for WebRTC -Nicesink: support GstBufferList -Better warnings on programming errors -Build fixes for Solaris and Windows -Bug and documentation fixes - -libnice 0.1.10 (2015-01-28) -=========================== -Fix bug on component change on the sink - -libnice 0.1.9 (2015-01-28) -========================== -Make it possible to statically build the GStreamer plugins -Bug fixes, in particular fix compatibility with coTurn servers -Documentation fixes - -libnice 0.1.8 (2014-10-09) -========================== -Added FIN-ACK behavior in the PseudoTCP -ICE-TCP, both standard mode and Microsoft compatible -Microsoft compatible TURN-TCP -API: nice_address_equal_no_port() to compare NiceAddresses ignoring the port -API: nice_agent_get_component_state() to get the current component state -API: agent:keepalive-conncheck to make the agent use conncheck as keepalives - and fail the connection if there is no answer -API: agent:ice-tcp, agent:udp-tcp to control ICE-UDP vs ICE-TCP behaviours -API: agent:bytestream-tcp to know if the send/receives in reliable mode create full packets or not -API: New signals agent::new-selected-pair-full, agent::new-candidate-full, - agent::new-remote-candidate-full which include the NiceCandidates directly -API: Deprecated agent::new-selected-pair and agent::new-candidate and - agent::new-remote-candidate signals -Now all signals are emitted at the function return time - -libnice 0.1.7 (2014-05-05) -========================== -Fix undesired API change that broke Farstream unit testsx - -libnice 0.1.6 (2014-04-28) -========================== -API: nice_agent_restart_stream() to do a ICE restart on a single strema -API: nice_component_state_to_string() to get a printable name for a component - state -API: nice_agent_forget_relays() to forget the relays set for a - specific component, along with nice_agent_restart_stream(), it allows - changing the current relay without dropping the connection. -It is now possible to add relays after the initial candidate gathering. -Many bug fixes - -libnice 0.1.5 (2014-03-06) -========================== - -API: nice_agent_recv() and nice_agent_recv_nonblocking() as an alternative to - the nice_agent_attach_recv() -API: nice_agent_recv_messages() and nice_agent_recv_messages_nonblocking() to - receive multiple messages at the same time -API: nice_agent_get_io_stream() to get a GIOStream in reliable mode -API: nice_agent_get_selected_socket() to extract the selected GSocket -Import Google's newer PseudoTCP code including window scaling -Improve PseudoTCP performance -Improve performance -Build fixes - -libnice 0.1.4 (2013-02-22) -========================== - -Fix issue with dribble mode -Fix issue with TURN permissions -Fix missing win32 directory from release archive -Fix support for OC2007 -Added new nice_address_ip_vesion API -Added new nice_agent_get_selected_pair API -Added new SDP parsing and generation API -Added simple examples (simple, threaded and sdp usages examples) - -libnice 0.1.3 (2012-09-13) -========================== - -Dribble mode: You can set remote candidates while gathering the local ones -Add support for GStreamer 1.0, will compile plugins for both 1.0 and 0.10 by default -Cache GSocketAddress in UdpBsdSocket, creating it is very slow - -libnice 0.1.2 (2012-04-03) -========================== - -Fix a bug where a controlled agent may never go to READY if it received early conncheck -Restart connchecks on a failed candidate pair when receiving a triggered check -Fix a bug where gathering-done signal could be sent before UPnP mapping finishes -Fix a race condition where setting remote-candidates on a gathered stream failed if another stream was gathering -Many fixes to complete and stabilize TURN support -Fix a bug in proxy support where TURN packets were misread -Refactor libnice to use GSocket which works around a glib limitation of g_io_channel on windows -Fix a bug with receiving error messages during conncheck -Fix a possible infinite loop bug -Fix memory leaks and multi-threaded race conditions -Better compatibility for BSD and Mingw -Added support files for Visual Studio compilation -Various fixes to UPnP support -Fixes to the build system - -libnice 0.1.1 (2011-09-07) -========================== - -Fixed BSD and Solaris compatibility -Fixed PPC64 symbol test -Removed a few possible leak/bugs -Fixed compatibility with google's recent protocol change - -libnice 0.1.0 (2011-01-20) -========================== - -Added nice_candidate_copy to the public API -Make stun_timer timeouts configurable (Break API and ABI) -Add compatibility support for MSOC 2007 and MSOC 2007 R2 -Add MS-TURN support for MSOC -Added and completed TURN RFC 5766 support -Add a nice_agent_set_port_range API to force a component to use a specific port -Fix various bugs and memory leaks -Improve documentation - -libnice 0.0.13 (2010-07-20) -========================== - -Add support for IPv6 -Fix crc32 function conflict with libz.so -Various bug fixing and code cleaning -Validate the remote candidate address before adding it - -libnice 0.0.12 (2010-05-19) -========================== - -Update compatibility to RFC5245 -Fix a memory corruption bug -Fix a possible buffer overflow with socks5 proxies - -libnice 0.0.11 (2010-03-18) -=========================== - -Handle EAGAIN for UDP sockets -Fix coverity warnings -Fix a bug with TURN and Channel Bindings -Add a reliable transport mode using libjingle's PseudoTcp implementation -Various fixes - -libnice 0.0.10 (2009-11-04) -=========================== - -Fix some memory leaks with the gstreamer elements -Fix username/foundation for google TURN candidates -Fix the sending of hundreds of connectivity checks at once the stream is connected -Fix BSD support -Fix reprocessing of already processed early incoming checks when in dribble-mode -Fix a rare crash with failing relay candidates allocations -Add a stun_agent_set_software API -Add a nice_agent_set_software API - -libnice 0.0.9 (2009-07-31) -=========================== - -Fix some more issues with peer-reflexive candidates in google mode (for early incoming checks) -Fix SHA1 algorithm when strict aliasing is used -Fix google mode connectivity with discovered remote peer reflexive candidates -Fix google/msn mode by not limiting the conncheck list -Fix the interfaces discovery by using getifaddrs -Fix compilation on Mac OS X -Add ToS support to the sockets - - -libnice 0.0.8 (2009-06-19) -=========================== - -Remove deprecated g_strcasecmp call -Use addr instead of base_addr on assigning remote peer-reflexive candidates (fixes crash) -Use a global mutex and g_source_is_destroyed to avoid race conditions (fixes crashes) -Unlock the mutex before calling the recv callback - -libnice 0.0.7 (2009-06-11) -=========================== - -Added UPnP Support -Fix a race condition when destroying the nice agent -Stun headers are now installed -Unset timer's source if they return FALSE -Fix interoperability with gtalk2voip.com -Avoid a race condition where a candidate has the wrong user/pass -Add support for delayed setting of the remote candidates in google mode -Better connectivity support and race condition fixes -Keepalive connchecks do not change the state if they fail but data was still received -Fix foundation generation for remote peer reflexive candidates -Drop packets when using TCP and the bandwidth is too slow for the data output - - -libnice 0.0.6 (2009-03-31) -=========================== - -Fix connectivity checks for detecting when we loose the connection -Fix a race condition with gtalk that made the call silent after 30 seconds -Robustness checks with regards to relay information -Fix a race condition crash with retransmission ticks -Added a new STUN API : stun_agent_forget_transaction -Fix a possible crash if tcp-turn is shutdown early in the process -Fix a crash when a stream is removed -Fix MSN support by disable keepalive connchecks - - -libnice 0.0.5 (2009-03-04) -=========================== - -Name change from nice to libnice -Added support for HTTP proxies -Added a nice_interfaces API to query the local interfaces/ips -Fixed libnice when used in dribble mode -Fix a data corruption issue with the SHA1 algorithm -Endianness gets checked at runtime so libnice should compile and work everywhere -Add compatiblity for WLM2009 ICE -Export libstun API and add documentation for libstun -Add connectivity checks during the connection to detect when the peer gets disconnected -Bug fixes and code cleaning - - -nice 0.0.4 (2008-12-17) -======================== - -Fix compilation for 64bits systems -Revert the use of netbuffer in the gstreamer elements -Added support for pseudossl-tcp TURN relay for Google -Added support for SOCKS5 proxy servers for TCP relaying -Bug fixes and code cleaning - -nice 0.0.3 (2008-11-25) -======================== - -Stable google talk support -Added TCP TURN relay support for google. -Removed openssl dependency. - -nice 0.0.2 (2008-11-12) -======================== - -Better support for google talk compatibility mode as well as UDP TURN relay compatibility for Google. -Removed -Werror compile flag for releases - -nice 0.0.1 (2008-11-05) -======================== - -Initial release of libnice. -It has compatibility support for the latest ICE draft 19, as well as google talk and MSN compatibility. -It also has support for TURN relays using TURN draft 9 if you're in ICE draft 19 compatibility, or specific Google/MSN relay support if you're in Google/MSN compatibility mode. -The library is multiplatform and should compile fine on Linux, Mac and Windows systems. diff --git a/README b/README deleted file mode 100644 index b42d730..0000000 --- a/README +++ /dev/null @@ -1,71 +0,0 @@ - -Nice: GLib ICE library -====================== - -Copyright ---------- - - (C) 2006-2020 Collabora Ltd. - (C) 2006-2011 Nokia Corporation - -License -------- - -See the file COPYING. - -Requirements ------------- - - glib >= 2.54 - pkg-config - gnutls >= 2.12.0 or OpenSSL - gupnp-igd >= 0.1.2 (optional) - gstreamer-0.10 >= 0.10.0 (optional) - gstreamer-1.0 (optional) - -Build instructions ------------------- - -To build, you need Python 3 and Meson. Then need to do: - meson build && ninja -C build && sudo ninja -C build install - -Structure ---------- - - agent/ - ICE agent - docs/ - Design and API documentation - gst/ - Gstreamer elements - nice/ - libnice library - random/ - random number generation - socket/ - Socket abstraction layer - stun/ - STUN implementation - tests/ - Unit tests - -Relevant standards ------------------- - -These standards are relevant to nice's current implementation. - -ICE - http://tools.ietf.org/html/rfc5245 (old) - http://tools.ietf.org/html/rfc8445 -STUN - http://tools.ietf.org/html/rfc3489 (old) - http://tools.ietf.org/html/rfc5389 -TURN - http://tools.ietf.org/html/rfc5766 -RTP - http://tools.ietf.org/html/rfc3550 -ICE-TCP RFC - http://tools.ietf.org/html/rfc6544 -Trickle ICE - https://tools.ietf.org/html/draft-ietf-ice-trickle-21 -XMPP Jingle ICE transport - http://www.xmpp.org/extensions/xep-0176.html - -In future, nice may additionally support the following standards. - -NAT-PMP - http://files.dns-sd.org/draft-cheshire-nat-pmp.txt - - diff --git a/TODO b/TODO deleted file mode 100644 index ca9cac4..0000000 --- a/TODO +++ /dev/null @@ -1,14 +0,0 @@ -- High priority: -Refactor/cleanup conncheck.c and discovery.c -Add a nice_agent_create_source() -Implement SIP-style forking -nice_socket_recv returns -1 means we must close the nice_socket and stop all connchecks/candidates and reelect if was eleected... -Bytestream mode (non packetized) for standard ICE-TCP -Standard (RFC 6062) TURN-TCP -Server reflexive candidates for ICE-TCP (aka STUN TCP) -Clear unused local sockets (freeing file descriptions in the process) on READY -TCP simultaneous-open (S-O) - -- Low priority: -Add HTTP Digest support -check for the cookie and act accordingly for incoming messages. diff --git a/agent/Makefile.am b/agent/Makefile.am deleted file mode 100644 index 118520f..0000000 --- a/agent/Makefile.am +++ /dev/null @@ -1,135 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2006, 2007 Collabora Ltd. -# (C) 2006, 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. - -include $(top_srcdir)/common.mk - -AM_CFLAGS = \ - -DG_LOG_DOMAIN=\"libnice\" \ - $(LIBNICE_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(GUPNP_CFLAGS) \ - -I $(top_srcdir) \ - -I $(top_srcdir)/random \ - -I $(top_srcdir)/socket \ - -I $(top_srcdir)/stun - -if WINDOWS - AM_CFLAGS += -DWINVER=0x0501 # _WIN32_WINNT_WINXP -endif - -BUILT_SOURCES = \ - agent-enum-types.h \ - agent-enum-types.c - -CLEANFILES += $(BUILT_SOURCES) - -noinst_LTLIBRARIES = libagent.la - -pkginclude_HEADERS = \ - agent.h \ - candidate.h \ - debug.h \ - address.h \ - interfaces.h \ - pseudotcp.h \ - $(NULL) - -libagent_la_SOURCES = \ - address.h \ - address.c \ - debug.h \ - debug.c \ - candidate.h \ - candidate.c \ - component.h \ - component.c \ - agent.h \ - agent-priv.h \ - agent.c \ - stream.h \ - stream.c \ - conncheck.c \ - conncheck.h \ - discovery.c \ - discovery.h \ - interfaces.c \ - interfaces.h \ - pseudotcp.h \ - pseudotcp.c \ - iostream.h \ - iostream.c \ - inputstream.h \ - inputstream.c \ - outputstream.h \ - outputstream.c \ - $(BUILT_SOURCES) - -agent-enum-types.h: $(pkginclude_HEADERS) Makefile - $(AM_V_GEN)$(GLIB_MKENUMS) \ - --fhead "#ifndef __AGENT_ENUM_TYPES_H__\n#define __AGENT_ENUM_TYPES_H__ 1\n\n#include \n\nG_BEGIN_DECLS\n" \ - --fprod "/* enumerations from \"@filename@\" */\n" \ - --vhead "GType @enum_name@_get_type (void) G_GNUC_CONST;\n#define NICE_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \ - --ftail "G_END_DECLS\n\n#endif /* !AGENT_ENUM_TYPES_H */" \ - $(addprefix $(srcdir)/,$(pkginclude_HEADERS)) > $@ - -agent-enum-types.c: $(pkginclude_HEADERS) Makefile agent-enum-types.h - $(AM_V_GEN)$(GLIB_MKENUMS) \ - --fhead "#include \n#include \n#include \"agent.h\"\n#include \"pseudotcp.h\"\n#include \"agent-enum-types.h\"" \ - --fprod "\n/* enumerations from \"@filename@\" */" \ - --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType type = 0;\n if (!type) {\n static const G@Type@Value values[] = {" \ - --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ - --vtail " { 0, NULL, NULL }\n };\n type = g_@type@_register_static (\"@EnumName@\", values);\n }\n return type;\n}\n\n" \ - $(addprefix $(srcdir)/,$(pkginclude_HEADERS)) > $@ - -libagent_la_LIBADD = \ - $(top_builddir)/random/libnice-random.la \ - $(top_builddir)/socket/libsocket.la \ - $(top_builddir)/stun/libstun.la \ - $(GLIB_LIBS) \ - $(GUPNP_LIBS) \ - $(NULL) -libagent_la_DEPENDENCIES = \ - $(top_builddir)/random/libnice-random.la \ - $(top_builddir)/socket/libsocket.la \ - $(top_builddir)/stun/libstun.la - -if WINDOWS - libagent_la_LIBADD += -liphlpapi -lws2_32 -endif - -# -# GObject introspection -# -# We need --accept-unprefixed because of PseudoTcp and TurnServer. -# --include $(INTROSPECTION_MAKEFILE) -INTROSPECTION_GIRS = -INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) --warn-all --accept-unprefixed -INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) - -if HAVE_INTROSPECTION -introspection_sources = $(pkginclude_HEADERS) - -Nice-0.1.gir: libagent.la -Nice_0_1_gir_INCLUDES = GObject-2.0 Gio-2.0 -Nice_0_1_gir_EXPORT_PACKAGES = nice -Nice_0_1_gir_CFLAGS = $(AM_CFLAGS) -Nice_0_1_gir_LIBS = libagent.la -Nice_0_1_gir_FILES = $(introspection_sources) -INTROSPECTION_GIRS += Nice-0.1.gir - -girdir = $(datadir)/gir-1.0 -gir_DATA = $(INTROSPECTION_GIRS) - -typelibdir = $(libdir)/girepository-1.0 -typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) - -CLEANFILES += $(gir_DATA) $(typelib_DATA) -endif - -EXTRA_DIST = meson.build diff --git a/agent/address.c b/agent/address.c deleted file mode 100644 index 8508c6f..0000000 --- a/agent/address.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -#define NICEAPI_EXPORT -#endif - -#include - -#ifdef HAVE_NETDB_H -#include -#endif - -#include "address.h" - -#ifdef G_OS_WIN32 -#define inet_ntop inet_ntop_win32 - -/* Defined in recent versions of mingw: - * https://github.com/mirror/mingw-w64/commit/0f4899473c4ba2e34fa447b1931a04e38c1f105e - */ -#ifndef IN6_ARE_ADDR_EQUAL -#define IN6_ARE_ADDR_EQUAL(a, b) \ - (memcmp ((const void *) (a), (const void *) (b), sizeof (struct in6_addr)) == 0) -#endif - - -static const char * -inet_ntop_win32 (int af, const void *src, char *dst, socklen_t cnt) -{ - if (af == AF_INET) { - struct sockaddr_in in; - memset(&in, 0, sizeof(in)); - in.sin_family = AF_INET; - memcpy(&in.sin_addr, src, sizeof(struct in_addr)); - getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), - dst, cnt, NULL, 0, NI_NUMERICHOST); - return dst; - } else if (af == AF_INET6) { - struct sockaddr_in6 in; - memset(&in, 0, sizeof(in)); - in.sin6_family = AF_INET6; - memcpy(&in.sin6_addr, src, sizeof(struct in_addr6)); - getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), - dst, cnt, NULL, 0, NI_NUMERICHOST); - return dst; - } - return NULL; -} - -#endif - - - -NICEAPI_EXPORT void -nice_address_init (NiceAddress *addr) -{ - addr->s.addr.sa_family = AF_UNSPEC; - memset (&addr->s, 0, sizeof(addr->s)); -} - -NICEAPI_EXPORT NiceAddress * -nice_address_new (void) -{ - NiceAddress *addr = g_slice_new0 (NiceAddress); - nice_address_init (addr); - return addr; -} - - -NICEAPI_EXPORT void -nice_address_set_ipv4 (NiceAddress *addr, guint32 addr_ipv4) -{ - addr->s.ip4.sin_family = AF_INET; -#ifdef HAVE_SA_LEN - addr->s.ip4.sin_len = sizeof (addr->sa.ip4); -#endif - addr->s.ip4.sin_addr.s_addr = addr_ipv4 ? htonl (addr_ipv4) : INADDR_ANY; - addr->s.ip4.sin_port = 0; -} - - -NICEAPI_EXPORT void -nice_address_set_ipv6 (NiceAddress *addr, const guchar *addr_ipv6) -{ - addr->s.ip6.sin6_family = AF_INET6; -#ifdef HAVE_SA_LEN - addr->s.ip6.sin6_len = sizeof (addr->sa.ip6); -#endif - memcpy (addr->s.ip6.sin6_addr.s6_addr, addr_ipv6, 16); - addr->s.ip6.sin6_port = 0; - addr->s.ip6.sin6_scope_id = 0; -} - - -NICEAPI_EXPORT void -nice_address_set_port (NiceAddress *addr, guint port) -{ - g_assert (addr); - - switch (addr->s.addr.sa_family) - { - case AF_INET: - addr->s.ip4.sin_port = htons (port); - break; - case AF_INET6: - addr->s.ip6.sin6_port = htons (port); - break; - default: - g_return_if_reached (); - } -} - - -guint -nice_address_get_port (const NiceAddress *addr) -{ - if (!addr) - return 0; - - switch (addr->s.addr.sa_family) - { - case AF_INET: - return ntohs (addr->s.ip4.sin_port); - case AF_INET6: - return ntohs (addr->s.ip6.sin6_port); - default: - g_return_val_if_reached (0); - } -} - - -NICEAPI_EXPORT gboolean -nice_address_set_from_string (NiceAddress *addr, const gchar *str) -{ - struct addrinfo hints; - struct addrinfo *res; - - memset (&hints, 0, sizeof (hints)); - - /* AI_NUMERICHOST prevents getaddrinfo() from doing DNS resolution. */ - hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_NUMERICHOST; - - if (getaddrinfo (str, NULL, &hints, &res) != 0) - return FALSE; /* invalid address */ - - nice_address_set_from_sockaddr (addr, res->ai_addr); - - freeaddrinfo (res); - - return TRUE; -} - - -NICEAPI_EXPORT void -nice_address_set_from_sockaddr (NiceAddress *addr, - const struct sockaddr *sa) -{ - switch (sa->sa_family) - { - case AF_INET: - memcpy(&addr->s.ip4, sa, sizeof (addr->s.ip4)); - break; - case AF_INET6: - memcpy(&addr->s.ip6, sa, sizeof (addr->s.ip6)); - break; - default: - g_return_if_reached (); - } -} - - -NICEAPI_EXPORT void -nice_address_copy_to_sockaddr (const NiceAddress *addr, - struct sockaddr *_sa) -{ - union { - struct sockaddr *addr; - struct sockaddr_in *in; - struct sockaddr_in6 *in6; - } sa; - - sa.addr = _sa; - - g_assert (_sa); - - switch (addr->s.addr.sa_family) - { - case AF_INET: - memcpy (sa.in, &addr->s.ip4, sizeof (*sa.in)); - break; - case AF_INET6: - memcpy (sa.in6, &addr->s.ip6, sizeof (*sa.in6)); - break; - default: - g_return_if_reached (); - } -} - -NICEAPI_EXPORT void -nice_address_to_string (const NiceAddress *addr, gchar *dst) -{ - switch (addr->s.addr.sa_family) { - case AF_INET: - inet_ntop (AF_INET, &addr->s.ip4.sin_addr, dst, INET_ADDRSTRLEN); - break; - case AF_INET6: - inet_ntop (AF_INET6, &addr->s.ip6.sin6_addr, dst, INET6_ADDRSTRLEN); - break; - default: - g_return_if_reached (); - } -} - - -NICEAPI_EXPORT gboolean -nice_address_equal (const NiceAddress *a, const NiceAddress *b) -{ - if (a->s.addr.sa_family != b->s.addr.sa_family) - return FALSE; - - switch (a->s.addr.sa_family) - { - case AF_INET: - return (a->s.ip4.sin_addr.s_addr == b->s.ip4.sin_addr.s_addr) - && (a->s.ip4.sin_port == b->s.ip4.sin_port); - - case AF_INET6: - return IN6_ARE_ADDR_EQUAL (&a->s.ip6.sin6_addr, &b->s.ip6.sin6_addr) - && (a->s.ip6.sin6_port == b->s.ip6.sin6_port) - && (a->s.ip6.sin6_scope_id == 0 || b->s.ip6.sin6_scope_id == 0 || - (a->s.ip6.sin6_scope_id == b->s.ip6.sin6_scope_id)); - - default: - g_return_val_if_reached (FALSE); - } -} - - -NICEAPI_EXPORT NiceAddress * -nice_address_dup (const NiceAddress *a) -{ - NiceAddress *dup = g_slice_new0 (NiceAddress); - - *dup = *a; - return dup; -} - - -NICEAPI_EXPORT void -nice_address_free (NiceAddress *addr) -{ - g_slice_free (NiceAddress, addr); -} - - -/* "private" in the sense of "not routable on the Internet" */ -static gboolean -ipv4_address_is_private (guint32 addr) -{ - addr = ntohl (addr); - - /* http://tools.ietf.org/html/rfc3330 - * https://tools.ietf.org/html/rfc3927 - */ - return ( - /* 10.0.0.0/8 */ - ((addr & 0xff000000) == 0x0a000000) || - /* 172.16.0.0 - 172.31.255.255 = 172.16.0.0/12 */ - ((addr & 0xfff00000) == 0xac100000) || - /* 192.168.0.0/16 */ - ((addr & 0xffff0000) == 0xc0a80000) || - /* 169.254.x.x/16 (for APIPA) */ - ((addr & 0xffff0000) == 0xa9fe0000) || - /* 127.0.0.0/8 */ - ((addr & 0xff000000) == 0x7f000000)); -} - - -static gboolean -ipv6_address_is_private (const guchar *addr) -{ - return ( - /* fe80::/10 (link local addresses, needs scope) */ - ((addr[0] == 0xfe) && ((addr[1] & 0xc0) == 0x80)) || - /* fd00::/8 (official private IP block) */ - (addr[0] == 0xfd) || - /* fc00::/7 (those are ULA) */ - ((addr[0] & 0xfe) == 0xfc) || - /* ::1 loopback */ - ((memcmp (addr, "\x00\x00\x00\x00" - "\x00\x00\x00\x00" - "\x00\x00\x00\x00" - "\x00\x00\x00\x01", 16) == 0))); -} - - -NICEAPI_EXPORT gboolean -nice_address_is_private (const NiceAddress *a) -{ - switch (a->s.addr.sa_family) - { - case AF_INET: - return ipv4_address_is_private (a->s.ip4.sin_addr.s_addr); - case AF_INET6: - return ipv6_address_is_private (a->s.ip6.sin6_addr.s6_addr); - default: - g_return_val_if_reached (FALSE); - } -} - - -NICEAPI_EXPORT gboolean -nice_address_is_valid (const NiceAddress *a) -{ - switch (a->s.addr.sa_family) - { - case AF_INET: - case AF_INET6: - return TRUE; - default: - return FALSE; - } -} - -NICEAPI_EXPORT int -nice_address_ip_version (const NiceAddress *addr) -{ - switch (addr->s.addr.sa_family) - { - case AF_INET: - return 4; - case AF_INET6: - return 6; - default: - return 0; - } -} - -NICEAPI_EXPORT gboolean -nice_address_equal_no_port (const NiceAddress *a, const NiceAddress *b) -{ - if (a->s.addr.sa_family != b->s.addr.sa_family) - return FALSE; - - switch (a->s.addr.sa_family) - { - case AF_INET: - return (a->s.ip4.sin_addr.s_addr == b->s.ip4.sin_addr.s_addr); - - case AF_INET6: - return IN6_ARE_ADDR_EQUAL (&a->s.ip6.sin6_addr, &b->s.ip6.sin6_addr) - && (a->s.ip6.sin6_scope_id == 0 || b->s.ip6.sin6_scope_id == 0 || - (a->s.ip6.sin6_scope_id == b->s.ip6.sin6_scope_id)); - - default: - g_return_val_if_reached (FALSE); - } -} diff --git a/agent/address.h b/agent/address.h deleted file mode 100644 index fa555b2..0000000 --- a/agent/address.h +++ /dev/null @@ -1,307 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Dafydd Harries, Collabora Ltd. - * Kai Vehmanen - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef __LIBNICE_ADDRESS_H__ -#define __LIBNICE_ADDRESS_H__ - -/** - * SECTION:address - * @short_description: IP address convenience library - * @stability: Stable - * - * The #NiceAddress structure will allow you to easily set/get and modify an IPv4 - * or IPv6 address in order to communicate with the #NiceAgent. - */ - - -#include - -#ifdef G_OS_WIN32 -#include -#include -#else -#include -#include -#include -#include -#endif - -G_BEGIN_DECLS - - -/** - * NiceAddress: - * - * The #NiceAddress structure that represents an IPv4 or IPv6 address. - */ -struct _NiceAddress -{ - union - { - struct sockaddr addr; - struct sockaddr_in ip4; - struct sockaddr_in6 ip6; - } s; -}; - - -/** - * NICE_ADDRESS_STRING_LEN: - * - * The maximum string length representation of an address. - * When using nice_address_to_string() make sure the string has a size of - * at least %NICE_ADDRESS_STRING_LEN - */ -#define NICE_ADDRESS_STRING_LEN INET6_ADDRSTRLEN - -typedef struct _NiceAddress NiceAddress; - - -/** - * nice_address_init: - * @addr: The #NiceAddress to init - * - * Initialize a #NiceAddress into an undefined address - */ -void -nice_address_init (NiceAddress *addr); - -/** - * nice_address_new: - * - * Create a new #NiceAddress with undefined address - * You must free it with nice_address_free() - * - * Returns: The new #NiceAddress - */ -NiceAddress * -nice_address_new (void); - -/** - * nice_address_free: - * @addr: The #NiceAddress to free - * - * Frees a #NiceAddress created with nice_address_new() or nice_address_dup() - */ -void -nice_address_free (NiceAddress *addr); - -/** - * nice_address_dup: - * @addr: The #NiceAddress to dup - * - * Creates a new #NiceAddress with the same address as @addr - * - * Returns: The new #NiceAddress - */ -NiceAddress * -nice_address_dup (const NiceAddress *addr); - - -/** - * nice_address_set_ipv4: - * @addr: The #NiceAddress to modify - * @addr_ipv4: The IPv4 address - * - * Set @addr to an IPv4 address using the data from @addr_ipv4 - * - - - This function will reset the port to 0, so make sure you call it before - nice_address_set_port() - - - */ -void -nice_address_set_ipv4 (NiceAddress *addr, guint32 addr_ipv4); - - -/** - * nice_address_set_ipv6: - * @addr: The #NiceAddress to modify - * @addr_ipv6: The IPv6 address - * - * Set @addr to an IPv6 address using the data from @addr_ipv6 - * - - - This function will reset the port to 0, so make sure you call it before - nice_address_set_port() - - - */ -void -nice_address_set_ipv6 (NiceAddress *addr, const guchar *addr_ipv6); - - -/** - * nice_address_set_port: - * @addr: The #NiceAddress to modify - * @port: The port to set - * - * Set the port of @addr to @port - */ -void -nice_address_set_port (NiceAddress *addr, guint port); - -/** - * nice_address_get_port: - * @addr: The #NiceAddress to query - * - * Retreive the port of @addr - * - * Returns: The port of @addr - */ -guint -nice_address_get_port (const NiceAddress *addr); - -/** - * nice_address_set_from_string: - * @addr: The #NiceAddress to modify - * @str: The string to set - * - * Sets an IPv4 or IPv6 address from the string @str - * - * Returns: %TRUE if success, %FALSE on error - */ -gboolean -nice_address_set_from_string (NiceAddress *addr, const gchar *str); - -/** - * nice_address_set_from_sockaddr: - * @addr: The #NiceAddress to modify - * @sin: The sockaddr to set - * - * Sets an IPv4 or IPv6 address from the sockaddr structure @sin - * - */ -void -nice_address_set_from_sockaddr (NiceAddress *addr, const struct sockaddr *sin); - - -/** - * nice_address_copy_to_sockaddr: - * @addr: The #NiceAddress to query - * @sin: The sockaddr to fill - * - * Fills the sockaddr structure @sin with the address contained in @addr - * - */ -void -nice_address_copy_to_sockaddr (const NiceAddress *addr, struct sockaddr *sin); - -/** - * nice_address_equal: - * @a: First #NiceAddress to compare - * @b: Second #NiceAddress to compare - * - * Compares two #NiceAddress structures to see if they contain the same address - * and the same port. - * - * Returns: %TRUE if @a and @b are the same address, %FALSE if they are different - */ -gboolean -nice_address_equal (const NiceAddress *a, const NiceAddress *b); - -/** - * nice_address_equal_no_port: - * @a: First #NiceAddress to compare - * @b: Second #NiceAddress to compare - * - * Compares two #NiceAddress structures to see if they contain the same address, - * ignoring the port. - * - * Returns: %TRUE if @a and @b are the same address, %FALSE if they - * are different - * - * Since: 0.1.8 - */ -gboolean -nice_address_equal_no_port (const NiceAddress *a, const NiceAddress *b); - -/** - * nice_address_to_string: - * @addr: The #NiceAddress to query - * @dst: The string to fill - * - * Transforms the address @addr into a human readable string - * - */ -void -nice_address_to_string (const NiceAddress *addr, gchar *dst); - -/** - * nice_address_is_private: - * @addr: The #NiceAddress to query - * - * Verifies if the address in @addr is a private address or not - * - * Returns: %TRUE if @addr is a private address, %FALSE otherwise - */ -gboolean -nice_address_is_private (const NiceAddress *addr); - -/** - * nice_address_is_valid: - * @addr: The #NiceAddress to query - * - * Validate whether the #NiceAddress @addr is a valid IPv4 or IPv6 address - * - * Returns: %TRUE if @addr is valid, %FALSE otherwise - */ -G_GNUC_WARN_UNUSED_RESULT -gboolean -nice_address_is_valid (const NiceAddress *addr); - -/** - * nice_address_ip_version: - * @addr: The #NiceAddress to query - * - * Returns the IP version of the address - * - * Returns: 4 for IPv4, 6 for IPv6 and 0 for undefined address - */ -G_GNUC_WARN_UNUSED_RESULT -int -nice_address_ip_version (const NiceAddress *addr); - -G_END_DECLS - -#endif /* __LIBNICE_ADDRESS_H__ */ - diff --git a/agent/agent-priv.h b/agent/agent-priv.h deleted file mode 100644 index d6c488c..0000000 --- a/agent/agent-priv.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _NICE_AGENT_PRIV_H -#define _NICE_AGENT_PRIV_H - -/* note: this is a private header part of agent.h */ - - -#ifdef HAVE_CONFIG_H -# include -#else -#define NICEAPI_EXPORT -#endif - -#include - -#include "agent.h" - -/** - * NiceInputMessageIter: - * @message: index of the message currently being written into - * @buffer: index of the buffer currently being written into - * @offset: byte offset into the buffer - * - * Iterator for sequentially writing into an array of #NiceInputMessages, - * tracking the current write position (i.e. the index of the next byte to be - * written). - * - * If @message is equal to the number of messages in the associated - * #NiceInputMessage array, and @buffer and @offset are zero, the iterator is at - * the end of the messages array, and the array is (presumably) full. - * - * Since: 0.1.5 - */ -typedef struct { - guint message; - guint buffer; - gsize offset; -} NiceInputMessageIter; - -void -nice_input_message_iter_reset (NiceInputMessageIter *iter); -gboolean -nice_input_message_iter_is_at_end (NiceInputMessageIter *iter, - NiceInputMessage *messages, guint n_messages); -guint -nice_input_message_iter_get_n_valid_messages (NiceInputMessageIter *iter); -gboolean -nice_input_message_iter_compare (const NiceInputMessageIter *a, - const NiceInputMessageIter *b); - - -#include "socket.h" -#include "candidate.h" -#include "stream.h" -#include "conncheck.h" -#include "component.h" -#include "random.h" -#include "stun/stunagent.h" -#include "stun/usages/turn.h" -#include "stun/usages/ice.h" - -#ifdef HAVE_GUPNP -#include -#endif - -/* XXX: starting from ICE ID-18, Ta SHOULD now be set according - * to session bandwidth -> this is not yet implemented in NICE */ - -#define NICE_AGENT_TIMER_TA_DEFAULT 20 /* timer Ta, msecs (impl. defined) */ -#define NICE_AGENT_TIMER_TR_DEFAULT 25000 /* timer Tr, msecs (impl. defined) */ -#define NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT 100 /* see RFC 8445 6.1.2.5 */ - - -/* An upper limit to size of STUN packets handled (based on Ethernet - * MTU and estimated typical sizes of ICE STUN packet */ -#define MAX_STUN_DATAGRAM_PAYLOAD 1300 - -#define NICE_COMPONENT_MAX_VALID_CANDIDATES 50 /* maximum number of validates remote candidates to keep, the number is arbitrary but hopefully large enough */ - -/* A convenient macro to test if the agent is compatible with RFC5245 - * or OC2007R2. Specifically these two modes share the support - * of the regular or aggressive nomination mode */ -#define NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2(obj) \ - ((obj)->compatibility == NICE_COMPATIBILITY_RFC5245 || \ - (obj)->compatibility == NICE_COMPATIBILITY_OC2007R2) - -struct _NiceAgent -{ - GObject parent; /* gobject pointer */ - - GMutex agent_mutex; /* Mutex used for thread-safe lib */ - - gboolean full_mode; /* property: full-mode */ - gchar *stun_server_ip; /* property: STUN server IP */ - guint stun_server_port; /* property: STUN server port */ - gchar *proxy_ip; /* property: Proxy server IP */ - guint proxy_port; /* property: Proxy server port */ - NiceProxyType proxy_type; /* property: Proxy type */ - gchar *proxy_username; /* property: Proxy username */ - gchar *proxy_password; /* property: Proxy password */ - gboolean saved_controlling_mode;/* property: controlling-mode */ - guint timer_ta; /* property: timer Ta */ - guint max_conn_checks; /* property: max connectivity checks */ - gboolean force_relay; /* property: force relay */ - guint stun_max_retransmissions; /* property: stun max retransmissions, Rc */ - guint stun_initial_timeout; /* property: stun initial timeout, RTO */ - guint stun_reliable_timeout; /* property: stun reliable timeout */ - NiceNominationMode nomination_mode; /* property: Nomination mode */ - gboolean support_renomination; /* property: support RENOMINATION STUN attribute */ - guint idle_timeout; /* property: conncheck timeout before stop */ - - GSList *local_addresses; /* list of NiceAddresses for local - interfaces */ - GSList *streams; /* list of Stream objects */ - GSList *pruning_streams; /* list of Streams current being shut down */ - GMainContext *main_context; /* main context pointer */ - guint next_candidate_id; /* id of next created candidate */ - guint next_stream_id; /* id of next created candidate */ - NiceRNG *rng; /* random number generator */ - GSList *discovery_list; /* list of CandidateDiscovery items */ - GSList *triggered_check_queue; /* pairs in the triggered check list */ - guint discovery_unsched_items; /* number of discovery items unscheduled */ - GSource *discovery_timer_source; /* source of discovery timer */ - GSource *conncheck_timer_source; /* source of conncheck timer */ - GSource *keepalive_timer_source; /* source of keepalive timer */ - GSList *refresh_list; /* list of CandidateRefresh items */ - guint64 tie_breaker; /* tie breaker (ICE sect 5.2 - "Determining Role" ID-19) */ - NiceCompatibility compatibility; /* property: Compatibility mode */ - gboolean media_after_tick; /* Received media after keepalive tick */ -#ifdef HAVE_GUPNP - GUPnPSimpleIgdThread* upnp; /* GUPnP Single IGD agent */ - gboolean upnp_enabled; /* whether UPnP discovery is enabled */ - guint upnp_timeout; /* UPnP discovery timeout */ - GSList *upnp_mapping; /* NiceAddresses of cands being mapped */ - GSource *upnp_timer_source; /* source of upnp timeout timer */ -#endif - gchar *software_attribute; /* SOFTWARE attribute */ - gboolean reliable; /* property: reliable */ - gboolean keepalive_conncheck; /* property: keepalive_conncheck */ - - GQueue pending_signals; - guint16 rfc4571_expecting_length; - gboolean use_ice_udp; - gboolean use_ice_tcp; - gboolean use_ice_trickle; - - guint conncheck_ongoing_idle_delay; /* ongoing delay before timer stop */ - gboolean controlling_mode; /* controlling mode used by the - conncheck */ - /* XXX: add pointer to internal data struct for ABI-safe extensions */ -}; - -gboolean -agent_find_component ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceStream **stream, - NiceComponent **component) G_GNUC_WARN_UNUSED_RESULT; - -NiceStream *agent_find_stream (NiceAgent *agent, guint stream_id); - -void agent_gathering_done (NiceAgent *agent); -void agent_signal_gathering_done (NiceAgent *agent); - -void agent_lock (NiceAgent *agent); -void agent_unlock (NiceAgent *agent); -void agent_unlock_and_emit (NiceAgent *agent); - -void agent_signal_new_selected_pair ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceCandidate *lcandidate, - NiceCandidate *rcandidate); - -void agent_signal_component_state_change ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceComponentState state); - -void agent_signal_new_candidate ( - NiceAgent *agent, - NiceCandidate *candidate); - -void agent_signal_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate); - -void agent_signal_initial_binding_request_received (NiceAgent *agent, NiceStream *stream); - -guint64 agent_candidate_pair_priority (NiceAgent *agent, NiceCandidate *local, NiceCandidate *remote); - -NiceSocket * agent_create_tcp_turn_socket (NiceAgent *agent, - NiceStream *stream, NiceComponent *component, NiceSocket *nicesock, - NiceAddress *server, NiceRelayType type, gboolean reliable_tcp); - -typedef gboolean (*NiceTimeoutLockedCallback)(NiceAgent *agent, - gpointer user_data); -void agent_timeout_add_with_context (NiceAgent *agent, GSource **out, - const gchar *name, guint interval, NiceTimeoutLockedCallback function, - gpointer data); -void agent_timeout_add_seconds_with_context (NiceAgent *agent, GSource **out, - const gchar *name, guint interval, NiceTimeoutLockedCallback function, - gpointer data); - -StunUsageIceCompatibility agent_to_ice_compatibility (NiceAgent *agent); -StunUsageTurnCompatibility agent_to_turn_compatibility (NiceAgent *agent); -NiceTurnSocketCompatibility agent_to_turn_socket_compatibility (NiceAgent *agent); - -void agent_remove_local_candidate (NiceAgent *agent, - NiceCandidate *candidate); - -void nice_agent_init_stun_agent (NiceAgent *agent, StunAgent *stun_agent); - -void _priv_set_socket_tos (NiceAgent *agent, NiceSocket *sock, gint tos); - -void _tcp_sock_is_writable (NiceSocket *sock, gpointer user_data); - -gboolean -component_io_cb ( - GSocket *gsocket, - GIOCondition condition, - gpointer data); - -gsize -memcpy_buffer_to_input_message (NiceInputMessage *message, - const guint8 *buffer, gsize buffer_length); -guint8 * -compact_input_message (const NiceInputMessage *message, gsize *buffer_length); - -guint8 * -compact_output_message (const NiceOutputMessage *message, gsize *buffer_length); - -gsize -output_message_get_size (const NiceOutputMessage *message); - -gsize -input_message_get_size (const NiceInputMessage *message); - -gssize agent_socket_send (NiceSocket *sock, const NiceAddress *addr, gsize len, - const gchar *buf); - -guint32 -nice_candidate_jingle_priority (NiceCandidate *candidate); - -guint32 -nice_candidate_msn_priority (NiceCandidate *candidate); - -guint32 -nice_candidate_ice_priority_full (guint type_pref, guint local_pref, - guint component_id); - -guint32 -nice_candidate_ice_priority (const NiceCandidate *candidate, - gboolean reliable, gboolean nat_assisted); - -guint32 -nice_candidate_ms_ice_priority (const NiceCandidate *candidate, - gboolean reliable, gboolean nat_assisted); - -guint64 -nice_candidate_pair_priority (guint32 o_prio, guint32 a_prio); - -#define NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE 32 - -void -nice_candidate_pair_priority_to_string (guint64 prio, gchar *string); - -/* - * nice_debug_init: - * - * Initialize the debugging system. Uses the NICE_DEBUG environment variable - * to set the appropriate debugging flags - */ -void nice_debug_init (void); - - -#ifdef NDEBUG -static inline gboolean nice_debug_is_enabled (void) { return FALSE; } -static inline gboolean nice_debug_is_verbose (void) { return FALSE; } -static inline void nice_debug (const char *fmt, ...) { } -static inline void nice_debug_verbose (const char *fmt, ...) { } -#else -gboolean nice_debug_is_enabled (void); -gboolean nice_debug_is_verbose (void); -void nice_debug (const char *fmt, ...) G_GNUC_PRINTF (1, 2); -void nice_debug_verbose (const char *fmt, ...) G_GNUC_PRINTF (1, 2); -#endif - -#if !GLIB_CHECK_VERSION(2, 59, 0) -#if __GNUC__ > 6 -#define G_GNUC_FALLTHROUGH __attribute__((fallthrough)) -#else -#define G_GNUC_FALLTHROUGH -#endif /* __GNUC__ */ -#endif - -#endif /*_NICE_AGENT_PRIV_H */ diff --git a/agent/agent.c b/agent/agent.c deleted file mode 100644 index 7bbf74a..0000000 --- a/agent/agent.c +++ /dev/null @@ -1,6954 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2010, 2013 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2010 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - - -#ifdef HAVE_CONFIG_H -# include -#else -#define NICEAPI_EXPORT -#endif - -#include -#include - -#include -#include - -#ifndef G_OS_WIN32 -#include -#include -#include -#endif - -#include "debug.h" - -#include "socket.h" -#include "stun/usages/turn.h" -#include "candidate.h" -#include "component.h" -#include "conncheck.h" -#include "discovery.h" -#include "agent.h" -#include "agent-priv.h" -#include "iostream.h" - -#include "stream.h" -#include "interfaces.h" - -#include "pseudotcp.h" -#include "agent-enum-types.h" - -/* Maximum size of a UDP packet’s payload, as the packet’s length field is 16b - * wide. */ -#define MAX_BUFFER_SIZE ((1 << 16) - 1) /* 65535 */ - -#define DEFAULT_STUN_PORT 3478 -#define DEFAULT_UPNP_TIMEOUT 200 /* milliseconds */ -#define DEFAULT_IDLE_TIMEOUT 5000 /* milliseconds */ - -#define MAX_TCP_MTU 1400 /* Use 1400 because of VPNs and we assume IEE 802.3 */ - - -static void -nice_debug_input_message_composition (const NiceInputMessage *messages, - guint n_messages); -static const gchar *_cand_type_to_sdp (NiceCandidateType type); - -G_DEFINE_TYPE (NiceAgent, nice_agent, G_TYPE_OBJECT); - -enum -{ - PROP_COMPATIBILITY = 1, - PROP_MAIN_CONTEXT, - PROP_STUN_SERVER, - PROP_STUN_SERVER_PORT, - PROP_CONTROLLING_MODE, - PROP_FULL_MODE, - PROP_STUN_PACING_TIMER, - PROP_MAX_CONNECTIVITY_CHECKS, - PROP_PROXY_TYPE, - PROP_PROXY_IP, - PROP_PROXY_PORT, - PROP_PROXY_USERNAME, - PROP_PROXY_PASSWORD, - PROP_UPNP, - PROP_UPNP_TIMEOUT, - PROP_RELIABLE, - PROP_ICE_UDP, - PROP_ICE_TCP, - PROP_BYTESTREAM_TCP, - PROP_KEEPALIVE_CONNCHECK, - PROP_FORCE_RELAY, - PROP_STUN_MAX_RETRANSMISSIONS, - PROP_STUN_INITIAL_TIMEOUT, - PROP_STUN_RELIABLE_TIMEOUT, - PROP_NOMINATION_MODE, - PROP_ICE_TRICKLE, - PROP_SUPPORT_RENOMINATION, - PROP_IDLE_TIMEOUT, -}; - - -enum -{ - SIGNAL_COMPONENT_STATE_CHANGED, - SIGNAL_CANDIDATE_GATHERING_DONE, - SIGNAL_NEW_SELECTED_PAIR, - SIGNAL_NEW_CANDIDATE, - SIGNAL_NEW_REMOTE_CANDIDATE, - SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED, - SIGNAL_RELIABLE_TRANSPORT_WRITABLE, - SIGNAL_STREAMS_REMOVED, - SIGNAL_NEW_SELECTED_PAIR_FULL, - SIGNAL_NEW_CANDIDATE_FULL, - SIGNAL_NEW_REMOTE_CANDIDATE_FULL, - - N_SIGNALS, -}; - -static guint signals[N_SIGNALS]; - -static void priv_stop_upnp (NiceAgent *agent); - -static void pseudo_tcp_socket_opened (PseudoTcpSocket *sock, gpointer user_data); -static void pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data); -static void pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data); -static void pseudo_tcp_socket_closed (PseudoTcpSocket *sock, guint32 err, - gpointer user_data); -static PseudoTcpWriteResult pseudo_tcp_socket_write_packet (PseudoTcpSocket *sock, - const gchar *buffer, guint32 len, gpointer user_data); -static void adjust_tcp_clock (NiceAgent *agent, NiceStream *stream, NiceComponent *component); - -static void nice_agent_dispose (GObject *object); -static void nice_agent_get_property (GObject *object, - guint property_id, GValue *value, GParamSpec *pspec); -static void nice_agent_set_property (GObject *object, - guint property_id, const GValue *value, GParamSpec *pspec); - -void agent_lock (NiceAgent *agent) -{ - g_mutex_lock (&agent->agent_mutex); -} - -void agent_unlock (NiceAgent *agent) -{ - g_mutex_unlock (&agent->agent_mutex); -} - -static GType _nice_agent_stream_ids_get_type (void); - -G_DEFINE_POINTER_TYPE (_NiceAgentStreamIds, _nice_agent_stream_ids); - -#define NICE_TYPE_AGENT_STREAM_IDS _nice_agent_stream_ids_get_type () - -typedef struct { - guint signal_id; - GSignalQuery query; - GValue *params; -} QueuedSignal; - - -static void -free_queued_signal (QueuedSignal *sig) -{ - guint i; - - g_value_unset (&sig->params[0]); - - for (i = 0; i < sig->query.n_params; i++) { - if (G_VALUE_HOLDS(&sig->params[i + 1], NICE_TYPE_AGENT_STREAM_IDS)) - g_free (g_value_get_pointer (&sig->params[i + 1])); - g_value_unset (&sig->params[i + 1]); - } - - g_slice_free1 (sizeof(GValue) * (sig->query.n_params + 1), sig->params); - g_slice_free (QueuedSignal, sig); -} - -void -agent_unlock_and_emit (NiceAgent *agent) -{ - GQueue queue = G_QUEUE_INIT; - QueuedSignal *sig; - - queue = agent->pending_signals; - g_queue_init (&agent->pending_signals); - - agent_unlock (agent); - - while ((sig = g_queue_pop_head (&queue))) { - g_signal_emitv (sig->params, sig->signal_id, 0, NULL); - - free_queued_signal (sig); - } -} - -static void -agent_queue_signal (NiceAgent *agent, guint signal_id, ...) -{ - QueuedSignal *sig; - guint i; - gchar *error = NULL; - va_list var_args; - - sig = g_slice_new (QueuedSignal); - g_signal_query (signal_id, &sig->query); - - sig->signal_id = signal_id; - sig->params = g_slice_alloc0 (sizeof(GValue) * (sig->query.n_params + 1)); - - g_value_init (&sig->params[0], G_TYPE_OBJECT); - g_value_set_object (&sig->params[0], agent); - - va_start (var_args, signal_id); - for (i = 0; i < sig->query.n_params; i++) { - G_VALUE_COLLECT_INIT (&sig->params[i + 1], sig->query.param_types[i], - var_args, 0, &error); - if (error) - break; - } - va_end (var_args); - - if (error) { - free_queued_signal (sig); - g_critical ("Error collecting values for signal: %s", error); - g_free (error); - return; - } - - g_queue_push_tail (&agent->pending_signals, sig); -} - - -StunUsageIceCompatibility -agent_to_ice_compatibility (NiceAgent *agent) -{ - return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ? - STUN_USAGE_ICE_COMPATIBILITY_GOOGLE : - agent->compatibility == NICE_COMPATIBILITY_MSN ? - STUN_USAGE_ICE_COMPATIBILITY_MSN : - agent->compatibility == NICE_COMPATIBILITY_WLM2009 ? - STUN_USAGE_ICE_COMPATIBILITY_MSICE2 : - agent->compatibility == NICE_COMPATIBILITY_OC2007 ? - STUN_USAGE_ICE_COMPATIBILITY_MSN : - agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ? - STUN_USAGE_ICE_COMPATIBILITY_MSICE2 : - STUN_USAGE_ICE_COMPATIBILITY_RFC5245; -} - - -StunUsageTurnCompatibility -agent_to_turn_compatibility (NiceAgent *agent) -{ - return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ? - STUN_USAGE_TURN_COMPATIBILITY_GOOGLE : - agent->compatibility == NICE_COMPATIBILITY_MSN ? - STUN_USAGE_TURN_COMPATIBILITY_MSN : - agent->compatibility == NICE_COMPATIBILITY_WLM2009 ? - STUN_USAGE_TURN_COMPATIBILITY_MSN : - agent->compatibility == NICE_COMPATIBILITY_OC2007 ? - STUN_USAGE_TURN_COMPATIBILITY_OC2007 : - agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ? - STUN_USAGE_TURN_COMPATIBILITY_OC2007 : - STUN_USAGE_TURN_COMPATIBILITY_RFC5766; -} - -NiceTurnSocketCompatibility -agent_to_turn_socket_compatibility (NiceAgent *agent) -{ - return agent->compatibility == NICE_COMPATIBILITY_GOOGLE ? - NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE : - agent->compatibility == NICE_COMPATIBILITY_MSN ? - NICE_TURN_SOCKET_COMPATIBILITY_MSN : - agent->compatibility == NICE_COMPATIBILITY_WLM2009 ? - NICE_TURN_SOCKET_COMPATIBILITY_MSN : - agent->compatibility == NICE_COMPATIBILITY_OC2007 ? - NICE_TURN_SOCKET_COMPATIBILITY_OC2007 : - agent->compatibility == NICE_COMPATIBILITY_OC2007R2 ? - NICE_TURN_SOCKET_COMPATIBILITY_OC2007 : - NICE_TURN_SOCKET_COMPATIBILITY_RFC5766; -} - -NiceStream *agent_find_stream (NiceAgent *agent, guint stream_id) -{ - GSList *i; - - for (i = agent->streams; i; i = i->next) - { - NiceStream *s = i->data; - - if (s->id == stream_id) - return s; - } - - return NULL; -} - - -gboolean -agent_find_component ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceStream **stream, - NiceComponent **component) -{ - NiceStream *s; - NiceComponent *c; - - s = agent_find_stream (agent, stream_id); - - if (s == NULL) - return FALSE; - - c = nice_stream_find_component_by_id (s, component_id); - - if (c == NULL) - return FALSE; - - if (stream) - *stream = s; - - if (component) - *component = c; - - return TRUE; -} - -static void -nice_agent_class_init (NiceAgentClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->get_property = nice_agent_get_property; - gobject_class->set_property = nice_agent_set_property; - gobject_class->dispose = nice_agent_dispose; - - /* install properties */ - /** - * NiceAgent:main-context: - * - * A GLib main context is needed for all timeouts used by libnice. - * This is a property being set by the nice_agent_new() call. - */ - g_object_class_install_property (gobject_class, PROP_MAIN_CONTEXT, - g_param_spec_pointer ( - "main-context", - "The GMainContext to use for timeouts", - "The GMainContext to use for timeouts", - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /** - * NiceAgent:compatibility: - * - * The Nice agent can work in various compatibility modes depending on - * what the application/peer needs. - * See also: #NiceCompatibility - */ - g_object_class_install_property (gobject_class, PROP_COMPATIBILITY, - g_param_spec_uint ( - "compatibility", - "ICE specification compatibility", - "The compatibility mode for the agent", - NICE_COMPATIBILITY_RFC5245, NICE_COMPATIBILITY_LAST, - NICE_COMPATIBILITY_RFC5245, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (gobject_class, PROP_STUN_SERVER, - g_param_spec_string ( - "stun-server", - "STUN server IP address", - "The IP address (not the hostname) of the STUN server to use", - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_STUN_SERVER_PORT, - g_param_spec_uint ( - "stun-server-port", - "STUN server port", - "Port of the STUN server used to gather server-reflexive candidates", - 1, 65536, - 1, /* not a construct property, ignored */ - G_PARAM_READWRITE)); - - /** - * NiceAgent:controlling-mode: - * - * Whether the agent has the controlling role. This property should - * be modified before gathering candidates, any modification occuring - * later will be hold until ICE is restarted. - */ - g_object_class_install_property (gobject_class, PROP_CONTROLLING_MODE, - g_param_spec_boolean ( - "controlling-mode", - "ICE controlling mode", - "Whether the agent is in controlling mode", - FALSE, /* not a construct property, ignored */ - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_FULL_MODE, - g_param_spec_boolean ( - "full-mode", - "ICE full mode", - "Whether agent runs in ICE full mode", - TRUE, /* use full mode by default */ - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (gobject_class, PROP_STUN_PACING_TIMER, - g_param_spec_uint ( - "stun-pacing-timer", - "STUN pacing timer", - "Timer 'Ta' (msecs) used in the IETF ICE specification for pacing " - "candidate gathering and sending of connectivity checks", - 1, 0xffffffff, - NICE_AGENT_TIMER_TA_DEFAULT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - /* note: according to spec recommendation in sect 5.7.3 (ID-19) */ - g_object_class_install_property (gobject_class, PROP_MAX_CONNECTIVITY_CHECKS, - g_param_spec_uint ( - "max-connectivity-checks", - "Maximum number of connectivity checks", - "Upper limit for the total number of connectivity checks performed", - 0, 0xffffffff, - 0, /* default set in init */ - G_PARAM_READWRITE)); - - /** - * NiceAgent:nomination-mode: - * - * The nomination mode used in the ICE specification for describing - * the selection of valid pairs to be used upstream. - * See also: #NiceNominationMode - * - * Since: 0.1.15 - */ - g_object_class_install_property (gobject_class, PROP_NOMINATION_MODE, - g_param_spec_enum ( - "nomination-mode", - "ICE nomination mode", - "Nomination mode used in the ICE specification for describing " - "the selection of valid pairs to be used upstream", - NICE_TYPE_NOMINATION_MODE, NICE_NOMINATION_MODE_AGGRESSIVE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /** - * NiceAgent:support-renomination: - * - * Support RENOMINATION STUN attribute proposed here: - * https://tools.ietf.org/html/draft-thatcher-ice-renomination-00 As - * soon as RENOMINATION attribute is received from remote - * candidate's address, corresponding candidates pair gets - * selected. This is specific to Google Chrome/libWebRTC. - */ - g_object_class_install_property (gobject_class, PROP_SUPPORT_RENOMINATION, - g_param_spec_boolean ( - "support-renomination", - "Support RENOMINATION STUN attribute", - "As soon as RENOMINATION attribute is received from remote candidate's address, " - "corresponding candidates pair gets selected.", - FALSE, - G_PARAM_READWRITE)); - - /** - * NiceAgent:idle-timeout - * - * A final timeout in msec, launched when the agent becomes idle, - * before stopping its activity. - * - * This timer will delay the decision to set a component as failed. - * This delay is added to reduce the chance to see the agent receiving - * new stun activity just after the conncheck list has been declared - * failed (some valid pairs, no nominated pair, and no in-progress - * pairs), reactiviting conncheck activity, and causing a (valid) - * state transitions like that: connecting -> failed -> connecting -> - * connected -> ready. Such transitions are not buggy per-se, but may - * break the test-suite, that counts precisely the number of time each - * state has been set, and doesnt expect these transcient failed - * states. - * - * This timer is also useful when the agent is in controlled mode and - * the other controlling peer takes some time to elect its nominated - * pair (this may be the case for SfB peers). - * - * This timer is *NOT* part if the RFC5245, as this situation is not - * covered in sect 8.1.2 "Updating States", but deals with a real - * use-case, where a controlled agent can not wait forever for the - * other peer to make a nomination decision. - * - * Also note that the value of this timeout will not delay the - * emission of 'connected' and 'ready' agent signals, and will not - * slow down the behaviour of the agent when the peer agent works - * in a timely manner. - * - * Since: 0.1.17 - */ - - g_object_class_install_property (gobject_class, PROP_IDLE_TIMEOUT, - g_param_spec_uint ( - "idle-timeout", - "Timeout before stopping the agent when being idle", - "A final timeout in msecs, launched when the agent becomes idle, " - "with no in-progress pairs to wait for, before stopping its activity, " - "and declaring a component as failed in needed.", - 50, 60000, - DEFAULT_IDLE_TIMEOUT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - /** - * NiceAgent:proxy-ip: - * - * The proxy server IP used to bypass a proxy firewall - * - * Since: 0.0.4 - */ - g_object_class_install_property (gobject_class, PROP_PROXY_IP, - g_param_spec_string ( - "proxy-ip", - "Proxy server IP", - "The proxy server IP used to bypass a proxy firewall", - NULL, - G_PARAM_READWRITE)); - - /** - * NiceAgent:proxy-port: - * - * The proxy server port used to bypass a proxy firewall - * - * Since: 0.0.4 - */ - g_object_class_install_property (gobject_class, PROP_PROXY_PORT, - g_param_spec_uint ( - "proxy-port", - "Proxy server port", - "The Proxy server port used to bypass a proxy firewall", - 1, 65536, - 1, - G_PARAM_READWRITE)); - - /** - * NiceAgent:proxy-type: - * - * The type of proxy set in the proxy-ip property - * - * Since: 0.0.4 - */ - g_object_class_install_property (gobject_class, PROP_PROXY_TYPE, - g_param_spec_uint ( - "proxy-type", - "Type of proxy to use", - "The type of proxy set in the proxy-ip property", - NICE_PROXY_TYPE_NONE, NICE_PROXY_TYPE_LAST, - NICE_PROXY_TYPE_NONE, - G_PARAM_READWRITE)); - - /** - * NiceAgent:proxy-username: - * - * The username used to authenticate with the proxy - * - * Since: 0.0.4 - */ - g_object_class_install_property (gobject_class, PROP_PROXY_USERNAME, - g_param_spec_string ( - "proxy-username", - "Proxy server username", - "The username used to authenticate with the proxy", - NULL, - G_PARAM_READWRITE)); - - /** - * NiceAgent:proxy-password: - * - * The password used to authenticate with the proxy - * - * Since: 0.0.4 - */ - g_object_class_install_property (gobject_class, PROP_PROXY_PASSWORD, - g_param_spec_string ( - "proxy-password", - "Proxy server password", - "The password used to authenticate with the proxy", - NULL, - G_PARAM_READWRITE)); - - /** - * NiceAgent:upnp: - * - * Whether the agent should use UPnP to open a port in the router and - * get the external IP - * - * Since: 0.0.7 - */ - g_object_class_install_property (gobject_class, PROP_UPNP, - g_param_spec_boolean ( - "upnp", -#ifdef HAVE_GUPNP - "Use UPnP", - "Whether the agent should use UPnP to open a port in the router and " - "get the external IP", -#else - "Use UPnP (disabled in build)", - "Does nothing because libnice was not built with UPnP support", -#endif - TRUE, /* enable UPnP by default */ - G_PARAM_READWRITE| G_PARAM_CONSTRUCT)); - - /** - * NiceAgent:upnp-timeout: - * - * The maximum amount of time (in milliseconds) to wait for UPnP discovery to - * finish before signaling the #NiceAgent::candidate-gathering-done signal - * - * Since: 0.0.7 - */ - g_object_class_install_property (gobject_class, PROP_UPNP_TIMEOUT, - g_param_spec_uint ( - "upnp-timeout", -#ifdef HAVE_GUPNP - "Timeout for UPnP discovery", - "The maximum amount of time to wait for UPnP discovery to finish before " - "signaling the candidate-gathering-done signal", -#else - "Timeout for UPnP discovery (disabled in build)", - "Does nothing because libnice was not built with UPnP support", -#endif - 100, 60000, - DEFAULT_UPNP_TIMEOUT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - /** - * NiceAgent:reliable: - * - * Whether the agent is providing a reliable transport of messages (through - * ICE-TCP or PseudoTCP over ICE-UDP) - * - * Since: 0.0.11 - */ - g_object_class_install_property (gobject_class, PROP_RELIABLE, - g_param_spec_boolean ( - "reliable", - "reliable mode", - "Whether the agent provides a reliable transport of messages", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /** - * NiceAgent:ice-udp: - * - * Whether the agent should use ICE-UDP when gathering candidates. - * If the option is disabled, no UDP candidates will be generated. If the - * agent is in reliable mode, then pseudotcp will not be used since pseudotcp - * works on top of UDP candidates. - * - * This option should be set before gathering candidates and should not be - * modified afterwards. - * - * The #NiceAgent:ice-udp property can be set at the same time as the - * #NiceAgent:ice-tcp property, but both cannot be unset at the same time. - * If #NiceAgent:ice-tcp is set to %FALSE, then this property cannot be set - * to %FALSE as well. - * - * Since: 0.1.8 - */ - g_object_class_install_property (gobject_class, PROP_ICE_UDP, - g_param_spec_boolean ( - "ice-udp", - "Use ICE-UDP", - "Use ICE-UDP specification to generate UDP candidates", - TRUE, /* use ice-udp by default */ - G_PARAM_READWRITE)); - - /** - * NiceAgent:ice-tcp: - * - * Whether the agent should use ICE-TCP when gathering candidates. - * If the option is disabled, no TCP candidates will be generated. If the - * agent is in reliable mode, then pseudotcp will need to be used over UDP - * candidates. - * - * This option should be set before gathering candidates and should not be - * modified afterwards. - * - * The #NiceAgent:ice-tcp property can be set at the same time as the - * #NiceAgent:ice-udp property, but both cannot be unset at the same time. - * If #NiceAgent:ice-udp is set to %FALSE, then this property cannot be set - * to %FALSE as well. - * - - ICE-TCP is only supported for %NICE_COMPATIBILITY_RFC5245, - %NICE_COMPATIBILITY_OC2007 and %NICE_COMPATIBILITY_OC2007R2 compatibility - modes. - - * - * - * Since: 0.1.8 - */ - g_object_class_install_property (gobject_class, PROP_ICE_TCP, - g_param_spec_boolean ( - "ice-tcp", - "Use ICE-TCP", - "Use ICE-TCP specification to generate TCP candidates", - TRUE, /* use ice-tcp by default */ - G_PARAM_READWRITE)); - - /** - * NiceAgent:bytestream-tcp: - * - * This property defines whether receive/send over a TCP or pseudo-TCP, in - * reliable mode, are considered as packetized or as bytestream. - * In unreliable mode, every send/recv is considered as packetized, and - * this property is ignored and cannot be set. - * - * In reliable mode, this property will always return %TRUE in the - * %NICE_COMPATIBILITY_GOOGLE compatibility mode. - * - * If the property is %TRUE, the stream is considered in bytestream mode - * and data can be read with any receive size. If the property is %FALSE, then - * the stream is considred packetized and each receive will return one packet - * of the same size as what was sent from the peer. If in packetized mode, - * then doing a receive with a size smaller than the packet, will cause the - * remaining bytes in the packet to be dropped, breaking the reliability - * of the stream. - * - * This property is currently read-only, and will become read/write once - * bytestream mode will be supported. - * - * - * Since: 0.1.8 - */ - g_object_class_install_property (gobject_class, PROP_BYTESTREAM_TCP, - g_param_spec_boolean ( - "bytestream-tcp", - "Bytestream TCP", - "Use bytestream mode for reliable TCP and Pseudo-TCP connections", - FALSE, - G_PARAM_READABLE)); - - /** - * NiceAgent:keepalive-conncheck: - * - * Use binding requests as keepalives instead of binding - * indications. This means that the keepalives may time out which - * will change the component state to %NICE_COMPONENT_STATE_FAILED. - * - * Enabing this is a slight violation of RFC 5245 section 10 which - * recommends using Binding Indications for keepalives. - * - * This is always enabled if the compatibility mode is - * %NICE_COMPATIBILITY_GOOGLE. - * - * Since: 0.1.8 - */ - g_object_class_install_property (gobject_class, PROP_KEEPALIVE_CONNCHECK, - g_param_spec_boolean ( - "keepalive-conncheck", - "Use conncheck as keepalives", - "Use binding requests which require a reply as keepalives instead of " - "binding indications which don't.", - FALSE, - G_PARAM_READWRITE)); - - /** - * NiceAgent:force-relay - * - * Force all traffic to go through a relay for added privacy, this - * allows hiding the local IP address. When this is enabled, so - * local candidates are available before relay servers have been set - * with nice_agent_set_relay_info(). - * - * Since: 0.1.14 - */ - g_object_class_install_property (gobject_class, PROP_FORCE_RELAY, - g_param_spec_boolean ( - "force-relay", - "Force Relay", - "Force all traffic to go through a relay for added privacy.", - FALSE, - G_PARAM_READWRITE)); - - /** - * NiceAgent:stun-max-retransmissions - * - * The maximum number of retransmissions of the STUN binding requests - * used in the gathering stage, to find our local candidates, and used - * in the connection check stage, to test the validity of each - * constructed pair. This property is described as 'Rc' in the RFC - * 5389, with a default value of 7. The timeout of each STUN request - * is doubled for each retransmission, so the choice of this value has - * a direct impact on the time needed to move from the CONNECTED state - * to the READY state, and on the time needed to complete the GATHERING - * state. - * - * Since: 0.1.15 - */ - - g_object_class_install_property (gobject_class, PROP_STUN_MAX_RETRANSMISSIONS, - g_param_spec_uint ( - "stun-max-retransmissions", - "STUN Max Retransmissions", - "Maximum number of STUN binding requests retransmissions " - "described as 'Rc' in the STUN specification.", - 1, 99, - STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - /** - * NiceAgent:stun-initial-timeout - * - * The initial timeout (msecs) of the STUN binding requests - * used in the gathering stage, to find our local candidates. - * This property is described as 'RTO' in the RFC 5389 and RFC 5245. - * This timeout is doubled for each retransmission, until - * #NiceAgent:stun-max-retransmissions have been done, - * with an exception for the last restransmission, where the timeout is - * divided by two instead (RFC 5389 indicates that a customisable - * multiplier 'Rm' to 'RTO' should be used). - * - * Since: 0.1.15 - */ - - g_object_class_install_property (gobject_class, PROP_STUN_INITIAL_TIMEOUT, - g_param_spec_uint ( - "stun-initial-timeout", - "STUN Initial Timeout", - "STUN timeout in msecs of the initial binding requests used in the " - "gathering state, described as 'RTO' in the ICE specification.", - 20, 9999, - STUN_TIMER_DEFAULT_TIMEOUT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - /** - * NiceAgent:stun-reliable-timeout - * - * The initial timeout of the STUN binding requests used - * for a reliable timer. - * - * Since: 0.1.15 - */ - - g_object_class_install_property (gobject_class, PROP_STUN_RELIABLE_TIMEOUT, - g_param_spec_uint ( - "stun-reliable-timeout", - "STUN Reliable Timeout", - "STUN timeout in msecs of the initial binding requests used for " - "a reliable timer.", - 20, 99999, - STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - /** - * NiceAgent:ice-trickle - * - * Whether to perform Trickle ICE as per draft-ietf-ice-trickle-ice-21. - * When %TRUE, the agent will postpone changing a component state to - * %NICE_COMPONENT_STATE_FAILED until nice_agent_peer_candidate_gathering_done() - * has been called with the ID of the component's stream. - * - * Since: 0.1.16 - */ - g_object_class_install_property (gobject_class, PROP_ICE_TRICKLE, - g_param_spec_boolean ( - "ice-trickle", - "Trickle ICE", - "Whether to perform Trickle ICE as per draft-ietf-ice-trickle-ice-21.", - FALSE, - G_PARAM_READWRITE)); - - /* install signals */ - - /** - * NiceAgent::component-state-changed - * @agent: The #NiceAgent object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * @state: The new #NiceComponentState of the component - * - * This signal is fired whenever a component’s state changes. There are many - * valid state transitions. - * - * ![State transition diagram](states.png) - */ - signals[SIGNAL_COMPONENT_STATE_CHANGED] = - g_signal_new ( - "component-state-changed", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 3, - G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, - G_TYPE_INVALID); - - /** - * NiceAgent::candidate-gathering-done: - * @agent: The #NiceAgent object - * @stream_id: The ID of the stream - * - * This signal is fired whenever a stream has finished gathering its - * candidates after a call to nice_agent_gather_candidates() - */ - signals[SIGNAL_CANDIDATE_GATHERING_DONE] = - g_signal_new ( - "candidate-gathering-done", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - G_TYPE_UINT, G_TYPE_INVALID); - - /** - * NiceAgent::new-selected-pair - * @agent: The #NiceAgent object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * @lfoundation: The local foundation of the selected candidate pair - * @rfoundation: The remote foundation of the selected candidate pair - * - * This signal is fired once a candidate pair is selected for data - * transfer for a stream's component This is emitted along with - * #NiceAgent::new-selected-pair-full which has the whole candidate, - * the Foundation of a Candidate is not a unique identifier. - * - * See also: #NiceAgent::new-selected-pair-full - * Deprecated: 0.1.8: Use #NiceAgent::new-selected-pair-full - */ - signals[SIGNAL_NEW_SELECTED_PAIR] = - g_signal_new ( - "new-selected-pair", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 4, - G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_INVALID); - - /** - * NiceAgent::new-candidate - * @agent: The #NiceAgent object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * @foundation: The foundation of the new candidate - * - * This signal is fired when the agent discovers a new local candidate. - * When this signal is emitted, a matching #NiceAgent::new-candidate-full is - * also emitted with the candidate. - * - * See also: #NiceAgent::candidate-gathering-done, - * #NiceAgent::new-candidate-full - * Deprecated: 0.1.8: Use #NiceAgent::new-candidate-full - */ - signals[SIGNAL_NEW_CANDIDATE] = - g_signal_new ( - "new-candidate", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 3, - G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, - G_TYPE_INVALID); - - /** - * NiceAgent::new-remote-candidate - * @agent: The #NiceAgent object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * @foundation: The foundation of the new candidate - * - * This signal is fired when the agent discovers a new remote - * candidate. This can happen with peer reflexive candidates. When - * this signal is emitted, a matching - * #NiceAgent::new-remote-candidate-full is also emitted with the - * candidate. - * - * See also: #NiceAgent::new-remote-candidate-full - * Deprecated: 0.1.8: Use #NiceAgent::new-remote-candidate-full - */ - signals[SIGNAL_NEW_REMOTE_CANDIDATE] = - g_signal_new ( - "new-remote-candidate", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 3, - G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, - G_TYPE_INVALID); - - /** - * NiceAgent::initial-binding-request-received - * @agent: The #NiceAgent object - * @stream_id: The ID of the stream - * - * This signal is fired when we received our first binding request from - * the peer. - */ - signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED] = - g_signal_new ( - "initial-binding-request-received", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - G_TYPE_UINT, - G_TYPE_INVALID); - - /** - * NiceAgent::reliable-transport-writable - * @agent: The #NiceAgent object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * - * This signal is fired on the reliable #NiceAgent when the underlying reliable - * transport becomes writable. - * This signal is only emitted when the nice_agent_send() function returns less - * bytes than requested to send (or -1) and once when the connection - * is established. - * - * Since: 0.0.11 - */ - signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE] = - g_signal_new ( - "reliable-transport-writable", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_UINT, G_TYPE_UINT, - G_TYPE_INVALID); - - /** - * NiceAgent::streams-removed - * @agent: The #NiceAgent object - * @stream_ids: (array zero-terminated=1) (element-type uint): An array of - * unsigned integer stream IDs, ending with a 0 ID - * - * This signal is fired whenever one or more streams are removed from the - * @agent. - * - * Since: 0.1.5 - */ - signals[SIGNAL_STREAMS_REMOVED] = - g_signal_new ( - "streams-removed", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, - NICE_TYPE_AGENT_STREAM_IDS, - G_TYPE_INVALID); - - - /** - * NiceAgent::new-selected-pair-full - * @agent: The #NiceAgent object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * @lcandidate: The local #NiceCandidate of the selected candidate pair - * @rcandidate: The remote #NiceCandidate of the selected candidate pair - * - * This signal is fired once a candidate pair is selected for data - * transfer for a stream's component. This is emitted along with - * #NiceAgent::new-selected-pair. - * - * See also: #NiceAgent::new-selected-pair - * Since: 0.1.8 - */ - signals[SIGNAL_NEW_SELECTED_PAIR_FULL] = - g_signal_new ( - "new-selected-pair-full", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 4, G_TYPE_UINT, G_TYPE_UINT, NICE_TYPE_CANDIDATE, NICE_TYPE_CANDIDATE, - G_TYPE_INVALID); - - /** - * NiceAgent::new-candidate-full - * @agent: The #NiceAgent object - * @candidate: The new #NiceCandidate - * - * This signal is fired when the agent discovers a new local candidate. - * When this signal is emitted, a matching #NiceAgent::new-candidate is - * also emitted with the candidate's foundation. - * - * See also: #NiceAgent::candidate-gathering-done, - * #NiceAgent::new-candidate - * Since: 0.1.8 - */ - signals[SIGNAL_NEW_CANDIDATE_FULL] = - g_signal_new ( - "new-candidate-full", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - NICE_TYPE_CANDIDATE, - G_TYPE_INVALID); - - /** - * NiceAgent::new-remote-candidate-full - * @agent: The #NiceAgent object - * @candidate: The new #NiceCandidate - * - * This signal is fired when the agent discovers a new remote candidate. - * This can happen with peer reflexive candidates. - * When this signal is emitted, a matching #NiceAgent::new-remote-candidate is - * also emitted with the candidate's foundation. - * - * See also: #NiceAgent::new-remote-candidate - * Since: 0.1.8 - */ - signals[SIGNAL_NEW_REMOTE_CANDIDATE_FULL] = - g_signal_new ( - "new-remote-candidate-full", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - NICE_TYPE_CANDIDATE, - G_TYPE_INVALID); - - /* Init debug options depending on env variables */ - nice_debug_init (); -} - -static void priv_generate_tie_breaker (NiceAgent *agent) -{ - nice_rng_generate_bytes (agent->rng, 8, (gchar*)&agent->tie_breaker); -} - -static void -priv_update_controlling_mode (NiceAgent *agent, gboolean value) -{ - gboolean update_controlling_mode; - GSList *i, *j; - - agent->saved_controlling_mode = value; - /* It is safe to update the agent controlling mode when all - * components are still in state disconnected. When we leave - * this state, the role must stay under the control of the - * conncheck algorithm exclusively, until the conncheck is - * eventually restarted. See RFC5245, sect 5.2. Determining Role - */ - if (agent->controlling_mode != agent->saved_controlling_mode) { - update_controlling_mode = TRUE; - for (i = agent->streams; - i && update_controlling_mode; i = i->next) { - NiceStream *stream = i->data; - for (j = stream->components; - j && update_controlling_mode; j = j->next) { - NiceComponent *component = j->data; - if (component->state > NICE_COMPONENT_STATE_DISCONNECTED) - update_controlling_mode = FALSE; - } - } - if (update_controlling_mode) { - agent->controlling_mode = agent->saved_controlling_mode; - nice_debug ("Agent %p : Property set, changing role to \"%s\".", - agent, agent->controlling_mode ? "controlling" : "controlled"); - } else { - nice_debug ("Agent %p : Property set, role switch requested " - "but conncheck already started.", agent); - nice_debug ("Agent %p : Property set, staying with role \"%s\" " - "until restart.", agent, - agent->controlling_mode ? "controlling" : "controlled"); - } - } else - nice_debug ("Agent %p : Property set, role is already \"%s\".", agent, - agent->controlling_mode ? "controlling" : "controlled"); -} - -static void -nice_agent_init (NiceAgent *agent) -{ - agent->next_candidate_id = 1; - agent->next_stream_id = 1; - - /* set defaults; not construct params, so set here */ - agent->stun_server_port = DEFAULT_STUN_PORT; - agent->controlling_mode = TRUE; - agent->saved_controlling_mode = TRUE; - agent->max_conn_checks = NICE_AGENT_MAX_CONNECTIVITY_CHECKS_DEFAULT; - agent->nomination_mode = NICE_NOMINATION_MODE_AGGRESSIVE; - agent->support_renomination = FALSE; - agent->idle_timeout = DEFAULT_IDLE_TIMEOUT; - - agent->discovery_list = NULL; - agent->discovery_unsched_items = 0; - agent->discovery_timer_source = NULL; - agent->conncheck_timer_source = NULL; - agent->keepalive_timer_source = NULL; - agent->refresh_list = NULL; - agent->media_after_tick = FALSE; - agent->software_attribute = NULL; - - agent->compatibility = NICE_COMPATIBILITY_RFC5245; - agent->reliable = FALSE; - agent->use_ice_udp = TRUE; - agent->use_ice_tcp = TRUE; - - agent->rng = nice_rng_new (); - priv_generate_tie_breaker (agent); - - g_queue_init (&agent->pending_signals); - - g_mutex_init (&agent->agent_mutex); -} - - -NICEAPI_EXPORT NiceAgent * -nice_agent_new (GMainContext *ctx, NiceCompatibility compat) -{ - NiceAgent *agent = g_object_new (NICE_TYPE_AGENT, - "compatibility", compat, - "main-context", ctx, - "reliable", FALSE, - NULL); - - return agent; -} - - -NICEAPI_EXPORT NiceAgent * -nice_agent_new_reliable (GMainContext *ctx, NiceCompatibility compat) -{ - NiceAgent *agent = g_object_new (NICE_TYPE_AGENT, - "compatibility", compat, - "main-context", ctx, - "reliable", TRUE, - NULL); - - return agent; -} - - -NICEAPI_EXPORT NiceAgent * -nice_agent_new_full (GMainContext *ctx, - NiceCompatibility compat, - NiceAgentOption flags) -{ - NiceAgent *agent = g_object_new (NICE_TYPE_AGENT, - "compatibility", compat, - "main-context", ctx, - "reliable", (flags & NICE_AGENT_OPTION_RELIABLE) ? TRUE : FALSE, - "nomination-mode", (flags & NICE_AGENT_OPTION_REGULAR_NOMINATION) ? - NICE_NOMINATION_MODE_REGULAR : NICE_NOMINATION_MODE_AGGRESSIVE, - "full-mode", (flags & NICE_AGENT_OPTION_LITE_MODE) ? FALSE : TRUE, - "ice-trickle", (flags & NICE_AGENT_OPTION_ICE_TRICKLE) ? TRUE : FALSE, - "support-renomination", (flags & NICE_AGENT_OPTION_SUPPORT_RENOMINATION) ? TRUE : FALSE, - NULL); - - return agent; -} - - -static void -nice_agent_get_property ( - GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - NiceAgent *agent = NICE_AGENT (object); - - agent_lock (agent); - - switch (property_id) - { - case PROP_MAIN_CONTEXT: - g_value_set_pointer (value, agent->main_context); - break; - - case PROP_COMPATIBILITY: - g_value_set_uint (value, agent->compatibility); - break; - - case PROP_STUN_SERVER: - g_value_set_string (value, agent->stun_server_ip); - break; - - case PROP_STUN_SERVER_PORT: - g_value_set_uint (value, agent->stun_server_port); - break; - - case PROP_CONTROLLING_MODE: - g_value_set_boolean (value, agent->saved_controlling_mode); - break; - - case PROP_FULL_MODE: - g_value_set_boolean (value, agent->full_mode); - break; - - case PROP_STUN_PACING_TIMER: - g_value_set_uint (value, agent->timer_ta); - break; - - case PROP_MAX_CONNECTIVITY_CHECKS: - g_value_set_uint (value, agent->max_conn_checks); - /* XXX: should we prune the list of already existing checks? */ - break; - - case PROP_NOMINATION_MODE: - g_value_set_enum (value, agent->nomination_mode); - break; - - case PROP_SUPPORT_RENOMINATION: - g_value_set_boolean (value, agent->support_renomination); - break; - - case PROP_IDLE_TIMEOUT: - g_value_set_uint (value, agent->idle_timeout); - break; - - case PROP_PROXY_IP: - g_value_set_string (value, agent->proxy_ip); - break; - - case PROP_PROXY_PORT: - g_value_set_uint (value, agent->proxy_port); - break; - - case PROP_PROXY_TYPE: - g_value_set_uint (value, agent->proxy_type); - break; - - case PROP_PROXY_USERNAME: - g_value_set_string (value, agent->proxy_username); - break; - - case PROP_PROXY_PASSWORD: - g_value_set_string (value, agent->proxy_password); - break; - - case PROP_UPNP: -#ifdef HAVE_GUPNP - g_value_set_boolean (value, agent->upnp_enabled); -#else - g_value_set_boolean (value, FALSE); -#endif - break; - - case PROP_UPNP_TIMEOUT: -#ifdef HAVE_GUPNP - g_value_set_uint (value, agent->upnp_timeout); -#else - g_value_set_uint (value, DEFAULT_UPNP_TIMEOUT); -#endif - break; - - case PROP_RELIABLE: - g_value_set_boolean (value, agent->reliable); - break; - - case PROP_ICE_UDP: - g_value_set_boolean (value, agent->use_ice_udp); - break; - - case PROP_ICE_TCP: - g_value_set_boolean (value, agent->use_ice_tcp); - break; - - case PROP_BYTESTREAM_TCP: - if (agent->reliable) { - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) - g_value_set_boolean (value, TRUE); - else - g_value_set_boolean (value, FALSE); - } else { - g_value_set_boolean (value, FALSE); - } - break; - - case PROP_KEEPALIVE_CONNCHECK: - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) - g_value_set_boolean (value, TRUE); - else - g_value_set_boolean (value, agent->keepalive_conncheck); - break; - - case PROP_FORCE_RELAY: - g_value_set_boolean (value, agent->force_relay); - break; - - case PROP_STUN_MAX_RETRANSMISSIONS: - g_value_set_uint (value, agent->stun_max_retransmissions); - break; - - case PROP_STUN_INITIAL_TIMEOUT: - g_value_set_uint (value, agent->stun_initial_timeout); - break; - - case PROP_STUN_RELIABLE_TIMEOUT: - g_value_set_uint (value, agent->stun_reliable_timeout); - break; - - case PROP_ICE_TRICKLE: - g_value_set_boolean (value, agent->use_ice_trickle); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } - - agent_unlock_and_emit(agent); -} - -void -nice_agent_init_stun_agent (NiceAgent *agent, StunAgent *stun_agent) -{ - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC3489, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS | - STUN_AGENT_USAGE_IGNORE_CREDENTIALS); - } else if (agent->compatibility == NICE_COMPATIBILITY_MSN) { - stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC3489, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS | - STUN_AGENT_USAGE_FORCE_VALIDATER); - } else if (agent->compatibility == NICE_COMPATIBILITY_WLM2009) { - stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_MSICE2, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS | - STUN_AGENT_USAGE_USE_FINGERPRINT); - } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007) { - stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC3489, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS | - STUN_AGENT_USAGE_FORCE_VALIDATER | - STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES); - } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_MSICE2, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS | - STUN_AGENT_USAGE_USE_FINGERPRINT | - STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES); - } else { - stun_agent_init (stun_agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC5389, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS | - STUN_AGENT_USAGE_USE_FINGERPRINT); - } - stun_agent_set_software (stun_agent, agent->software_attribute); -} - -static void -nice_agent_reset_all_stun_agents (NiceAgent *agent, gboolean only_software) -{ - GSList *stream_item, *component_item; - - for (stream_item = agent->streams; stream_item; - stream_item = stream_item->next) { - NiceStream *stream = stream_item->data; - - for (component_item = stream->components; component_item; - component_item = component_item->next) { - NiceComponent *component = component_item->data; - - if (only_software) - stun_agent_set_software (&component->stun_agent, - agent->software_attribute); - else - nice_agent_init_stun_agent(agent, &component->stun_agent); - } - } -} - -static void -nice_agent_set_property ( - GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - NiceAgent *agent = NICE_AGENT (object); - - agent_lock (agent); - - switch (property_id) - { - case PROP_MAIN_CONTEXT: - agent->main_context = g_value_get_pointer (value); - if (agent->main_context != NULL) - g_main_context_ref (agent->main_context); - break; - - case PROP_COMPATIBILITY: - agent->compatibility = g_value_get_uint (value); - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE || - agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_WLM2009) - agent->use_ice_tcp = FALSE; - - nice_agent_reset_all_stun_agents (agent, FALSE); - break; - - case PROP_STUN_SERVER: - g_free (agent->stun_server_ip); - agent->stun_server_ip = g_value_dup_string (value); - break; - - case PROP_STUN_SERVER_PORT: - agent->stun_server_port = g_value_get_uint (value); - break; - - case PROP_CONTROLLING_MODE: - priv_update_controlling_mode (agent, g_value_get_boolean (value)); - break; - - case PROP_FULL_MODE: - agent->full_mode = g_value_get_boolean (value); - break; - - case PROP_STUN_PACING_TIMER: - agent->timer_ta = g_value_get_uint (value); - break; - - case PROP_MAX_CONNECTIVITY_CHECKS: - agent->max_conn_checks = g_value_get_uint (value); - break; - - case PROP_NOMINATION_MODE: - agent->nomination_mode = g_value_get_enum (value); - break; - - case PROP_SUPPORT_RENOMINATION: - agent->support_renomination = g_value_get_boolean (value); - break; - - case PROP_IDLE_TIMEOUT: - agent->idle_timeout = g_value_get_uint (value); - break; - - case PROP_PROXY_IP: - g_free (agent->proxy_ip); - agent->proxy_ip = g_value_dup_string (value); - break; - - case PROP_PROXY_PORT: - agent->proxy_port = g_value_get_uint (value); - break; - - case PROP_PROXY_TYPE: - agent->proxy_type = g_value_get_uint (value); - break; - - case PROP_PROXY_USERNAME: - g_free (agent->proxy_username); - agent->proxy_username = g_value_dup_string (value); - break; - - case PROP_PROXY_PASSWORD: - g_free (agent->proxy_password); - agent->proxy_password = g_value_dup_string (value); - break; - - case PROP_UPNP_TIMEOUT: -#ifdef HAVE_GUPNP - agent->upnp_timeout = g_value_get_uint (value); -#endif - break; - - case PROP_UPNP: -#ifdef HAVE_GUPNP - agent->upnp_enabled = g_value_get_boolean (value); -#endif - break; - - case PROP_RELIABLE: - agent->reliable = g_value_get_boolean (value); - break; - - /* Don't allow ice-udp and ice-tcp to be disabled at the same time */ - case PROP_ICE_UDP: - if (agent->use_ice_tcp == TRUE || g_value_get_boolean (value) == TRUE) - agent->use_ice_udp = g_value_get_boolean (value); - break; - - case PROP_ICE_TCP: - if ((agent->compatibility == NICE_COMPATIBILITY_RFC5245 || - agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2) && - (agent->use_ice_udp == TRUE || g_value_get_boolean (value) == TRUE)) - agent->use_ice_tcp = g_value_get_boolean (value); - break; - - case PROP_BYTESTREAM_TCP: - /* TODO: support bytestream mode and set property to writable */ - break; - - case PROP_KEEPALIVE_CONNCHECK: - agent->keepalive_conncheck = g_value_get_boolean (value); - break; - - case PROP_FORCE_RELAY: - agent->force_relay = g_value_get_boolean (value); - break; - - case PROP_STUN_MAX_RETRANSMISSIONS: - agent->stun_max_retransmissions = g_value_get_uint (value); - break; - - case PROP_STUN_INITIAL_TIMEOUT: - agent->stun_initial_timeout = g_value_get_uint (value); - break; - - case PROP_STUN_RELIABLE_TIMEOUT: - agent->stun_reliable_timeout = g_value_get_uint (value); - break; - - case PROP_ICE_TRICKLE: - agent->use_ice_trickle = g_value_get_boolean (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } - - agent_unlock_and_emit (agent); - -} - - -static void - agent_signal_socket_writable (NiceAgent *agent, NiceComponent *component) -{ - g_cancellable_cancel (component->tcp_writable_cancellable); - - agent_queue_signal (agent, signals[SIGNAL_RELIABLE_TRANSPORT_WRITABLE], - component->stream_id, component->id); -} - -static void -pseudo_tcp_socket_create (NiceAgent *agent, NiceStream *stream, NiceComponent *component) -{ - PseudoTcpCallbacks tcp_callbacks = {component, - pseudo_tcp_socket_opened, - pseudo_tcp_socket_readable, - pseudo_tcp_socket_writable, - pseudo_tcp_socket_closed, - pseudo_tcp_socket_write_packet}; - component->tcp = pseudo_tcp_socket_new (0, &tcp_callbacks); - component->tcp_writable_cancellable = g_cancellable_new (); - nice_debug ("Agent %p: Create Pseudo Tcp Socket for component %d", - agent, component->id); -} - -static void priv_pseudo_tcp_error (NiceAgent *agent, NiceComponent *component) -{ - if (component->tcp_writable_cancellable) { - g_cancellable_cancel (component->tcp_writable_cancellable); - g_clear_object (&component->tcp_writable_cancellable); - } - - if (component->tcp) { - agent_signal_component_state_change (agent, component->stream_id, - component->id, NICE_COMPONENT_STATE_FAILED); - nice_component_detach_all_sockets (component); - pseudo_tcp_socket_close (component->tcp, TRUE); - } - - if (component->tcp_clock) { - g_source_destroy (component->tcp_clock); - g_source_unref (component->tcp_clock); - component->tcp_clock = NULL; - } -} - -static void -pseudo_tcp_socket_opened (PseudoTcpSocket *sock, gpointer user_data) -{ - NiceComponent *component = user_data; - NiceAgent *agent; - - agent = g_weak_ref_get (&component->agent_ref); - if (agent == NULL) - return; - - nice_debug ("Agent %p: s%d:%d pseudo Tcp socket Opened", agent, - component->stream_id, component->id); - - agent_signal_socket_writable (agent, component); - - g_object_unref (agent); -} - -/* Will attempt to queue all @n_messages into the pseudo-TCP transmission - * buffer. This is always used in reliable mode, so essentially treats @messages - * as a massive flat array of buffers. - * - * Returns the number of messages successfully sent on success (which may be - * zero if sending the first buffer of the message would have blocked), or - * a negative number on error. If "allow_partial" is TRUE, then it returns - * the number of bytes sent - */ -static gint -pseudo_tcp_socket_send_messages (PseudoTcpSocket *self, - const NiceOutputMessage *messages, guint n_messages, gboolean allow_partial, - GError **error) -{ - guint i; - gint bytes_sent = 0; - - for (i = 0; i < n_messages; i++) { - const NiceOutputMessage *message = &messages[i]; - guint j; - - /* If allow_partial is FALSE and there’s not enough space for the - * entire message, bail now before queuing anything. This doesn’t - * gel with the fact this function is only used in reliable mode, - * and there is no concept of a ‘message’, but is necessary - * because the calling API has no way of returning to the client - * and indicating that a message was partially sent. */ - if (!allow_partial && - output_message_get_size (message) > - pseudo_tcp_socket_get_available_send_space (self)) { - return i; - } - - for (j = 0; - (message->n_buffers >= 0 && j < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[j].buffer != NULL); - j++) { - const GOutputVector *buffer = &message->buffers[j]; - gssize ret; - - /* Send on the pseudo-TCP socket. */ - ret = pseudo_tcp_socket_send (self, buffer->buffer, buffer->size); - - /* In case of -1, the error is either EWOULDBLOCK or ENOTCONN, which both - * need the user to wait for the reliable-transport-writable signal */ - if (ret < 0) { - if (pseudo_tcp_socket_get_error (self) == EWOULDBLOCK) - goto out; - - if (pseudo_tcp_socket_get_error (self) == ENOTCONN || - pseudo_tcp_socket_get_error (self) == EPIPE) - g_set_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK, - "TCP connection is not yet established."); - else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Error writing data to pseudo-TCP socket."); - return -1; - } else { - bytes_sent += ret; - } - } - } - - out: - - return allow_partial ? bytes_sent : (gint) i; -} - -/* Will fill up @messages from the first free byte onwards (as determined using - * @iter). This is always used in reliable mode, so it essentially treats - * @messages as a massive flat array of buffers. - * - * Updates @iter in place. @iter and @messages are left in invalid states if - * an error is returned. - * - * Returns the number of valid messages in @messages on success (which may be - * zero if no data is pending and the peer has disconnected), or a negative - * number on error (including if the request would have blocked returning no - * messages). */ -static gint -pseudo_tcp_socket_recv_messages (PseudoTcpSocket *self, - NiceInputMessage *messages, guint n_messages, NiceInputMessageIter *iter, - GError **error) -{ - for (; iter->message < n_messages; iter->message++) { - NiceInputMessage *message = &messages[iter->message]; - - if (iter->buffer == 0 && iter->offset == 0) { - message->length = 0; - } - - for (; - (message->n_buffers >= 0 && iter->buffer < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[iter->buffer].buffer != NULL); - iter->buffer++) { - GInputVector *buffer = &message->buffers[iter->buffer]; - - do { - gssize len; - - len = pseudo_tcp_socket_recv (self, - (gchar *) buffer->buffer + iter->offset, - buffer->size - iter->offset); - - nice_debug_verbose ("%s: Received %" G_GSSIZE_FORMAT " bytes into " - "buffer %p (offset %" G_GSIZE_FORMAT ", length %" G_GSIZE_FORMAT - ").", G_STRFUNC, len, buffer->buffer, iter->offset, buffer->size); - - if (len == 0) { - /* Reached EOS. */ - goto done; - } else if (len < 0 && - pseudo_tcp_socket_get_error (self) == EWOULDBLOCK) { - /* EWOULDBLOCK. If we’ve already received something, return that; - * otherwise, error. */ - if (nice_input_message_iter_get_n_valid_messages (iter) > 0) { - goto done; - } - g_set_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK, - "Error reading data from pseudo-TCP socket: would block."); - return len; - } else if (len < 0 && pseudo_tcp_socket_get_error (self) == ENOTCONN) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK, - "Error reading data from pseudo-TCP socket: not connected."); - return len; - } else if (len < 0) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Error reading data from pseudo-TCP socket."); - return len; - } else { - /* Got some data! */ - message->length += len; - iter->offset += len; - } - } while (iter->offset < buffer->size); - - iter->offset = 0; - } - - iter->buffer = 0; - } - -done: - return nice_input_message_iter_get_n_valid_messages (iter); -} - -/* This is called with the agent lock held. */ -static void -pseudo_tcp_socket_readable (PseudoTcpSocket *sock, gpointer user_data) -{ - NiceComponent *component = user_data; - NiceAgent *agent; - gboolean has_io_callback; - NiceStream *stream = NULL; - guint stream_id = component->stream_id; - guint component_id = component->id; - - agent = g_weak_ref_get (&component->agent_ref); - if (agent == NULL) - return; - - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) { - goto out; - } - - nice_debug_verbose ("Agent %p: s%d:%d pseudo Tcp socket readable", agent, - stream_id, component->id); - - component->tcp_readable = TRUE; - - has_io_callback = nice_component_has_io_callback (component); - - /* Only dequeue pseudo-TCP data if we can reliably inform the client. The - * agent lock is held here, so has_io_callback can only change during - * nice_component_emit_io_callback(), after which it’s re-queried. This ensures - * no data loss of packets already received and dequeued. */ - if (has_io_callback) { - do { - guint8 buf[MAX_BUFFER_SIZE]; - gssize len; - - /* FIXME: Why copy into a temporary buffer here? Why can’t the I/O - * callbacks be emitted directly from the pseudo-TCP receive buffer? */ - len = pseudo_tcp_socket_recv (sock, (gchar *) buf, sizeof(buf)); - - nice_debug ("%s: I/O callback case: Received %" G_GSSIZE_FORMAT " bytes", - G_STRFUNC, len); - - if (len == 0) { - /* Reached EOS. */ - component->tcp_readable = FALSE; - pseudo_tcp_socket_close (component->tcp, FALSE); - break; - } else if (len < 0) { - /* Handle errors. */ - if (pseudo_tcp_socket_get_error (sock) != EWOULDBLOCK) { - nice_debug ("%s: calling priv_pseudo_tcp_error()", G_STRFUNC); - priv_pseudo_tcp_error (agent, component); - } - - if (component->recv_buf_error != NULL) { - GIOErrorEnum error_code; - - if (pseudo_tcp_socket_get_error (sock) == ENOTCONN) - error_code = G_IO_ERROR_BROKEN_PIPE; - else if (pseudo_tcp_socket_get_error (sock) == EWOULDBLOCK) - error_code = G_IO_ERROR_WOULD_BLOCK; - else - error_code = G_IO_ERROR_FAILED; - - g_set_error (component->recv_buf_error, G_IO_ERROR, error_code, - "Error reading data from pseudo-TCP socket."); - } - - break; - } - - nice_component_emit_io_callback (agent, component, buf, len); - - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) { - nice_debug ("Stream or Component disappeared during the callback"); - goto out; - } - if (pseudo_tcp_socket_is_closed (component->tcp)) { - nice_debug ("PseudoTCP socket got destroyed in readable callback!"); - goto out; - } - - has_io_callback = nice_component_has_io_callback (component); - } while (has_io_callback); - } else if (component->recv_messages != NULL) { - gint n_valid_messages; - GError *child_error = NULL; - - /* Fill up every buffer in every message until the connection closes or an - * error occurs. Copy the data directly into the client’s receive message - * array without making any callbacks. Update component->recv_messages_iter - * as we go. */ - n_valid_messages = pseudo_tcp_socket_recv_messages (sock, - component->recv_messages, component->n_recv_messages, - &component->recv_messages_iter, &child_error); - - nice_debug_verbose ("%s: Client buffers case: Received %d valid messages:", - G_STRFUNC, n_valid_messages); - nice_debug_input_message_composition (component->recv_messages, - component->n_recv_messages); - - if (n_valid_messages < 0) { - g_propagate_error (component->recv_buf_error, child_error); - } else { - g_clear_error (&child_error); - } - - if (n_valid_messages < 0 && - g_error_matches (child_error, G_IO_ERROR, - G_IO_ERROR_WOULD_BLOCK)) { - component->tcp_readable = FALSE; - } else if (n_valid_messages < 0) { - nice_debug ("%s: calling priv_pseudo_tcp_error()", G_STRFUNC); - priv_pseudo_tcp_error (agent, component); - } else if (n_valid_messages == 0) { - /* Reached EOS. */ - component->tcp_readable = FALSE; - pseudo_tcp_socket_close (component->tcp, FALSE); - } - } else { - nice_debug ("%s: no data read", G_STRFUNC); - } - - if (stream && component) - adjust_tcp_clock (agent, stream, component); - -out: - - g_object_unref (agent); -} - -static void -pseudo_tcp_socket_writable (PseudoTcpSocket *sock, gpointer user_data) -{ - NiceComponent *component = user_data; - NiceAgent *agent; - - agent = g_weak_ref_get (&component->agent_ref); - if (agent == NULL) - return; - - nice_debug_verbose ("Agent %p: s%d:%d pseudo Tcp socket writable", agent, - component->stream_id, component->id); - - agent_signal_socket_writable (agent, component); - - g_object_unref (agent); -} - -static void -pseudo_tcp_socket_closed (PseudoTcpSocket *sock, guint32 err, - gpointer user_data) -{ - NiceComponent *component = user_data; - NiceAgent *agent; - - agent = g_weak_ref_get (&component->agent_ref); - if (agent == NULL) - return; - - nice_debug ("Agent %p: s%d:%d pseudo Tcp socket closed. " - "Calling priv_pseudo_tcp_error().", agent, component->stream_id, - component->id); - priv_pseudo_tcp_error (agent, component); - - g_object_unref (agent); -} - - -static PseudoTcpWriteResult -pseudo_tcp_socket_write_packet (PseudoTcpSocket *psocket, - const gchar *buffer, guint32 len, gpointer user_data) -{ - NiceComponent *component = user_data; - NiceAgent *agent; - - agent = g_weak_ref_get (&component->agent_ref); - if (agent == NULL) - return WR_FAIL; - - if (component->selected_pair.local != NULL) { - NiceSocket *sock; - NiceAddress *addr; - - sock = component->selected_pair.local->sockptr; - addr = &component->selected_pair.remote->addr; - - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (addr, tmpbuf); - - nice_debug_verbose ( - "Agent %p : s%d:%d: sending %d bytes on socket %p (FD %d) to [%s]:%d", - agent, component->stream_id, component->id, len, - sock->fileno, g_socket_get_fd (sock->fileno), tmpbuf, - nice_address_get_port (addr)); - } - - /* Send the segment. nice_socket_send() returns 0 on EWOULDBLOCK; in that - * case the segment is not sent on the wire, but we return WR_SUCCESS - * anyway. This effectively drops the segment. The pseudo-TCP state machine - * will eventually pick up this loss and go into recovery mode, reducing - * its transmission rate and, hopefully, the usage of system resources - * which caused the EWOULDBLOCK in the first place. */ - if (nice_socket_send (sock, addr, len, buffer) >= 0) { - g_object_unref (agent); - return WR_SUCCESS; - } - } else { - nice_debug ("%s: WARNING: Failed to send pseudo-TCP packet from agent %p " - "as no pair has been selected yet.", G_STRFUNC, agent); - } - - g_object_unref (agent); - - return WR_FAIL; -} - - -static gboolean -notify_pseudo_tcp_socket_clock_agent_locked (NiceAgent *agent, - gpointer user_data) -{ - NiceComponent *component = user_data; - NiceStream *stream; - - stream = agent_find_stream (agent, component->stream_id); - if (!stream) - return G_SOURCE_REMOVE; - - pseudo_tcp_socket_notify_clock (component->tcp); - adjust_tcp_clock (agent, stream, component); - - return G_SOURCE_CONTINUE; -} - -static void -adjust_tcp_clock (NiceAgent *agent, NiceStream *stream, NiceComponent *component) -{ - if (!pseudo_tcp_socket_is_closed (component->tcp)) { - guint64 timeout = component->last_clock_timeout; - - if (pseudo_tcp_socket_get_next_clock (component->tcp, &timeout)) { - if (timeout != component->last_clock_timeout) { - component->last_clock_timeout = timeout; - if (component->tcp_clock) { - g_source_set_ready_time (component->tcp_clock, timeout * 1000); - } - if (!component->tcp_clock) { - long interval = timeout - (guint32) (g_get_monotonic_time () / 1000); - - /* Prevent integer overflows */ - if (interval < 0 || interval > G_MAXINT) - interval = G_MAXINT; - agent_timeout_add_with_context (agent, &component->tcp_clock, - "Pseudo-TCP clock", interval, - notify_pseudo_tcp_socket_clock_agent_locked, component); - } - } - } else { - nice_debug ("Agent %p: component %d pseudo-TCP socket should be " - "destroyed. Calling priv_pseudo_tcp_error().", - agent, component->id); - priv_pseudo_tcp_error (agent, component); - } - } -} - -void -_tcp_sock_is_writable (NiceSocket *sock, gpointer user_data) -{ - NiceComponent *component = user_data; - NiceAgent *agent; - - agent = g_weak_ref_get (&component->agent_ref); - if (agent == NULL) - return; - - agent_lock (agent); - - /* Don't signal writable if the socket that has become writable is not - * the selected pair */ - if (component->selected_pair.local == NULL || - !nice_socket_is_based_on (component->selected_pair.local->sockptr, sock)) { - agent_unlock (agent); - g_object_unref (agent); - return; - } - - nice_debug ("Agent %p: s%d:%d Tcp socket writable", agent, - component->stream_id, component->id); - agent_signal_socket_writable (agent, component); - - agent_unlock_and_emit (agent); - - g_object_unref (agent); -} - -static const gchar * -_transport_to_string (NiceCandidateTransport type) { - switch(type) { - case NICE_CANDIDATE_TRANSPORT_UDP: - return "UDP"; - case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE: - return "TCP-ACT"; - case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE: - return "TCP-PASS"; - case NICE_CANDIDATE_TRANSPORT_TCP_SO: - return "TCP-SO"; - default: - return "???"; - } -} - -void agent_gathering_done (NiceAgent *agent) -{ - - GSList *i, *j, *k, *l, *m; - - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - - /* We ignore streams not in gathering state, typically already in - * ready state. Such streams may have couples (local,remote) - * candidates that have not resulted in the creation a new pair - * during a previous conncheck session, and we don't want these new - * pairs to be added now, because it would generate unneeded - * transition changes for a stream unconcerned by this gathering. - */ - if (!stream->gathering) - continue; - - for (j = stream->components; j; j = j->next) { - NiceComponent *component = j->data; - - for (k = component->local_candidates; k;) { - NiceCandidate *local_candidate = k->data; - GSList *next = k->next; - - if (agent->force_relay && - local_candidate->type != NICE_CANDIDATE_TYPE_RELAYED) - goto next_cand; - - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (&local_candidate->addr, tmpbuf); - nice_debug ("Agent %p: gathered %s local candidate : [%s]:%u" - " for s%d/c%d. U/P '%s'/'%s'", agent, - _transport_to_string (local_candidate->transport), - tmpbuf, nice_address_get_port (&local_candidate->addr), - local_candidate->stream_id, local_candidate->component_id, - local_candidate->username, local_candidate->password); - } - - /* In addition to not contribute to the creation of a pair in the - * conncheck list, according to RFC 5245, sect. 5.7.3 "Pruning the - * Pairs", it can be guessed from SfB behavior, that server - * reflexive pairs are expected to be also removed from the - * candidates list, when pairs are formed, so they have no way to - * become part of a selected pair with such type. - * - * It can be observed that, each time a valid pair is discovered and - * nominated with a local candidate of type srv-rflx, is makes SfB - * fails with a 500 Internal Error. - * - * On the contrary, when a local srv-rflx candidate is gathered, - * normally announced in the sdp, but removed from the candidate - * list, in that case, when the *same* candidate is discovered again - * later during the conncheck, with peer-rflx type this time, then - * it just works. - */ - - if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2 && - local_candidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE) { - nice_debug ("Agent %p: removing this previous srv-rflx candidate " - "for OC2007R2 compatibility", agent); - component->local_candidates = - g_slist_remove (component->local_candidates, local_candidate); - agent_remove_local_candidate (agent, local_candidate); - nice_candidate_free (local_candidate); - goto next_cand; - } - - for (l = component->remote_candidates; l; l = l->next) { - NiceCandidate *remote_candidate = l->data; - - for (m = stream->conncheck_list; m; m = m->next) { - CandidateCheckPair *p = m->data; - - if (p->local == local_candidate && p->remote == remote_candidate) - break; - } - if (m == NULL) { - conn_check_add_for_candidate_pair (agent, stream->id, component, - local_candidate, remote_candidate); - } - } -next_cand: - k = next; - } - } - } - -#ifdef HAVE_GUPNP - if (agent->discovery_timer_source == NULL && - agent->upnp_timer_source == NULL) { - agent_signal_gathering_done (agent); - } -#else - if (agent->discovery_timer_source == NULL) - agent_signal_gathering_done (agent); -#endif -} - -void agent_signal_gathering_done (NiceAgent *agent) -{ - GSList *i; - - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - if (stream->gathering) { - stream->gathering = FALSE; - agent_queue_signal (agent, signals[SIGNAL_CANDIDATE_GATHERING_DONE], - stream->id); - } - } -} - -void -agent_signal_initial_binding_request_received (NiceAgent *agent, - NiceStream *stream) -{ - if (stream->initial_binding_request_received != TRUE) { - stream->initial_binding_request_received = TRUE; - agent_queue_signal (agent, signals[SIGNAL_INITIAL_BINDING_REQUEST_RECEIVED], - stream->id); - } -} - -/* If the Component now has a selected_pair, and has pending TCP packets which - * it couldn’t receive before due to not being able to send out ACKs (or - * SYNACKs, for the initial SYN packet), handle them now. - * - * Must be called with the agent lock held. */ -static void -process_queued_tcp_packets (NiceAgent *agent, NiceStream *stream, - NiceComponent *component) -{ - GOutputVector *vec; - guint stream_id = stream->id; - guint component_id = component->id; - - g_assert (agent->reliable); - - if (component->selected_pair.local == NULL || - pseudo_tcp_socket_is_closed (component->tcp) || - nice_socket_is_reliable (component->selected_pair.local->sockptr)) { - return; - } - - nice_debug_verbose ("%s: Sending outstanding packets for agent %p.", G_STRFUNC, - agent); - - while ((vec = g_queue_peek_head (&component->queued_tcp_packets)) != NULL) { - gboolean retval; - - nice_debug ("%s: Sending %" G_GSIZE_FORMAT " bytes.", G_STRFUNC, vec->size); - retval = - pseudo_tcp_socket_notify_packet (component->tcp, vec->buffer, - vec->size); - - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) { - nice_debug ("Stream or Component disappeared during " - "pseudo_tcp_socket_notify_packet()"); - return; - } - if (pseudo_tcp_socket_is_closed (component->tcp)) { - nice_debug ("PseudoTCP socket got destroyed in" - " pseudo_tcp_socket_notify_packet()!"); - return; - } - - adjust_tcp_clock (agent, stream, component); - - if (!retval) { - /* Failed to send; try again later. */ - break; - } - - g_queue_pop_head (&component->queued_tcp_packets); - g_free ((gpointer) vec->buffer); - g_slice_free (GOutputVector, vec); - } -} - -void agent_signal_new_selected_pair (NiceAgent *agent, guint stream_id, - guint component_id, NiceCandidate *lcandidate, NiceCandidate *rcandidate) -{ - NiceComponent *component; - NiceStream *stream; - - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) - return; - - if (((NiceSocket *)lcandidate->sockptr)->type == NICE_SOCKET_TYPE_UDP_TURN) { - nice_udp_turn_socket_set_peer (lcandidate->sockptr, &rcandidate->addr); - } - - if(agent->reliable && !nice_socket_is_reliable (lcandidate->sockptr)) { - if (!component->tcp) - pseudo_tcp_socket_create (agent, stream, component); - process_queued_tcp_packets (agent, stream, component); - - pseudo_tcp_socket_connect (component->tcp); - pseudo_tcp_socket_notify_mtu (component->tcp, MAX_TCP_MTU); - adjust_tcp_clock (agent, stream, component); - } - - if (nice_debug_is_enabled ()) { - gchar ip[100]; - guint port; - - port = nice_address_get_port (&lcandidate->addr); - nice_address_to_string (&lcandidate->addr, ip); - - nice_debug ("Agent %p: Local selected pair: %d:%d %s %s %s:%d %s", - agent, stream_id, component_id, lcandidate->foundation, - lcandidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ? - "TCP-ACT" : - lcandidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE ? - "TCP-PASS" : - lcandidate->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "UDP" : "???", - ip, port, lcandidate->type == NICE_CANDIDATE_TYPE_HOST ? "HOST" : - lcandidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ? - "SRV-RFLX" : - lcandidate->type == NICE_CANDIDATE_TYPE_RELAYED ? - "RELAYED" : - lcandidate->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE ? - "PEER-RFLX" : "???"); - - port = nice_address_get_port (&rcandidate->addr); - nice_address_to_string (&rcandidate->addr, ip); - - nice_debug ("Agent %p: Remote selected pair: %d:%d %s %s %s:%d %s", - agent, stream_id, component_id, rcandidate->foundation, - rcandidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ? - "TCP-ACT" : - rcandidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE ? - "TCP-PASS" : - rcandidate->transport == NICE_CANDIDATE_TRANSPORT_UDP ? "UDP" : "???", - ip, port, rcandidate->type == NICE_CANDIDATE_TYPE_HOST ? "HOST" : - rcandidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ? - "SRV-RFLX" : - rcandidate->type == NICE_CANDIDATE_TYPE_RELAYED ? - "RELAYED" : - rcandidate->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE ? - "PEER-RFLX" : "???"); - } - - agent_queue_signal (agent, signals[SIGNAL_NEW_SELECTED_PAIR_FULL], - stream_id, component_id, lcandidate, rcandidate); - agent_queue_signal (agent, signals[SIGNAL_NEW_SELECTED_PAIR], - stream_id, component_id, lcandidate->foundation, rcandidate->foundation); - - if(agent->reliable && nice_socket_is_reliable (lcandidate->sockptr)) { - agent_signal_socket_writable (agent, component); - } -} - -void agent_signal_new_candidate (NiceAgent *agent, NiceCandidate *candidate) -{ - agent_queue_signal (agent, signals[SIGNAL_NEW_CANDIDATE_FULL], - candidate); - agent_queue_signal (agent, signals[SIGNAL_NEW_CANDIDATE], - candidate->stream_id, candidate->component_id, candidate->foundation); -} - -void agent_signal_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate) -{ - agent_queue_signal (agent, signals[SIGNAL_NEW_REMOTE_CANDIDATE_FULL], - candidate); - agent_queue_signal (agent, signals[SIGNAL_NEW_REMOTE_CANDIDATE], - candidate->stream_id, candidate->component_id, candidate->foundation); -} - -NICEAPI_EXPORT const gchar * -nice_component_state_to_string (NiceComponentState state) -{ - switch (state) - { - case NICE_COMPONENT_STATE_DISCONNECTED: - return "disconnected"; - case NICE_COMPONENT_STATE_GATHERING: - return "gathering"; - case NICE_COMPONENT_STATE_CONNECTING: - return "connecting"; - case NICE_COMPONENT_STATE_CONNECTED: - return "connected"; - case NICE_COMPONENT_STATE_READY: - return "ready"; - case NICE_COMPONENT_STATE_FAILED: - return "failed"; - case NICE_COMPONENT_STATE_LAST: - default: - return "invalid"; - } -} - -void agent_signal_component_state_change (NiceAgent *agent, guint stream_id, guint component_id, NiceComponentState new_state) -{ - NiceComponentState old_state; - NiceComponent *component; - NiceStream *stream; - - g_return_if_fail (new_state < NICE_COMPONENT_STATE_LAST); - - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) - return; - - /* Validate the state change. */ - old_state = component->state; - - if (new_state == old_state) { - return; - } - - nice_debug ("Agent %p : stream %u component %u STATE-CHANGE %s -> %s.", agent, - stream_id, component_id, nice_component_state_to_string (old_state), - nice_component_state_to_string (new_state)); - - /* Check whether it’s a valid state transition. */ -#define TRANSITION(OLD, NEW) \ - (old_state == NICE_COMPONENT_STATE_##OLD && \ - new_state == NICE_COMPONENT_STATE_##NEW) - - g_assert (/* Can (almost) always transition to FAILED (including - * DISCONNECTED → FAILED which happens if one component fails - * before another leaves DISCONNECTED): */ - TRANSITION (DISCONNECTED, FAILED) || - TRANSITION (GATHERING, FAILED) || - TRANSITION (CONNECTING, FAILED) || - TRANSITION (CONNECTED, FAILED) || - TRANSITION (READY, FAILED) || - /* Standard progression towards a ready connection: */ - TRANSITION (DISCONNECTED, GATHERING) || - TRANSITION (GATHERING, CONNECTING) || - TRANSITION (CONNECTING, CONNECTED) || - TRANSITION (CONNECTED, READY) || - /* priv_conn_check_add_for_candidate_pair_matched(): */ - TRANSITION (READY, CONNECTED) || - /* If set_remote_candidates() is called with new candidates after - * reaching FAILED: */ - TRANSITION (FAILED, CONNECTING) || - /* if new relay servers are added to a failed connection */ - TRANSITION (FAILED, GATHERING) || - /* Possible by calling set_remote_candidates() without calling - * nice_agent_gather_candidates(): */ - TRANSITION (DISCONNECTED, CONNECTING)); - -#undef TRANSITION - - component->state = new_state; - - if (agent->reliable) - process_queued_tcp_packets (agent, stream, component); - - agent_queue_signal (agent, signals[SIGNAL_COMPONENT_STATE_CHANGED], - stream_id, component_id, new_state); -} - -guint64 -agent_candidate_pair_priority (NiceAgent *agent, NiceCandidate *local, NiceCandidate *remote) -{ - if (agent->controlling_mode) - return nice_candidate_pair_priority (local->priority, remote->priority); - else - return nice_candidate_pair_priority (remote->priority, local->priority); -} - -static void -priv_add_new_candidate_discovery_stun (NiceAgent *agent, - NiceSocket *nicesock, NiceAddress server, - NiceStream *stream, guint component_id) -{ - CandidateDiscovery *cdisco; - - /* note: no need to check for redundant candidates, as this is - * done later on in the process */ - - cdisco = g_slice_new0 (CandidateDiscovery); - - cdisco->type = NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE; - cdisco->nicesock = nicesock; - cdisco->server = server; - cdisco->stream_id = stream->id; - cdisco->component_id = component_id; - stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC3489, - (agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2) ? - STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES : 0); - - nice_debug ("Agent %p : Adding new srv-rflx candidate discovery %p", - agent, cdisco); - - agent->discovery_list = g_slist_append (agent->discovery_list, cdisco); - ++agent->discovery_unsched_items; -} - -NiceSocket * -agent_create_tcp_turn_socket (NiceAgent *agent, NiceStream *stream, - NiceComponent *component, NiceSocket *nicesock, - NiceAddress *server, NiceRelayType type, gboolean reliable_tcp) -{ - NiceAddress proxy_server; - NiceAddress local_address = nicesock->addr; - - nice_address_set_port (&local_address, 0); - nicesock = NULL; - - /* TODO: add support for turn-tcp RFC 6062 */ - if (agent->proxy_type != NICE_PROXY_TYPE_NONE && - agent->proxy_ip != NULL && - nice_address_set_from_string (&proxy_server, agent->proxy_ip)) { - nice_address_set_port (&proxy_server, agent->proxy_port); - nicesock = nice_tcp_bsd_socket_new (agent->main_context, &local_address, - &proxy_server, reliable_tcp); - - if (nicesock) { - _priv_set_socket_tos (agent, nicesock, stream->tos); - if (agent->proxy_type == NICE_PROXY_TYPE_SOCKS5) { - nicesock = nice_socks5_socket_new (nicesock, server, - agent->proxy_username, agent->proxy_password); - } else if (agent->proxy_type == NICE_PROXY_TYPE_HTTP){ - nicesock = nice_http_socket_new (nicesock, server, - agent->proxy_username, agent->proxy_password); - } else { - nice_socket_free (nicesock); - nicesock = NULL; - } - } - } - - if (nicesock == NULL) { - nicesock = nice_tcp_bsd_socket_new (agent->main_context, &local_address, - server, reliable_tcp); - - if (nicesock) - _priv_set_socket_tos (agent, nicesock, stream->tos); - } - - /* The TURN server may be invalid or not listening */ - if (nicesock == NULL) - return NULL; - - nice_socket_set_writable_callback (nicesock, _tcp_sock_is_writable, - component); - - if (type == NICE_RELAY_TYPE_TURN_TLS && - agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - nicesock = nice_pseudossl_socket_new (nicesock, - NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE); - } else if (type == NICE_RELAY_TYPE_TURN_TLS && - (agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2)) { - nicesock = nice_pseudossl_socket_new (nicesock, - NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC); - } - return nice_udp_turn_over_tcp_socket_new (nicesock, - agent_to_turn_socket_compatibility (agent)); -} - -static void -priv_add_new_candidate_discovery_turn (NiceAgent *agent, - NiceSocket *nicesock, TurnServer *turn, - NiceStream *stream, guint component_id, gboolean turn_tcp) -{ - CandidateDiscovery *cdisco; - NiceComponent *component = nice_stream_find_component_by_id (stream, component_id); - - /* note: no need to check for redundant candidates, as this is - * done later on in the process */ - - cdisco = g_slice_new0 (CandidateDiscovery); - cdisco->type = NICE_CANDIDATE_TYPE_RELAYED; - - if (turn->type == NICE_RELAY_TYPE_TURN_UDP) { - if (agent->use_ice_udp == FALSE || turn_tcp == TRUE) { - g_slice_free (CandidateDiscovery, cdisco); - return; - } - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - NiceAddress addr = nicesock->addr; - NiceSocket *new_socket; - nice_address_set_port (&addr, 0); - - new_socket = nice_udp_bsd_socket_new (&addr); - if (new_socket) { - _priv_set_socket_tos (agent, new_socket, stream->tos); - nice_component_attach_socket (component, new_socket); - nicesock = new_socket; - } - } - cdisco->nicesock = nicesock; - } else { - gboolean reliable_tcp = FALSE; - - /* MS-TURN will allocate a transport with the same protocol it received - * the allocate request. So if we are connecting in TCP, then the candidate - * will be TCP-ACT/TCP-PASS which means it will be reliable all the way - * to the peer. - * [MS-TURN] : The transport address has the same transport protocol - * over which the Allocate request was received; a request that is - * received over TCP returns a TCP allocated transport address. - */ - /* TURN-TCP is currently unsupport unless it's OC2007 compatibliity */ - /* TODO: Add support for TURN-TCP */ - if (turn_tcp && - (agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2)) - reliable_tcp = TRUE; - - /* Ignore tcp candidates if we disabled ice-tcp */ - if ((agent->use_ice_udp == FALSE && reliable_tcp == FALSE) || - (agent->use_ice_tcp == FALSE && reliable_tcp == TRUE)) { - g_slice_free (CandidateDiscovery, cdisco); - return; - } - - if (turn_tcp == FALSE) { - g_slice_free (CandidateDiscovery, cdisco); - return; - } - - cdisco->nicesock = agent_create_tcp_turn_socket (agent, stream, - component, nicesock, &turn->server, turn->type, reliable_tcp); - - nice_component_attach_socket (component, cdisco->nicesock); - } - - cdisco->turn = turn_server_ref (turn); - cdisco->server = turn->server; - - cdisco->stream_id = stream->id; - cdisco->component_id = component_id; - - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC3489, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS | - STUN_AGENT_USAGE_IGNORE_CREDENTIALS); - } else if (agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_WLM2009) { - stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC3489, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS); - } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - stun_agent_init (&cdisco->stun_agent, STUN_MSOC_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_OC2007, - STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS | - STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES); - } else { - stun_agent_init (&cdisco->stun_agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC5389, - STUN_AGENT_USAGE_ADD_SOFTWARE | - STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS); - } - stun_agent_set_software (&cdisco->stun_agent, agent->software_attribute); - - nice_debug ("Agent %p : Adding new relay-rflx candidate discovery %p", - agent, cdisco); - agent->discovery_list = g_slist_append (agent->discovery_list, cdisco); - ++agent->discovery_unsched_items; -} - -NICEAPI_EXPORT guint -nice_agent_add_stream ( - NiceAgent *agent, - guint n_components) -{ - NiceStream *stream; - guint ret = 0; - guint i; - - g_return_val_if_fail (NICE_IS_AGENT (agent), 0); - g_return_val_if_fail (n_components >= 1, 0); - - agent_lock (agent); - stream = nice_stream_new (agent->next_stream_id++, n_components, agent); - - agent->streams = g_slist_append (agent->streams, stream); - nice_debug ("Agent %p : allocating stream id %u (%p)", agent, stream->id, stream); - if (agent->reliable) { - nice_debug ("Agent %p : reliable stream", agent); - for (i = 0; i < n_components; i++) { - NiceComponent *component = nice_stream_find_component_by_id (stream, i + 1); - if (component) { - pseudo_tcp_socket_create (agent, stream, component); - } else { - nice_debug ("Agent %p: couldn't find component %d", agent, i+1); - } - } - } - - nice_stream_initialize_credentials (stream, agent->rng); - - ret = stream->id; - - agent_unlock_and_emit (agent); - return ret; -} - - -NICEAPI_EXPORT gboolean -nice_agent_set_relay_info(NiceAgent *agent, - guint stream_id, guint component_id, - const gchar *server_ip, guint server_port, - const gchar *username, const gchar *password, - NiceRelayType type) -{ - - NiceComponent *component = NULL; - NiceStream *stream = NULL; - gboolean ret = TRUE; - TurnServer *turn; - guint length; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id >= 1, FALSE); - g_return_val_if_fail (component_id >= 1, FALSE); - g_return_val_if_fail (server_ip, FALSE); - g_return_val_if_fail (server_port, FALSE); - g_return_val_if_fail (username, FALSE); - g_return_val_if_fail (password, FALSE); - g_return_val_if_fail (type <= NICE_RELAY_TYPE_TURN_TLS, FALSE); - - agent_lock (agent); - - if (!agent_find_component (agent, stream_id, component_id, &stream, - &component)) { - ret = FALSE; - goto done; - } - - length = g_list_length (component->turn_servers); - if (length == NICE_CANDIDATE_MAX_TURN_SERVERS) { - g_warning ("Agent %p : cannot have more than %d turn servers.", - agent, length); - ret = FALSE; - goto done; - } - - turn = turn_server_new (server_ip, server_port, username, password, type); - - if (!turn) { - ret = FALSE; - goto done; - } - - nice_debug ("Agent %p: added relay server [%s]:%d of type %d to s/c %d/%d " - "with user/pass : %s -- %s", agent, server_ip, server_port, type, - stream_id, component_id, username, - nice_debug_is_verbose() ? password : "****"); - - /* The turn server preference (used to setup its priority in the - * conncheck) is simply its position in the list. The preference must - * be unique for each one. - */ - turn->preference = length; - component->turn_servers = g_list_append (component->turn_servers, turn); - - if (stream->gathering_started) { - GSList *i; - - stream->gathering = TRUE; - - for (i = component->local_candidates; i; i = i->next) { - NiceCandidate *candidate = i->data; - - if (candidate->type == NICE_CANDIDATE_TYPE_HOST && - candidate->transport != NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE && - nice_address_ip_version (&candidate->addr) == - nice_address_ip_version (&turn->server)) - priv_add_new_candidate_discovery_turn (agent, - candidate->sockptr, turn, stream, component_id, - candidate->transport != NICE_CANDIDATE_TRANSPORT_UDP); - } - - if (agent->discovery_unsched_items) - discovery_schedule (agent); - } - - - done: - - agent_unlock_and_emit (agent); - return ret; -} - -#ifdef HAVE_GUPNP - -static void agent_check_upnp_gathering_done (NiceAgent *agent); - -static gboolean priv_upnp_timeout_cb_agent_locked (NiceAgent *agent, - gpointer user_data) -{ - nice_debug ("Agent %p : UPnP port mapping timed out", agent); - - /* We cannot free priv->upnp here as it may be holding mappings open which - * we are using (e.g. if some mappings were successful and others errored). */ - g_slist_free_full (agent->upnp_mapping, (GDestroyNotify) nice_address_free); - agent->upnp_mapping = NULL; - - agent_check_upnp_gathering_done (agent); - - return FALSE; -} - -/* Check whether UPnP gathering is done, which is true when the list of pending - * mappings (upnp_mapping) is empty. When it is empty, we have heard back from - * gupnp-igd about each of the mappings we added, either successfully or not. - * - * Note that upnp_mapping has to be a list, rather than a counter, as the - * mapped-external-port and error-mapping-port signals could be emitted multiple - * times for each mapping. */ -static void agent_check_upnp_gathering_done (NiceAgent *agent) -{ - if (agent->upnp_mapping != NULL) - return; - - if (agent->upnp_timer_source != NULL) { - g_source_destroy (agent->upnp_timer_source); - g_source_unref (agent->upnp_timer_source); - agent->upnp_timer_source = NULL; - } - - agent_gathering_done (agent); -} - -static void _upnp_mapped_external_port (GUPnPSimpleIgd *self, gchar *proto, - gchar *external_ip, gchar *replaces_external_ip, guint external_port, - gchar *local_ip, guint local_port, gchar *description, gpointer user_data) -{ - NiceAgent *agent = (NiceAgent*)user_data; - NiceAddress localaddr; - NiceAddress externaddr; - NiceCandidateTransport transport; - GSList *i, *j, *k; - - agent_lock (agent); - - if (agent->upnp_timer_source == NULL) - goto end; - - nice_debug ("Agent %p : Successfully mapped %s:%d to %s:%d", agent, local_ip, - local_port, external_ip, external_port); - - if (!nice_address_set_from_string (&localaddr, local_ip)) - goto end; - nice_address_set_port (&localaddr, local_port); - - if (g_strcmp0 (proto, "TCP") == 0) - transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE; - else - transport = NICE_CANDIDATE_TRANSPORT_UDP; - - for (i = agent->upnp_mapping; i; i = i->next) { - NiceAddress *addr = i->data; - if (nice_address_equal (&localaddr, addr)) { - agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr); - nice_address_free (addr); - break; - } - } - - if (!nice_address_set_from_string (&externaddr, external_ip)) - goto end; - nice_address_set_port (&externaddr, external_port); - - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - for (j = stream->components; j; j = j->next) { - NiceComponent *component = j->data; - for (k = component->local_candidates; k; k = k->next) { - NiceCandidate *local_candidate = k->data; - - if (agent->force_relay && - local_candidate->type != NICE_CANDIDATE_TYPE_RELAYED) - continue; - - if (nice_address_equal (&localaddr, &local_candidate->base_addr)) { - discovery_add_server_reflexive_candidate ( - agent, - stream->id, - component->id, - &externaddr, - transport, - local_candidate->sockptr, - TRUE); - goto end; - } - } - } - } - - end: - agent_check_upnp_gathering_done (agent); - - agent_unlock_and_emit (agent); -} - -static void _upnp_error_mapping_port (GUPnPSimpleIgd *self, GError *error, - gchar *proto, guint external_port, gchar *local_ip, guint local_port, - gchar *description, gpointer user_data) -{ - NiceAgent *agent = (NiceAgent*)user_data; - NiceAddress localaddr; - GSList *i; - - agent_lock (agent); - - nice_debug ("Agent %p : Error mapping %s:%d to %d (%d) : %s", agent, local_ip, - local_port, external_port, error->domain, error->message); - if (nice_address_set_from_string (&localaddr, local_ip)) { - nice_address_set_port (&localaddr, local_port); - - for (i = agent->upnp_mapping; i; i = i->next) { - NiceAddress *addr = i->data; - if (nice_address_equal (&localaddr, addr)) { - agent->upnp_mapping = g_slist_remove (agent->upnp_mapping, addr); - nice_address_free (addr); - break; - } - } - - agent_check_upnp_gathering_done (agent); - } - - agent_unlock_and_emit (agent); -} - -#endif - -NICEAPI_EXPORT gboolean -nice_agent_gather_candidates ( - NiceAgent *agent, - guint stream_id) -{ - guint cid; - GSList *i; - NiceStream *stream; - GSList *local_addresses = NULL; - gboolean ret = TRUE; - guint length; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id >= 1, FALSE); - - agent_lock (agent); - - stream = agent_find_stream (agent, stream_id); - if (stream == NULL) { - agent_unlock_and_emit (agent); - return FALSE; - } - - if (stream->gathering_started) { - /* Stream is already gathering, ignore this call */ - agent_unlock_and_emit (agent); - return TRUE; - } - - nice_debug ("Agent %p : In %s mode, starting candidate gathering.", agent, - agent->full_mode ? "ICE-FULL" : "ICE-LITE"); - -#ifdef HAVE_GUPNP - if (agent->upnp_enabled && agent->upnp == NULL && !agent->force_relay) { - agent->upnp = gupnp_simple_igd_thread_new (); - - if (agent->upnp) { - g_signal_connect (agent->upnp, "mapped-external-port", - G_CALLBACK (_upnp_mapped_external_port), agent); - g_signal_connect (agent->upnp, "error-mapping-port", - G_CALLBACK (_upnp_error_mapping_port), agent); - } else { - nice_debug ("Agent %p : Error creating UPnP Simple IGD agent", agent); - } - } else { - nice_debug ("Agent %p : UPnP property Disabled", agent); - } -#else - nice_debug ("Agent %p : libnice compiled without UPnP support", agent); -#endif - - /* if no local addresses added, generate them ourselves */ - if (agent->local_addresses == NULL) { - GList *addresses = nice_interfaces_get_local_ips (FALSE); - GList *item; - - for (item = addresses; item; item = g_list_next (item)) { - const gchar *addr_string = item->data; - NiceAddress *addr = nice_address_new (); - - if (nice_address_set_from_string (addr, addr_string)) { - local_addresses = g_slist_append (local_addresses, addr); - } else { - nice_debug ("Error: Failed to parse local address ‘%s’.", addr_string); - nice_address_free (addr); - } - } - - g_list_free_full (addresses, (GDestroyNotify) g_free); - } else { - for (i = agent->local_addresses; i; i = i->next) { - NiceAddress *addr = i->data; - NiceAddress *dupaddr = nice_address_dup (addr); - - local_addresses = g_slist_append (local_addresses, dupaddr); - } - } - - length = g_slist_length (local_addresses); - if (length > NICE_CANDIDATE_MAX_LOCAL_ADDRESSES) { - g_warning ("Agent %p : cannot have more than %d local addresses.", - agent, NICE_CANDIDATE_MAX_LOCAL_ADDRESSES); - } - - for (cid = 1; cid <= stream->n_components; cid++) { - NiceComponent *component = nice_stream_find_component_by_id (stream, cid); - gboolean found_local_address = FALSE; - enum { - ADD_HOST_MIN = 0, - ADD_HOST_UDP = ADD_HOST_MIN, - ADD_HOST_TCP_ACTIVE, - ADD_HOST_TCP_PASSIVE, - ADD_HOST_MAX = ADD_HOST_TCP_PASSIVE - } add_type; - - if (component == NULL) - continue; - - /* generate a local host candidate for each local address */ - length = 0; - for (i = local_addresses; - i && length < NICE_CANDIDATE_MAX_LOCAL_ADDRESSES; - i = i->next, length++) { - NiceAddress *addr = i->data; - NiceCandidate *host_candidate; - -#ifdef HAVE_GUPNP - gchar local_ip[NICE_ADDRESS_STRING_LEN]; - nice_address_to_string (addr, local_ip); -#endif - - for (add_type = ADD_HOST_MIN; add_type <= ADD_HOST_MAX; add_type++) { - NiceCandidateTransport transport; - guint current_port; - guint start_port; - HostCandidateResult res = HOST_CANDIDATE_CANT_CREATE_SOCKET; - - if ((agent->use_ice_udp == FALSE && add_type == ADD_HOST_UDP) || - (agent->use_ice_tcp == FALSE && add_type != ADD_HOST_UDP)) - continue; - - switch (add_type) { - default: - case ADD_HOST_UDP: - transport = NICE_CANDIDATE_TRANSPORT_UDP; - break; - case ADD_HOST_TCP_ACTIVE: - transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; - break; - case ADD_HOST_TCP_PASSIVE: - transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE; - break; - } - - start_port = component->min_port; - if(component->min_port != 0) { - start_port = nice_rng_generate_int(agent->rng, component->min_port, component->max_port+1); - } - current_port = start_port; - - host_candidate = NULL; - while (res == HOST_CANDIDATE_CANT_CREATE_SOCKET || - res == HOST_CANDIDATE_DUPLICATE_PORT) { - nice_debug ("Agent %p: Trying to create host candidate on port %d", agent, current_port); - nice_address_set_port (addr, current_port); - res = discovery_add_local_host_candidate (agent, stream->id, cid, - addr, transport, &host_candidate); - if (current_port > 0) - current_port++; - if (current_port > component->max_port) - current_port = component->min_port; - if (current_port == start_port && res != HOST_CANDIDATE_DUPLICATE_PORT) - break; - if (current_port == 0 && res != HOST_CANDIDATE_DUPLICATE_PORT) - break; - } - - if (res == HOST_CANDIDATE_REDUNDANT) { - nice_debug ("Agent %p: Ignoring local candidate, it's redundant", - agent); - continue; - } else if (res == HOST_CANDIDATE_FAILED) { - nice_debug ("Agent %p: Could not retrieve component %d/%d", agent, - stream->id, cid); - continue; - } else if (res == HOST_CANDIDATE_CANT_CREATE_SOCKET) { - if (nice_debug_is_enabled ()) { - gchar ip[NICE_ADDRESS_STRING_LEN]; - nice_address_to_string (addr, ip); - nice_debug ("Agent %p: Unable to add local host candidate %s for" - " s%d:%d. Invalid interface?", agent, ip, stream->id, - component->id); - } - continue; - } else if (res == HOST_CANDIDATE_DUPLICATE_PORT) { - nice_debug ("Agent %p: Ignoring local candidate, duplicate port", - agent); - continue; - } - - found_local_address = TRUE; - nice_address_set_port (addr, 0); - - nice_socket_set_writable_callback (host_candidate->sockptr, - _tcp_sock_is_writable, component); - -#ifdef HAVE_GUPNP - if (agent->upnp_enabled && agent->upnp && - transport != NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) { - NiceAddress *base_addr = nice_address_dup (&host_candidate->base_addr); - nice_debug ("Agent %p: Adding UPnP port %s:%d", agent, local_ip, - nice_address_get_port (base_addr)); - gupnp_simple_igd_add_port (GUPNP_SIMPLE_IGD (agent->upnp), - transport == NICE_CANDIDATE_TRANSPORT_UDP ? "UDP" : "TCP", - 0, local_ip, nice_address_get_port (base_addr), - 0, PACKAGE_STRING); - agent->upnp_mapping = g_slist_prepend (agent->upnp_mapping, base_addr); - - agent_timeout_add_with_context (agent, &agent->upnp_timer_source, - "UPnP timeout", agent->upnp_timeout, - priv_upnp_timeout_cb_agent_locked, agent); - } -#endif - - /* TODO: Add server-reflexive support for TCP candidates */ - if (agent->full_mode && agent->stun_server_ip && !agent->force_relay && - transport == NICE_CANDIDATE_TRANSPORT_UDP) { - NiceAddress stun_server; - if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) { - nice_address_set_port (&stun_server, agent->stun_server_port); - - if (nice_address_ip_version (&host_candidate->addr) == - nice_address_ip_version (&stun_server)) - priv_add_new_candidate_discovery_stun (agent, - host_candidate->sockptr, - stun_server, - stream, - cid); - } - } - - if (agent->full_mode && component && - transport != NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) { - GList *item; - int host_ip_version = nice_address_ip_version (&host_candidate->addr); - - for (item = component->turn_servers; item; item = item->next) { - TurnServer *turn = item->data; - - if (host_ip_version != nice_address_ip_version (&turn->server)) { - continue; - } - - priv_add_new_candidate_discovery_turn (agent, - host_candidate->sockptr, - turn, - stream, - cid, - host_candidate->transport != NICE_CANDIDATE_TRANSPORT_UDP); - } - } - } - } - /* Go to error if we could not find a local address for a given - * component - */ - if (!found_local_address) { - ret = FALSE; - goto error; - } - } - - stream->gathering = TRUE; - stream->gathering_started = TRUE; - - /* Only signal the new candidates after we're sure that the gathering was - * succesfful. But before sending gathering-done */ - for (cid = 1; cid <= stream->n_components; cid++) { - NiceComponent *component = nice_stream_find_component_by_id (stream, cid); - for (i = component->local_candidates; i; i = i->next) { - NiceCandidate *candidate = i->data; - - if (agent->force_relay && candidate->type != NICE_CANDIDATE_TYPE_RELAYED) - continue; - - agent_signal_new_candidate (agent, candidate); - } - } - - /* note: no async discoveries pending, signal that we are ready */ - if (agent->discovery_unsched_items == 0 && -#ifdef HAVE_GUPNP - agent->upnp_mapping == NULL) { -#else - TRUE) { -#endif - nice_debug ("Agent %p: Candidate gathering FINISHED, no scheduled items.", - agent); - agent_gathering_done (agent); - } else if (agent->discovery_unsched_items) { - discovery_schedule (agent); - } - - error: - for (i = local_addresses; i; i = i->next) - nice_address_free (i->data); - g_slist_free (local_addresses); - - if (ret == FALSE) { - priv_stop_upnp (agent); - for (cid = 1; cid <= stream->n_components; cid++) { - NiceComponent *component = nice_stream_find_component_by_id (stream, cid); - - nice_component_free_socket_sources (component); - - for (i = component->local_candidates; i; i = i->next) { - NiceCandidate *candidate = i->data; - - agent_remove_local_candidate (agent, candidate); - - nice_candidate_free (candidate); - } - g_slist_free (component->local_candidates); - component->local_candidates = NULL; - } - discovery_prune_stream (agent, stream_id); - } - - agent_unlock_and_emit (agent); - - return ret; -} - -void agent_remove_local_candidate (NiceAgent *agent, NiceCandidate *candidate) -{ -#ifdef HAVE_GUPNP - gchar local_ip[NICE_ADDRESS_STRING_LEN]; - - if (agent->upnp == NULL) - return; - - if (candidate->type != NICE_CANDIDATE_TYPE_HOST) - return; - - if (nice_address_get_port (&candidate->addr) == 0) - return; - - nice_address_to_string (&candidate->addr, local_ip); - - gupnp_simple_igd_remove_port_local (GUPNP_SIMPLE_IGD (agent->upnp), "UDP", - local_ip, nice_address_get_port (&candidate->addr)); -#endif -} - -static void priv_stop_upnp (NiceAgent *agent) -{ -#ifdef HAVE_GUPNP - if (!agent->upnp) - return; - - g_slist_free_full (agent->upnp_mapping, (GDestroyNotify) nice_address_free); - agent->upnp_mapping = NULL; - - if (agent->upnp_timer_source != NULL) { - g_source_destroy (agent->upnp_timer_source); - g_source_unref (agent->upnp_timer_source); - agent->upnp_timer_source = NULL; - } -#endif -} - -static void priv_remove_keepalive_timer (NiceAgent *agent) -{ - if (agent->keepalive_timer_source != NULL) { - g_source_destroy (agent->keepalive_timer_source); - g_source_unref (agent->keepalive_timer_source); - agent->keepalive_timer_source = NULL; - } -} - -static gboolean -on_stream_refreshes_pruned (NiceAgent *agent, NiceStream *stream) -{ - // This is called from a timeout cb with agent lock held - - nice_stream_close (agent, stream); - - agent->pruning_streams = g_slist_remove (agent->pruning_streams, stream); - - agent_unlock (agent); - - /* Actually free the stream. This should be done with the lock released, as - * it could end up disposing of a NiceIOStream, which tries to take the - * agent lock itself. */ - g_object_unref (stream); - - agent_lock (agent); - - return G_SOURCE_REMOVE; -} - -NICEAPI_EXPORT void -nice_agent_remove_stream ( - NiceAgent *agent, - guint stream_id) -{ - guint stream_ids[] = { stream_id, 0 }; - - /* note that streams/candidates can be in use by other threads */ - - NiceStream *stream; - - g_return_if_fail (NICE_IS_AGENT (agent)); - g_return_if_fail (stream_id >= 1); - - agent_lock (agent); - stream = agent_find_stream (agent, stream_id); - - if (!stream) { - agent_unlock_and_emit (agent); - return; - } - - /* note: remove items with matching stream_ids from both lists */ - conn_check_prune_stream (agent, stream); - discovery_prune_stream (agent, stream_id); - refresh_prune_stream_async (agent, stream, - (NiceTimeoutLockedCallback) on_stream_refreshes_pruned); - - agent->pruning_streams = g_slist_prepend (agent->pruning_streams, stream); - - /* Remove the stream and signal its removal. */ - agent->streams = g_slist_remove (agent->streams, stream); - - if (!agent->streams) - priv_remove_keepalive_timer (agent); - - agent_queue_signal (agent, signals[SIGNAL_STREAMS_REMOVED], - g_memdup (stream_ids, sizeof(stream_ids))); - - agent_unlock_and_emit (agent); -} - -NICEAPI_EXPORT void -nice_agent_set_port_range (NiceAgent *agent, guint stream_id, guint component_id, - guint min_port, guint max_port) -{ - NiceStream *stream; - NiceComponent *component; - - g_return_if_fail (NICE_IS_AGENT (agent)); - g_return_if_fail (stream_id >= 1); - g_return_if_fail (component_id >= 1); - - agent_lock (agent); - - if (agent_find_component (agent, stream_id, component_id, &stream, - &component)) { - if (stream->gathering_started) { - g_critical ("nice_agent_gather_candidates (stream_id=%u) already called for this stream", stream_id); - } else { - component->min_port = min_port; - component->max_port = max_port; - } - } - - agent_unlock_and_emit (agent); -} - -NICEAPI_EXPORT gboolean -nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr) -{ - NiceAddress *dupaddr; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (addr != NULL, FALSE); - - agent_lock (agent); - - dupaddr = nice_address_dup (addr); - nice_address_set_port (dupaddr, 0); - agent->local_addresses = g_slist_append (agent->local_addresses, dupaddr); - - agent_unlock_and_emit (agent); - return TRUE; -} - -/* Recompute foundations of all candidate pairs from a given stream - * having a specific remote candidate, and eventually update the - * priority of the selected pair as well. - */ -static void priv_update_pair_foundations (NiceAgent *agent, - guint stream_id, guint component_id, NiceCandidate *remote) -{ - NiceStream *stream; - NiceComponent *component; - - if (agent_find_component (agent, stream_id, component_id, &stream, - &component)) { - GSList *i; - - for (i = stream->conncheck_list; i; i = i->next) { - CandidateCheckPair *pair = i->data; - - if (pair->remote == remote) { - gchar foundation[NICE_CANDIDATE_PAIR_MAX_FOUNDATION]; - g_snprintf (foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s", - pair->local->foundation, pair->remote->foundation); - if (strncmp (pair->foundation, foundation, - NICE_CANDIDATE_PAIR_MAX_FOUNDATION)) { - g_strlcpy (pair->foundation, foundation, - NICE_CANDIDATE_PAIR_MAX_FOUNDATION); - nice_debug ("Agent %p : Updating pair %p foundation to '%s'", - agent, pair, pair->foundation); - if (pair->state == NICE_CHECK_SUCCEEDED) - conn_check_unfreeze_related (agent, pair); - if (component->selected_pair.local == pair->local && - component->selected_pair.remote == pair->remote) { - gchar priority[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE]; - - /* the foundation update of the selected pair also implies - * an update of its priority. stun_priority doesn't change - * because only the remote candidate foundation is modified. - */ - nice_debug ("Agent %p : pair %p is the selected pair, updating " - "its priority.", agent, pair); - component->selected_pair.priority = pair->priority; - - nice_candidate_pair_priority_to_string (pair->priority, priority); - nice_debug ("Agent %p : updating SELECTED PAIR for component " - "%u: %s (prio:%s).", agent, - component->id, foundation, priority); - agent_signal_new_selected_pair (agent, pair->stream_id, - component->id, pair->local, pair->remote); - } - } - } - } - } -} - -/* Returns the nominated pair with the highest priority. - */ -static CandidateCheckPair *priv_get_highest_priority_nominated_pair ( - NiceAgent *agent, guint stream_id, guint component_id) -{ - NiceStream *stream; - NiceComponent *component; - CandidateCheckPair *pair; - GSList *i; - - if (agent_find_component (agent, stream_id, component_id, &stream, - &component)) { - - for (i = stream->conncheck_list; i; i = i->next) { - pair = i->data; - if (pair->component_id == component_id && pair->nominated) { - return pair; - } - } - } - return NULL; -} - -static gboolean priv_add_remote_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceCandidateType type, - const NiceAddress *addr, - const NiceAddress *base_addr, - NiceCandidateTransport transport, - guint32 priority, - const gchar *username, - const gchar *password, - const gchar *foundation) -{ - NiceStream *stream; - NiceComponent *component; - NiceCandidate *candidate; - CandidateCheckPair *pair; - - if (transport == NICE_CANDIDATE_TRANSPORT_UDP && - !agent->use_ice_udp) - return FALSE; - if (transport != NICE_CANDIDATE_TRANSPORT_UDP && - !agent->use_ice_tcp) - return FALSE; - - if (!agent_find_component (agent, stream_id, component_id, &stream, - &component)) - return FALSE; - - /* step: check whether the candidate already exists */ - candidate = nice_component_find_remote_candidate (component, addr, transport); - - /* If it was a discovered remote peer reflexive candidate, then it should - * be updated according to RFC 5245 section 7.2.1.3 */ - if (candidate && candidate->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) { - nice_debug ("Agent %p : Updating existing peer-rfx remote candidate to %s", - agent, _cand_type_to_sdp (type)); - candidate->type = type; - /* The updated candidate is no more peer reflexive, so its - * sockptr can be cleared - */ - candidate->sockptr = NULL; - /* If it got there, the next one will also be ran, so the foundation - * will be set. - */ - } - - if (candidate && candidate->type == type) { - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (addr, tmpbuf); - nice_debug ("Agent %p : Updating existing remote candidate with addr [%s]:%u" - " for s%d/c%d. U/P '%s'/'%s' prio: %08x", agent, tmpbuf, - nice_address_get_port (addr), stream_id, component_id, - username, password, priority); - } - /* case 1: an existing candidate, update the attributes */ - if (base_addr) - candidate->base_addr = *base_addr; - candidate->priority = priority; - if (foundation) - g_strlcpy(candidate->foundation, foundation, - NICE_CANDIDATE_MAX_FOUNDATION); - /* note: username and password must remain the same during - * a session; see sect 9.1.2 in ICE ID-19 */ - - /* note: however, the user/pass in ID-19 is global, if the user/pass - * are set in the candidate here, it means they need to be updated... - * this is essential to overcome a race condition where we might receive - * a valid binding request from a valid candidate that wasn't yet added to - * our list of candidates.. this 'update' will make the peer-rflx a - * server-rflx/host candidate again */ - if (username) { - if (candidate->username == NULL) - candidate->username = g_strdup (username); - else if (g_strcmp0 (username, candidate->username)) - nice_debug ("Agent %p : Candidate username '%s' is not allowed " - "to change to '%s' now (ICE restart only).", agent, - candidate->username, username); - } - if (password) { - if (candidate->password == NULL) - candidate->password = g_strdup (password); - else if (g_strcmp0 (password, candidate->password)) - nice_debug ("Agent %p : candidate password '%s' is not allowed " - "to change to '%s' now (ICE restart only).", agent, - candidate->password, password); - } - - /* since the type of the existing candidate may have changed, - * the pairs priority and foundation related to this candidate need - * to be recomputed... - */ - recalculate_pair_priorities (agent); - priv_update_pair_foundations (agent, stream_id, component_id, candidate); - /* ... and maybe we now have another nominated pair with a higher - * priority as the result of this priorities update. - */ - pair = priv_get_highest_priority_nominated_pair (agent, - stream_id, component_id); - if (pair && - (pair->local != component->selected_pair.local || - pair->remote != component->selected_pair.remote)) { - /* If we have (at least) one pair with the nominated flag set, it - * implies that this pair (or another) is set as the selected pair - * for this component. In other words, this is really an *update* - * of the selected pair. - */ - g_assert (component->selected_pair.local != NULL); - g_assert (component->selected_pair.remote != NULL); - nice_debug ("Agent %p : Updating selected pair with higher " - "priority nominated pair %p.", agent, pair); - conn_check_update_selected_pair (agent, component, pair); - } - conn_check_update_check_list_state_for_ready (agent, stream, component); - } - else { - /* case 2: add a new candidate */ - - if (type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) { - nice_debug("Agent %p : Warning: ignoring externally set peer-reflexive candidate!", agent); - return FALSE; - } - candidate = nice_candidate_new (type); - - candidate->stream_id = stream_id; - candidate->component_id = component_id; - - candidate->type = type; - if (addr) - candidate->addr = *addr; - - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN] = {0}; - if (addr) - nice_address_to_string (addr, tmpbuf); - nice_debug ("Agent %p : Adding %s remote candidate with addr [%s]:%u" - " for s%d/c%d. U/P '%s'/'%s' prio: %08x", agent, - _transport_to_string (transport), tmpbuf, - addr? nice_address_get_port (addr) : 0, stream_id, component_id, - username, password, priority); - } - - if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) { - /* note: If there are TCP candidates for a media stream, - * a controlling agent MUST use the regular selection algorithm, - * RFC 6544, sect 8, "Concluding ICE Processing" - */ - if (agent->controlling_mode && - agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE && - transport != NICE_CANDIDATE_TRANSPORT_UDP) { - if (conn_check_stun_transactions_count (agent) > 0) { - /* changing nomination mode from aggressive to regular while - * conncheck is ongoing may cause unexpected results (inflight - * aggressive stun requests may nominate a pair unilaterally) - */ - nice_debug ("Agent %p : we have a TCP candidate, but conncheck " - "has started already in aggressive mode, ignore it", agent); - goto errors; - } else { - nice_debug ("Agent %p : we have a TCP candidate, switching back " - "to regular nomination mode", agent); - agent->nomination_mode = NICE_NOMINATION_MODE_REGULAR; - } - } - } - - if (base_addr) - candidate->base_addr = *base_addr; - - candidate->transport = transport; - candidate->priority = priority; - candidate->username = g_strdup (username); - candidate->password = g_strdup (password); - - if (foundation) - g_strlcpy (candidate->foundation, foundation, - NICE_CANDIDATE_MAX_FOUNDATION); - - /* We only create a pair when a candidate is new, and not when - * updating an existing one. - */ - if (conn_check_add_for_candidate (agent, stream_id, - component, candidate) < 0) - goto errors; - - component->remote_candidates = g_slist_append (component->remote_candidates, - candidate); - } - return TRUE; - -errors: - nice_candidate_free (candidate); - return FALSE; -} - -NICEAPI_EXPORT gboolean -nice_agent_set_remote_credentials ( - NiceAgent *agent, - guint stream_id, - const gchar *ufrag, const gchar *pwd) -{ - NiceStream *stream; - gboolean ret = FALSE; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id >= 1, FALSE); - - nice_debug ("Agent %p: set_remote_credentials %d", agent, stream_id); - - agent_lock (agent); - - stream = agent_find_stream (agent, stream_id); - /* note: oddly enough, ufrag and pwd can be empty strings */ - if (stream && ufrag && pwd) { - - g_strlcpy (stream->remote_ufrag, ufrag, NICE_STREAM_MAX_UFRAG); - g_strlcpy (stream->remote_password, pwd, NICE_STREAM_MAX_PWD); - - conn_check_remote_credentials_set(agent, stream); - - ret = TRUE; - goto done; - } - - done: - agent_unlock_and_emit (agent); - return ret; -} - -NICEAPI_EXPORT gboolean -nice_agent_set_local_credentials ( - NiceAgent *agent, - guint stream_id, - const gchar *ufrag, - const gchar *pwd) -{ - NiceStream *stream; - gboolean ret = FALSE; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id >= 1, FALSE); - - agent_lock (agent); - - stream = agent_find_stream (agent, stream_id); - - /* note: oddly enough, ufrag and pwd can be empty strings */ - if (stream && ufrag && pwd) { - g_strlcpy (stream->local_ufrag, ufrag, NICE_STREAM_MAX_UFRAG); - g_strlcpy (stream->local_password, pwd, NICE_STREAM_MAX_PWD); - - ret = TRUE; - goto done; - } - - done: - agent_unlock_and_emit (agent); - return ret; -} - - -NICEAPI_EXPORT gboolean -nice_agent_get_local_credentials ( - NiceAgent *agent, - guint stream_id, - gchar **ufrag, gchar **pwd) -{ - NiceStream *stream; - gboolean ret = TRUE; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id >= 1, FALSE); - - agent_lock (agent); - - stream = agent_find_stream (agent, stream_id); - if (stream == NULL) { - goto done; - } - - if (!ufrag || !pwd) { - goto done; - } - - *ufrag = g_strdup (stream->local_ufrag); - *pwd = g_strdup (stream->local_password); - ret = TRUE; - - done: - - agent_unlock_and_emit (agent); - return ret; -} - -static int -_set_remote_candidates_locked (NiceAgent *agent, NiceStream *stream, - NiceComponent *component, const GSList *candidates) -{ - const GSList *i; - int added = 0; - - for (i = candidates; i && added >= 0; i = i->next) { - NiceCandidate *d = (NiceCandidate*) i->data; - - if (nice_address_is_valid (&d->addr) == TRUE) { - gboolean res = - priv_add_remote_candidate (agent, - stream->id, - component->id, - d->type, - &d->addr, - &d->base_addr, - d->transport, - d->priority, - d->username, - d->password, - d->foundation); - if (res) - ++added; - } - } - - if (added > 0) { - conn_check_remote_candidates_set(agent, stream, component); - conn_check_schedule_next (agent); - } - - return added; -} - - -NICEAPI_EXPORT int -nice_agent_set_remote_candidates (NiceAgent *agent, guint stream_id, guint component_id, const GSList *candidates) -{ - int added = 0; - NiceStream *stream; - NiceComponent *component; - - g_return_val_if_fail (NICE_IS_AGENT (agent), 0); - g_return_val_if_fail (stream_id >= 1, 0); - g_return_val_if_fail (component_id >= 1, 0); - - nice_debug ("Agent %p: set_remote_candidates %d %d", agent, stream_id, component_id); - - agent_lock (agent); - - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) { - g_warning ("Could not find component %u in stream %u", component_id, - stream_id); - added = -1; - goto done; - } - - added = _set_remote_candidates_locked (agent, stream, component, candidates); - - done: - agent_unlock_and_emit (agent); - - return added; -} - -/* Return values for agent_recv_message_unlocked(). Needed purely because it - * must differentiate between RECV_OOB and RECV_SUCCESS. */ -typedef enum { - RECV_ERROR = -2, - RECV_WOULD_BLOCK = -1, - RECV_OOB = 0, - RECV_SUCCESS = 1, -} RecvStatus; - -/* - * agent_recv_message_unlocked: - * @agent: a #NiceAgent - * @stream: the stream to receive from - * @component: the component to receive from - * @socket: the socket to receive on - * @message: the message to write into (must have at least 65536 bytes of buffer - * space) - * - * Receive a single message of data from the given @stream, @component and - * @socket tuple, in a non-blocking fashion. The caller must ensure that - * @message contains enough buffers to provide at least 65536 bytes of buffer - * space, but the buffers may be split as the caller sees fit. - * - * This must be called with the agent’s lock held. - * - * Returns: number of valid messages received on success (i.e. %RECV_SUCCESS or - * 1), %RECV_OOB if data was successfully received but was handled out-of-band - * (e.g. due to being a STUN control packet), %RECV_WOULD_BLOCK if no data is - * available and the call would block, or %RECV_ERROR on error - */ -static RecvStatus -agent_recv_message_unlocked ( - NiceAgent *agent, - NiceStream *stream, - NiceComponent *component, - NiceSocket *nicesock, - NiceInputMessage *message) -{ - NiceAddress from; - GList *item; - RecvStatus retval; - gint sockret; - gboolean is_turn = FALSE; - - /* We need an address for packet parsing, below. */ - if (message->from == NULL) { - message->from = &from; - } - - /* ICE-TCP requires that all packets be framed with RFC4571 */ - if (nice_socket_is_reliable (nicesock)) { - /* In the case of OC2007 and OC2007R2 which uses UDP TURN for TCP-ACTIVE - * and TCP-PASSIVE candidates, the recv_messages will be packetized and - * always return an entire frame, so we must read it as is */ - if (nicesock->type == NICE_SOCKET_TYPE_UDP_TURN_OVER_TCP || - nicesock->type == NICE_SOCKET_TYPE_UDP_TURN) { - GSList *cand_i; - GInputVector *local_bufs; - NiceInputMessage local_message; - guint n_bufs = 0; - guint16 rfc4571_frame; - guint i; - - /* In case of ICE-TCP on UDP-TURN (OC2007 compat), we need to do the recv - * on the UDP_TURN socket, but it's possible we receive the source event - * on the UDP_TURN_OVER_TCP socket, so in that case, we need to replace - * the socket we do the recv on to the topmost socket - */ - for (cand_i = component->local_candidates; cand_i; cand_i = cand_i->next) { - NiceCandidate *cand = cand_i->data; - - if (cand->type == NICE_CANDIDATE_TYPE_RELAYED && - cand->stream_id == stream->id && - cand->component_id == component->id && - nice_socket_is_based_on(cand->sockptr, nicesock)) { - nice_debug ("Agent %p : Packet received from a TURN socket.", - agent); - nicesock = cand->sockptr; - break; - } - } - /* Count the number of buffers. */ - if (message->n_buffers == -1) { - for (i = 0; message->buffers[i].buffer != NULL; i++) - n_bufs++; - } else { - n_bufs = message->n_buffers; - } - - local_bufs = g_alloca ((n_bufs + 1) * sizeof (GInputVector)); - local_message.buffers = local_bufs; - local_message.n_buffers = n_bufs + 1; - local_message.from = message->from; - local_message.length = 0; - - local_bufs[0].buffer = &rfc4571_frame; - local_bufs[0].size = sizeof (guint16); - - for (i = 0; i < n_bufs; i++) { - local_bufs[i + 1].buffer = message->buffers[i].buffer; - local_bufs[i + 1].size = message->buffers[i].size; - } - sockret = nice_socket_recv_messages (nicesock, &local_message, 1); - if (sockret == 1 && local_message.length >= sizeof (guint16)) { - message->length = ntohs (rfc4571_frame); - } - } else { - if (nicesock->type == NICE_SOCKET_TYPE_TCP_PASSIVE) { - NiceSocket *new_socket; - - /* Passive candidates when readable should accept and create a new - * socket. When established, the connchecks will create a peer reflexive - * candidate for it */ - new_socket = nice_tcp_passive_socket_accept (nicesock); - if (new_socket) { - _priv_set_socket_tos (agent, new_socket, stream->tos); - nice_debug ("Agent %p: add to tcp-pass socket %p a new " - "tcp accept socket %p in s/c %d/%d", - agent, nicesock, new_socket, stream->id, component->id); - nice_component_attach_socket (component, new_socket); - } - sockret = 0; - } else { - /* In the case of a real ICE-TCP connection, we can use the socket as a - * bytestream and do the read here with caching of data being read - */ - gssize available = g_socket_get_available_bytes (nicesock->fileno); - - /* TODO: Support bytestream reads */ - message->length = 0; - sockret = 0; - if (available <= 0) { - sockret = available; - - /* If we don't call check_connect_result on an outbound connection, - * then is_connected will always return FALSE. That's why we check - * both conditions to make sure g_socket_is_connected returns the - * correct result, otherwise we end up closing valid connections - */ - if (g_socket_check_connect_result (nicesock->fileno, NULL) == FALSE || - g_socket_is_connected (nicesock->fileno) == FALSE) { - /* If we receive a readable event on a TCP_BSD socket which is - * not connected, it means that it failed to connect, so we must - * return an error to make the socket fail/closed - */ - sockret = -1; - } else { - gint flags = G_SOCKET_MSG_PEEK; - - /* If available bytes are 0, but the socket is still considered - * connected, then either we're just trying to see if there's more - * data available or the peer closed the connection. - * The only way to know is to do a read, so we do here a peek and - * check the return value, if it's 0, it means the peer has closed - * the connection, so we must return an error instead of WOULD_BLOCK - */ - if (g_socket_receive_message (nicesock->fileno, NULL, - NULL, 0, NULL, NULL, &flags, NULL, NULL) == 0) - sockret = -1; - } - } else if (agent->rfc4571_expecting_length == 0) { - if ((gsize) available >= sizeof(guint16)) { - guint16 rfc4571_frame; - GInputVector local_buf = { &rfc4571_frame, sizeof(guint16)}; - NiceInputMessage local_message = { &local_buf, 1, message->from, 0}; - - sockret = nice_socket_recv_messages (nicesock, &local_message, 1); - if (sockret == 1 && local_message.length >= sizeof (guint16)) { - agent->rfc4571_expecting_length = ntohs (rfc4571_frame); - available = g_socket_get_available_bytes (nicesock->fileno); - } - } - } - if (agent->rfc4571_expecting_length > 0 && - available >= agent->rfc4571_expecting_length) { - GInputVector *local_bufs; - NiceInputMessage local_message; - gsize off; - guint n_bufs = 0; - guint i; - - /* Count the number of buffers. */ - if (message->n_buffers == -1) { - for (i = 0; message->buffers[i].buffer != NULL; i++) - n_bufs++; - } else { - n_bufs = message->n_buffers; - } - - local_bufs = g_alloca (n_bufs * sizeof (GInputVector)); - local_message.buffers = local_bufs; - local_message.from = message->from; - local_message.length = 0; - local_message.n_buffers = 0; - - /* Only read up to the expected number of bytes in the frame */ - off = 0; - for (i = 0; i < n_bufs; i++) { - if (message->buffers[i].size < agent->rfc4571_expecting_length - off) { - local_bufs[i].buffer = message->buffers[i].buffer; - local_bufs[i].size = message->buffers[i].size; - local_message.n_buffers++; - off += message->buffers[i].size; - } else { - local_bufs[i].buffer = message->buffers[i].buffer; - local_bufs[i].size = MIN (message->buffers[i].size, - agent->rfc4571_expecting_length - off); - local_message.n_buffers++; - off += local_bufs[i].size; - } - } - sockret = nice_socket_recv_messages (nicesock, &local_message, 1); - if (sockret == 1) { - message->length = local_message.length; - agent->rfc4571_expecting_length -= local_message.length; - } - } - } - } - } else { - sockret = nice_socket_recv_messages (nicesock, message, 1); - } - - if (sockret == 0) { - retval = RECV_WOULD_BLOCK; /* EWOULDBLOCK */ - nice_debug_verbose ("%s: Agent %p: no message available on read attempt", - G_STRFUNC, agent); - goto done; - } else if (sockret < 0) { - nice_debug ("Agent %p: %s returned %d, errno (%d) : %s", - agent, G_STRFUNC, sockret, errno, g_strerror (errno)); - - retval = RECV_ERROR; - goto done; - } else { - retval = sockret; - } - - g_assert_cmpint (retval, !=, RECV_OOB); - if (message->length == 0) { - retval = RECV_OOB; - nice_debug_verbose ("%s: Agent %p: message handled out-of-band", G_STRFUNC, - agent); - goto done; - } - - if (nice_debug_is_verbose ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (message->from, tmpbuf); - nice_debug_verbose ("%s: Agent %p : Packet received on local socket %p " - "(fd %d) from [%s]:%u (%" G_GSSIZE_FORMAT " octets).", G_STRFUNC, agent, - nicesock, nicesock->fileno ? g_socket_get_fd (nicesock->fileno) : -1, tmpbuf, - nice_address_get_port (message->from), message->length); - } - - if (nicesock->type == NICE_SOCKET_TYPE_UDP_TURN) - is_turn = TRUE; - - if (!is_turn && component->turn_candidate && - nice_socket_is_based_on (component->turn_candidate->sockptr, nicesock) && - nice_address_equal (message->from, - &component->turn_candidate->turn->server)) { - is_turn = TRUE; - retval = nice_udp_turn_socket_parse_recv_message ( - component->turn_candidate->sockptr, &nicesock, message); - } - - for (item = component->turn_servers; item && !is_turn; - item = g_list_next (item)) { - TurnServer *turn = item->data; - GSList *i = NULL; - - if (!nice_address_equal (message->from, &turn->server)) - continue; - - nice_debug_verbose ("Agent %p : Packet received from TURN server candidate.", - agent); - is_turn = TRUE; - - for (i = component->local_candidates; i; i = i->next) { - NiceCandidate *cand = i->data; - - if (cand->type == NICE_CANDIDATE_TYPE_RELAYED && - cand->turn == turn && - cand->stream_id == stream->id && - nice_socket_is_based_on (cand->sockptr, nicesock)) { - retval = nice_udp_turn_socket_parse_recv_message (cand->sockptr, &nicesock, - message); - break; - } - } - break; - } - - if (agent->force_relay && !is_turn) { - /* Ignore messages not from TURN if TURN is required */ - retval = RECV_WOULD_BLOCK; /* EWOULDBLOCK */ - goto done; - } - - if (retval == RECV_OOB) - goto done; - - /* If the message’s stated length is equal to its actual length, it’s probably - * a STUN message; otherwise it’s probably data. */ - if (stun_message_validate_buffer_length_fast ( - (StunInputVector *) message->buffers, message->n_buffers, message->length, - (agent->compatibility != NICE_COMPATIBILITY_OC2007 && - agent->compatibility != NICE_COMPATIBILITY_OC2007R2)) == (ssize_t) message->length) { - /* Slow path: If this message isn’t obviously *not* a STUN packet, compact - * its buffers - * into a single monolithic one and parse the packet properly. */ - guint8 *big_buf; - gsize big_buf_len; - int validated_len; - - big_buf = compact_input_message (message, &big_buf_len); - - validated_len = stun_message_validate_buffer_length (big_buf, big_buf_len, - (agent->compatibility != NICE_COMPATIBILITY_OC2007 && - agent->compatibility != NICE_COMPATIBILITY_OC2007R2)); - - if (validated_len == (gint) big_buf_len) { - gboolean handled; - - handled = - conn_check_handle_inbound_stun (agent, stream, component, nicesock, - message->from, (gchar *) big_buf, big_buf_len); - - if (handled) { - /* Handled STUN message. */ - nice_debug ("%s: Valid STUN packet received.", G_STRFUNC); - retval = RECV_OOB; - g_free (big_buf); - agent->media_after_tick = TRUE; - goto done; - } - } - - nice_debug ("%s: Packet passed fast STUN validation but failed " - "slow validation.", G_STRFUNC); - - g_free (big_buf); - } - - if (!nice_component_verify_remote_candidate (component, - message->from, nicesock)) { - if (nice_debug_is_verbose ()) { - gchar str[INET6_ADDRSTRLEN]; - - nice_address_to_string (message->from, str); - nice_debug_verbose ("Agent %p : %d:%d DROPPING packet from unknown source" - " %s:%d sock-type: %d", agent, stream->id, component->id, str, - nice_address_get_port (message->from), nicesock->type); - } - - retval = RECV_OOB; - goto done; - } - - agent->media_after_tick = TRUE; - - /* Unhandled STUN; try handling TCP data, then pass to the client. */ - if (message->length > 0 && agent->reliable) { - if (!nice_socket_is_reliable (nicesock) && - !pseudo_tcp_socket_is_closed (component->tcp)) { - /* If we don’t yet have an underlying selected socket, queue up the - * incoming data to handle later. This is because we can’t send ACKs (or, - * more importantly for the first few packets, SYNACKs) without an - * underlying socket. We’d rather wait a little longer for a pair to be - * selected, then process the incoming packets and send out ACKs, than try - * to process them now, fail to send the ACKs, and incur a timeout in our - * pseudo-TCP state machine. */ - if (component->selected_pair.local == NULL) { - GOutputVector *vec = g_slice_new (GOutputVector); - vec->buffer = compact_input_message (message, &vec->size); - g_queue_push_tail (&component->queued_tcp_packets, vec); - nice_debug ("%s: Queued %" G_GSSIZE_FORMAT " bytes for agent %p.", - G_STRFUNC, vec->size, agent); - - return RECV_OOB; - } else { - process_queued_tcp_packets (agent, stream, component); - } - - /* Received data on a reliable connection. */ - - nice_debug_verbose ("%s: notifying pseudo-TCP of packet, length %" G_GSIZE_FORMAT, - G_STRFUNC, message->length); - pseudo_tcp_socket_notify_message (component->tcp, message); - - adjust_tcp_clock (agent, stream, component); - - /* Success! Handled out-of-band. */ - retval = RECV_OOB; - goto done; - } else if (pseudo_tcp_socket_is_closed (component->tcp)) { - nice_debug ("Received data on a pseudo tcp FAILED component. Ignoring."); - - retval = RECV_OOB; - goto done; - } - } - -done: - /* Clear local modifications. */ - if (message->from == &from) { - message->from = NULL; - } - - return retval; -} - -/* Print the composition of an array of messages. No-op if debugging is - * disabled. */ -static void -nice_debug_input_message_composition (const NiceInputMessage *messages, - guint n_messages) -{ - guint i; - - if (!nice_debug_is_verbose ()) - return; - - for (i = 0; i < n_messages; i++) { - const NiceInputMessage *message = &messages[i]; - guint j; - - nice_debug_verbose ("Message %p (from: %p, length: %" G_GSIZE_FORMAT ")", message, - message->from, message->length); - - for (j = 0; - (message->n_buffers >= 0 && j < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[j].buffer != NULL); - j++) { - GInputVector *buffer = &message->buffers[j]; - - nice_debug_verbose ("\tBuffer %p (length: %" G_GSIZE_FORMAT ")", buffer->buffer, - buffer->size); - } - } -} - -static guint8 * -compact_message (const NiceOutputMessage *message, gsize buffer_length) -{ - guint8 *buffer; - gsize offset = 0; - guint i; - - buffer = g_malloc (buffer_length); - - for (i = 0; - (message->n_buffers >= 0 && i < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[i].buffer != NULL); - i++) { - gsize len = MIN (buffer_length - offset, message->buffers[i].size); - memcpy (buffer + offset, message->buffers[i].buffer, len); - offset += len; - } - - return buffer; -} - -/* Concatenate all the buffers in the given @recv_message into a single, newly - * allocated, monolithic buffer which is returned. The length of the new buffer - * is returned in @buffer_length, and should be equal to the length field of - * @recv_message. - * - * The return value must be freed with g_free(). */ -guint8 * -compact_input_message (const NiceInputMessage *message, gsize *buffer_length) -{ - nice_debug_verbose ("%s: **WARNING: SLOW PATH**", G_STRFUNC); - nice_debug_input_message_composition (message, 1); - - /* This works as long as NiceInputMessage is a subset of eNiceOutputMessage */ - - *buffer_length = message->length; - - return compact_message ((NiceOutputMessage *) message, *buffer_length); -} - -/* Returns the number of bytes copied. Silently drops any data from @buffer - * which doesn’t fit in @message. */ -gsize -memcpy_buffer_to_input_message (NiceInputMessage *message, - const guint8 *buffer, gsize buffer_length) -{ - guint i; - - nice_debug_verbose ("%s: **WARNING: SLOW PATH**", G_STRFUNC); - - message->length = 0; - - for (i = 0; - buffer_length > 0 && - ((message->n_buffers >= 0 && i < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[i].buffer != NULL)); - i++) { - gsize len; - - len = MIN (message->buffers[i].size, buffer_length); - memcpy (message->buffers[i].buffer, buffer, len); - - buffer += len; - buffer_length -= len; - - message->length += len; - } - - nice_debug_input_message_composition (message, 1); - - if (buffer_length > 0) { - g_warning ("Dropped %" G_GSIZE_FORMAT " bytes of data from the end of " - "buffer %p (length: %" G_GSIZE_FORMAT ") due to not fitting in " - "message %p", buffer_length, buffer - message->length, - message->length + buffer_length, message); - } - - return message->length; -} - -/* Concatenate all the buffers in the given @message into a single, newly - * allocated, monolithic buffer which is returned. The length of the new buffer - * is returned in @buffer_length, and should be equal to the length field of - * @recv_message. - * - * The return value must be freed with g_free(). */ -guint8 * -compact_output_message (const NiceOutputMessage *message, gsize *buffer_length) -{ - nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC); - - *buffer_length = output_message_get_size (message); - - return compact_message (message, *buffer_length); -} - -gsize -output_message_get_size (const NiceOutputMessage *message) -{ - guint i; - gsize message_len = 0; - - /* Find the total size of the message */ - for (i = 0; - (message->n_buffers >= 0 && i < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[i].buffer != NULL); - i++) - message_len += message->buffers[i].size; - - return message_len; -} - -gsize -input_message_get_size (const NiceInputMessage *message) -{ - guint i; - gsize message_len = 0; - - /* Find the total size of the message */ - for (i = 0; - (message->n_buffers >= 0 && i < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[i].buffer != NULL); - i++) - message_len += message->buffers[i].size; - - return message_len; -} - -/* - * nice_input_message_iter_reset: - * @iter: a #NiceInputMessageIter - * - * Reset the given @iter to point to the beginning of the array of messages. - * This may be used both to initialise it and to reset it after use. - * - * Since: 0.1.5 - */ -void -nice_input_message_iter_reset (NiceInputMessageIter *iter) -{ - iter->message = 0; - iter->buffer = 0; - iter->offset = 0; -} - -/* - * nice_input_message_iter_is_at_end: - * @iter: a #NiceInputMessageIter - * @messages: (array length=n_messages): an array of #NiceInputMessages - * @n_messages: number of entries in @messages - * - * Determine whether @iter points to the end of the given @messages array. If it - * does, the array is full: every buffer in every message is full of valid - * bytes. - * - * Returns: %TRUE if the messages’ buffers are full, %FALSE otherwise - * - * Since: 0.1.5 - */ -gboolean -nice_input_message_iter_is_at_end (NiceInputMessageIter *iter, - NiceInputMessage *messages, guint n_messages) -{ - return (iter->message == n_messages && - iter->buffer == 0 && iter->offset == 0); -} - -/* - * nice_input_message_iter_get_n_valid_messages: - * @iter: a #NiceInputMessageIter - * - * Calculate the number of valid messages in the messages array. A valid message - * is one which contains at least one valid byte of data in its buffers. - * - * Returns: number of valid messages (may be zero) - * - * Since: 0.1.5 - */ -guint -nice_input_message_iter_get_n_valid_messages (NiceInputMessageIter *iter) -{ - if (iter->buffer == 0 && iter->offset == 0) - return iter->message; - else - return iter->message + 1; -} - -/** - * nice_input_message_iter_compare: - * @a: a #NiceInputMessageIter - * @b: another #NiceInputMessageIter - * - * Compare two #NiceInputMessageIters for equality, returning %TRUE if they - * point to the same place in the receive message array. - * - * Returns: %TRUE if the iters match, %FALSE otherwise - * - * Since: 0.1.5 - */ -gboolean -nice_input_message_iter_compare (const NiceInputMessageIter *a, - const NiceInputMessageIter *b) -{ - return (a->message == b->message && a->buffer == b->buffer && a->offset == b->offset); -} - -/* Will fill up @messages from the first free byte onwards (as determined using - * @iter). This may be used in reliable or non-reliable mode; in non-reliable - * mode it will always increment the message index after each buffer is - * consumed. - * - * Updates @iter in place. No errors can occur. - * - * Returns the number of valid messages in @messages on success (which may be - * zero if reading into the first buffer of the message would have blocked). - * - * Must be called with the io_mutex held. */ -static gint -pending_io_messages_recv_messages (NiceComponent *component, gboolean reliable, - NiceInputMessage *messages, guint n_messages, NiceInputMessageIter *iter) -{ - gsize len; - IOCallbackData *data; - NiceInputMessage *message = &messages[iter->message]; - - g_assert_cmpuint (component->io_callback_id, ==, 0); - - data = g_queue_peek_head (&component->pending_io_messages); - if (data == NULL) - goto done; - - if (iter->buffer == 0 && iter->offset == 0) { - message->length = 0; - } - - for (; - (message->n_buffers >= 0 && iter->buffer < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[iter->buffer].buffer != NULL); - iter->buffer++) { - GInputVector *buffer = &message->buffers[iter->buffer]; - - do { - len = MIN (data->buf_len - data->offset, buffer->size - iter->offset); - memcpy ((guint8 *) buffer->buffer + iter->offset, - data->buf + data->offset, len); - - nice_debug ("%s: Unbuffered %" G_GSIZE_FORMAT " bytes into " - "buffer %p (offset %" G_GSIZE_FORMAT ", length %" G_GSIZE_FORMAT - ").", G_STRFUNC, len, buffer->buffer, iter->offset, buffer->size); - - message->length += len; - iter->offset += len; - data->offset += len; - } while (iter->offset < buffer->size); - - iter->offset = 0; - } - - /* Only if we managed to consume the whole buffer should it be popped off the - * queue; otherwise we’ll have another go at it later. */ - if (data->offset == data->buf_len) { - g_queue_pop_head (&component->pending_io_messages); - io_callback_data_free (data); - - /* If we’ve consumed an entire message from pending_io_messages, and - * are in non-reliable mode, move on to the next message in - * @messages. */ - if (!reliable) { - iter->offset = 0; - iter->buffer = 0; - iter->message++; - } - } - -done: - return nice_input_message_iter_get_n_valid_messages (iter); -} - -static gboolean -nice_agent_recv_cancelled_cb (GCancellable *cancellable, gpointer user_data) -{ - GError **error = user_data; - - if (error && !*error) - g_cancellable_set_error_if_cancelled (cancellable, error); - return G_SOURCE_REMOVE; -} - -static gint -nice_agent_recv_messages_blocking_or_nonblocking (NiceAgent *agent, - guint stream_id, guint component_id, gboolean blocking, - NiceInputMessage *messages, guint n_messages, - GCancellable *cancellable, GError **error) -{ - GMainContext *context; - NiceStream *stream; - NiceComponent *component; - gint n_valid_messages = -1; - GSource *cancellable_source = NULL; - gboolean received_enough = FALSE, error_reported = FALSE; - gboolean all_sockets_would_block = FALSE; - gboolean reached_eos = FALSE; - GError *child_error = NULL; - NiceInputMessage *messages_orig = NULL; - guint i; - - g_return_val_if_fail (NICE_IS_AGENT (agent), -1); - g_return_val_if_fail (stream_id >= 1, -1); - g_return_val_if_fail (component_id >= 1, -1); - g_return_val_if_fail (n_messages == 0 || messages != NULL, -1); - g_return_val_if_fail ( - cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); - - if (n_messages == 0) - return 0; - - if (n_messages > G_MAXINT) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - "The number of messages can't exceed G_MAXINT: %d", G_MAXINT); - return -1; - } - - /* Receive buffer size must be at least 1280 for STUN */ - if (!agent->reliable) { - for (i = 0; i < n_messages; i++) { - if (input_message_get_size (&messages[i]) < 1280) { - GInputVector *vec; - - if (messages_orig == NULL) - messages_orig = g_memdup (messages, - sizeof (NiceInputMessage) * n_messages); - vec = g_slice_new (GInputVector); - vec->buffer = g_slice_alloc (1280); - vec->size = 1280; - messages[i].buffers = vec; - messages[i].n_buffers = 1; - } - } - } - - agent_lock (agent); - - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) { - g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE, - "Invalid stream/component."); - goto done; - } - - nice_debug_verbose ("%s: %p: (%s):", G_STRFUNC, agent, - blocking ? "blocking" : "non-blocking"); - nice_debug_input_message_composition (messages, n_messages); - - /* Disallow re-entrant reads. */ - g_assert (component->n_recv_messages == 0 && - component->recv_messages == NULL); - - /* Set the component’s receive buffer. */ - context = nice_component_dup_io_context (component); - nice_component_set_io_callback (component, NULL, NULL, messages, n_messages, - &child_error); - - /* Add the cancellable as a source. */ - if (cancellable != NULL) { - cancellable_source = g_cancellable_source_new (cancellable); - g_source_set_callback (cancellable_source, - (GSourceFunc) G_CALLBACK (nice_agent_recv_cancelled_cb), &child_error, - NULL); - g_source_attach (cancellable_source, context); - } - - /* Is there already pending data left over from having an I/O callback - * attached and switching to using nice_agent_recv()? This is a horrifically - * specific use case which I hope nobody ever tries. And yet, it still must be - * supported. */ - g_mutex_lock (&component->io_mutex); - - while (!received_enough && - !g_queue_is_empty (&component->pending_io_messages)) { - pending_io_messages_recv_messages (component, agent->reliable, - component->recv_messages, component->n_recv_messages, - &component->recv_messages_iter); - - nice_debug_verbose ("%s: %p: Received %d valid messages from pending I/O buffer.", - G_STRFUNC, agent, - nice_input_message_iter_get_n_valid_messages ( - &component->recv_messages_iter)); - - received_enough = - nice_input_message_iter_is_at_end (&component->recv_messages_iter, - component->recv_messages, component->n_recv_messages); - } - - g_mutex_unlock (&component->io_mutex); - - /* For a reliable stream, grab any data from the pseudo-TCP input buffer - * before trying the sockets. */ - if (agent->reliable && - pseudo_tcp_socket_get_available_bytes (component->tcp) > 0) { - pseudo_tcp_socket_recv_messages (component->tcp, - component->recv_messages, component->n_recv_messages, - &component->recv_messages_iter, &child_error); - adjust_tcp_clock (agent, stream, component); - - nice_debug_verbose ("%s: %p: Received %d valid messages from pseudo-TCP read " - "buffer.", G_STRFUNC, agent, - nice_input_message_iter_get_n_valid_messages ( - &component->recv_messages_iter)); - - received_enough = - nice_input_message_iter_is_at_end (&component->recv_messages_iter, - component->recv_messages, component->n_recv_messages); - error_reported = (child_error != NULL); - } - - /* Each iteration of the main context will either receive some data, a - * cancellation error or a socket error. In non-reliable mode, the iter’s - * @message counter will be incremented after each read. - * - * In blocking, reliable mode, iterate the loop enough to fill exactly - * @n_messages messages. In blocking, non-reliable mode, iterate the loop to - * receive @n_messages messages (which may not fill all the buffers). In - * non-blocking mode, stop iterating the loop if all sockets would block (i.e. - * if no data was received for an iteration; in which case @child_error will - * be set to %G_IO_ERROR_WOULD_BLOCK). - */ - while (!received_enough && !error_reported && !all_sockets_would_block && - !reached_eos) { - NiceInputMessageIter prev_recv_messages_iter; - - g_clear_error (&child_error); - memcpy (&prev_recv_messages_iter, &component->recv_messages_iter, - sizeof (NiceInputMessageIter)); - - agent_unlock (agent); - g_main_context_iteration (context, blocking); - agent_lock (agent); - - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) { - g_clear_error (&child_error); - g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE, - "Component removed during call."); - - component = NULL; - - goto recv_error; - } - - received_enough = - nice_input_message_iter_is_at_end (&component->recv_messages_iter, - component->recv_messages, component->n_recv_messages); - error_reported = (child_error != NULL && - !g_error_matches (child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)); - reached_eos = (agent->reliable && - pseudo_tcp_socket_is_closed_remotely (component->tcp) && - nice_input_message_iter_compare (&prev_recv_messages_iter, - &component->recv_messages_iter)); - all_sockets_would_block = (!blocking && !reached_eos && - nice_input_message_iter_compare (&prev_recv_messages_iter, - &component->recv_messages_iter)); - } - - n_valid_messages = - nice_input_message_iter_get_n_valid_messages ( - &component->recv_messages_iter); /* grab before resetting the iter */ - - nice_component_set_io_callback (component, NULL, NULL, NULL, 0, NULL); - -recv_error: - /* Tidy up. Below this point, @component may be %NULL. */ - if (cancellable_source != NULL) { - g_source_destroy (cancellable_source); - g_source_unref (cancellable_source); - } - - g_main_context_unref (context); - - /* Handle errors and cancellations. */ - if (child_error != NULL) { - n_valid_messages = -1; - } else if (n_valid_messages == 0 && all_sockets_would_block) { - g_set_error_literal (&child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK, - g_strerror (EAGAIN)); - n_valid_messages = -1; - } - - nice_debug_verbose ("%s: %p: n_valid_messages: %d, n_messages: %u", G_STRFUNC, agent, - n_valid_messages, n_messages); - -done: - g_assert ((child_error != NULL) == (n_valid_messages == -1)); - g_assert (n_valid_messages < 0 || (guint) n_valid_messages <= n_messages); - g_assert (n_valid_messages != 0 || reached_eos); - - if (child_error != NULL) - g_propagate_error (error, child_error); - - agent_unlock_and_emit (agent); - - if (messages_orig) { - for (i = 0; i < n_messages; i++) { - if (messages[i].buffers != messages_orig[i].buffers) { - g_assert_cmpint (messages[i].n_buffers, ==, 1); - - memcpy_buffer_to_input_message (&messages_orig[i], - messages[i].buffers[0].buffer, messages[i].length); - - g_slice_free1 (1280, messages[i].buffers[0].buffer); - g_slice_free (GInputVector, messages[i].buffers); - - messages[i].buffers = messages_orig[i].buffers; - messages[i].n_buffers = messages_orig[i].n_buffers; - messages[i].length = messages_orig[i].length; - } - } - g_free (messages_orig); - } - - return n_valid_messages; -} - -NICEAPI_EXPORT gint -nice_agent_recv_messages (NiceAgent *agent, guint stream_id, guint component_id, - NiceInputMessage *messages, guint n_messages, GCancellable *cancellable, - GError **error) -{ - return nice_agent_recv_messages_blocking_or_nonblocking (agent, stream_id, - component_id, TRUE, messages, n_messages, cancellable, error); -} - -NICEAPI_EXPORT gssize -nice_agent_recv (NiceAgent *agent, guint stream_id, guint component_id, - guint8 *buf, gsize buf_len, GCancellable *cancellable, GError **error) -{ - gint n_valid_messages; - GInputVector local_bufs = { buf, buf_len }; - NiceInputMessage local_messages = { &local_bufs, 1, NULL, 0 }; - - g_return_val_if_fail (NICE_IS_AGENT (agent), -1); - g_return_val_if_fail (stream_id >= 1, -1); - g_return_val_if_fail (component_id >= 1, -1); - g_return_val_if_fail (buf != NULL || buf_len == 0, -1); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); - - if (buf_len > G_MAXSSIZE) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - "The buffer length can't exceed G_MAXSSIZE: %" G_GSSIZE_FORMAT, - G_MAXSSIZE); - return -1; - } - - n_valid_messages = nice_agent_recv_messages (agent, stream_id, component_id, - &local_messages, 1, cancellable, error); - - if (n_valid_messages <= 0) - return n_valid_messages; - - return local_messages.length; -} - -NICEAPI_EXPORT gint -nice_agent_recv_messages_nonblocking (NiceAgent *agent, guint stream_id, - guint component_id, NiceInputMessage *messages, guint n_messages, - GCancellable *cancellable, GError **error) -{ - return nice_agent_recv_messages_blocking_or_nonblocking (agent, stream_id, - component_id, FALSE, messages, n_messages, cancellable, error); -} - -NICEAPI_EXPORT gssize -nice_agent_recv_nonblocking (NiceAgent *agent, guint stream_id, - guint component_id, guint8 *buf, gsize buf_len, GCancellable *cancellable, - GError **error) -{ - gint n_valid_messages; - GInputVector local_bufs = { buf, buf_len }; - NiceInputMessage local_messages = { &local_bufs, 1, NULL, 0 }; - - g_return_val_if_fail (NICE_IS_AGENT (agent), -1); - g_return_val_if_fail (stream_id >= 1, -1); - g_return_val_if_fail (component_id >= 1, -1); - g_return_val_if_fail (buf != NULL || buf_len == 0, -1); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); - - if (buf_len > G_MAXSSIZE) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - "The buffer length can't exceed G_MAXSSIZE: %" G_GSSIZE_FORMAT, - G_MAXSSIZE); - return -1; - } - - n_valid_messages = nice_agent_recv_messages_nonblocking (agent, stream_id, - component_id, &local_messages, 1, cancellable, error); - - if (n_valid_messages <= 0) - return n_valid_messages; - - return local_messages.length; -} - -/* nice_agent_send_messages_nonblocking_internal: - * - * Returns: number of bytes sent if allow_partial is %TRUE, the number - * of messages otherwise. - */ - -static gint -nice_agent_send_messages_nonblocking_internal ( - NiceAgent *agent, - guint stream_id, - guint component_id, - const NiceOutputMessage *messages, - guint n_messages, - gboolean allow_partial, - GError **error) -{ - NiceStream *stream; - NiceComponent *component; - gint n_sent = -1; /* is in bytes if allow_partial is TRUE, - otherwise in messages */ - GError *child_error = NULL; - - g_assert (n_messages == 1 || !allow_partial); - - agent_lock (agent); - - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) { - g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE, - "Invalid stream/component."); - goto done; - } - - /* FIXME: Cancellation isn’t yet supported, but it doesn’t matter because - * we only deal with non-blocking writes. */ - if (component->selected_pair.local != NULL) { - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf); - - nice_debug_verbose ("Agent %p : s%d:%d: sending %u messages to " - "[%s]:%d", agent, stream_id, component_id, n_messages, tmpbuf, - nice_address_get_port (&component->selected_pair.remote->addr)); - } - - if(agent->reliable && - !nice_socket_is_reliable (component->selected_pair.local->sockptr)) { - if (!pseudo_tcp_socket_is_closed (component->tcp)) { - /* Send on the pseudo-TCP socket. */ - n_sent = pseudo_tcp_socket_send_messages (component->tcp, messages, - n_messages, allow_partial, &child_error); - adjust_tcp_clock (agent, stream, component); - - if (!pseudo_tcp_socket_can_send (component->tcp)) - g_cancellable_reset (component->tcp_writable_cancellable); - if (n_sent < 0 && !g_error_matches (child_error, G_IO_ERROR, - G_IO_ERROR_WOULD_BLOCK)) { - /* Signal errors */ - priv_pseudo_tcp_error (agent, component); - } - } else { - g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Pseudo-TCP socket not connected."); - } - } else { - NiceSocket *sock; - NiceAddress *addr; - - sock = component->selected_pair.local->sockptr; - addr = &component->selected_pair.remote->addr; - - if (nice_socket_is_reliable (sock)) { - guint i; - - /* ICE-TCP requires that all packets be framed with RFC4571 */ - n_sent = 0; - for (i = 0; i < n_messages; i++) { - const NiceOutputMessage *message = &messages[i]; - gsize message_len = output_message_get_size (message); - gsize offset = 0; - gsize current_offset = 0; - gsize offset_in_buffer = 0; - gint n_sent_framed; - GOutputVector *local_bufs; - NiceOutputMessage local_message; - guint j; - guint n_bufs = 0; - - /* Count the number of buffers. */ - if (message->n_buffers == -1) { - for (j = 0; message->buffers[j].buffer != NULL; j++) - n_bufs++; - } else { - n_bufs = message->n_buffers; - } - - local_bufs = g_malloc_n (n_bufs + 1, sizeof (GOutputVector)); - local_message.buffers = local_bufs; - - while (message_len > 0) { - guint16 packet_len; - guint16 rfc4571_frame; - - /* Split long messages into 62KB packets, leaving enough space - * for TURN overhead as well */ - if (message_len > 0xF800) - packet_len = 0xF800; - else - packet_len = (guint16) message_len; - message_len -= packet_len; - rfc4571_frame = htons (packet_len); - - local_bufs[0].buffer = &rfc4571_frame; - local_bufs[0].size = sizeof (guint16); - - local_message.n_buffers = 1; - /* If we had to split the message, we need to find which buffer - * to start copying from and our offset within that buffer */ - offset_in_buffer = 0; - current_offset = 0; - for (j = 0; j < n_bufs; j++) { - if (message->buffers[j].size < offset - current_offset) { - current_offset += message->buffers[j].size; - continue; - } else { - offset_in_buffer = offset - current_offset; - current_offset = offset; - break; - } - } - - /* Keep j position in array and start copying from there */ - for (; j < n_bufs; j++) { - local_bufs[local_message.n_buffers].buffer = - ((guint8 *) message->buffers[j].buffer) + offset_in_buffer; - local_bufs[local_message.n_buffers].size = - MIN (message->buffers[j].size, packet_len); - packet_len -= local_bufs[local_message.n_buffers].size; - offset += local_bufs[local_message.n_buffers++].size; - offset_in_buffer = 0; - } - - /* If we sent part of the message already, then send the rest - * reliably so the message is sent as a whole even if it's split */ - if (current_offset == 0) - n_sent_framed = nice_socket_send_messages (sock, addr, - &local_message, 1); - else - n_sent_framed = nice_socket_send_messages_reliable (sock, addr, - &local_message, 1); - - if (component->tcp_writable_cancellable && - !nice_socket_can_send (sock, addr)) - g_cancellable_reset (component->tcp_writable_cancellable); - - if (n_sent_framed < 0 && n_sent == 0) - n_sent = n_sent_framed; - if (n_sent_framed != 1) - break; - /* This is the last split frame, increment n_sent */ - if (message_len == 0) - n_sent ++; - } - g_free (local_bufs); - } - - } else { - n_sent = nice_socket_send_messages (sock, addr, messages, n_messages); - } - - if (n_sent < 0) { - g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Error writing data to socket."); - } else if (n_sent > 0 && allow_partial) { - g_assert_cmpuint (n_messages, ==, 1); - n_sent = output_message_get_size (messages); - } - } - } else { - /* Socket isn’t properly open yet. */ - n_sent = 0; /* EWOULDBLOCK */ - } - - /* Handle errors and cancellations. */ - if (n_sent == 0) { - g_set_error_literal (&child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK, - g_strerror (EAGAIN)); - n_sent = -1; - } - - nice_debug_verbose ("%s: n_sent: %d, n_messages: %u", G_STRFUNC, - n_sent, n_messages); - -done: - g_assert ((child_error != NULL) == (n_sent == -1)); - g_assert_cmpint (n_sent, !=, 0); - g_assert (n_sent < 0 || - (!allow_partial && (guint) n_sent <= n_messages) || - (allow_partial && n_messages == 1 && - (gsize) n_sent <= output_message_get_size (&messages[0]))); - - if (child_error != NULL) - g_propagate_error (error, child_error); - - agent_unlock_and_emit (agent); - - return n_sent; -} - -NICEAPI_EXPORT gint -nice_agent_send_messages_nonblocking ( - NiceAgent *agent, - guint stream_id, - guint component_id, - const NiceOutputMessage *messages, - guint n_messages, - GCancellable *cancellable, - GError **error) -{ - g_return_val_if_fail (NICE_IS_AGENT (agent), -1); - g_return_val_if_fail (stream_id >= 1, -1); - g_return_val_if_fail (component_id >= 1, -1); - g_return_val_if_fail (n_messages == 0 || messages != NULL, -1); - g_return_val_if_fail ( - cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return -1; - - return nice_agent_send_messages_nonblocking_internal (agent, stream_id, - component_id, messages, n_messages, FALSE, error); -} - -NICEAPI_EXPORT gint -nice_agent_send ( - NiceAgent *agent, - guint stream_id, - guint component_id, - guint len, - const gchar *buf) -{ - GOutputVector local_buf = { buf, len }; - NiceOutputMessage local_message = { &local_buf, 1 }; - gint n_sent_bytes; - - g_return_val_if_fail (NICE_IS_AGENT (agent), -1); - g_return_val_if_fail (stream_id >= 1, -1); - g_return_val_if_fail (component_id >= 1, -1); - g_return_val_if_fail (buf != NULL, -1); - - n_sent_bytes = nice_agent_send_messages_nonblocking_internal (agent, - stream_id, component_id, &local_message, 1, TRUE, NULL); - - return n_sent_bytes; -} - -NICEAPI_EXPORT GSList * -nice_agent_get_local_candidates ( - NiceAgent *agent, - guint stream_id, - guint component_id) -{ - NiceComponent *component; - GSList * ret = NULL; - GSList * item = NULL; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - g_return_val_if_fail (component_id >= 1, NULL); - - agent_lock (agent); - - if (!agent_find_component (agent, stream_id, component_id, NULL, &component)) { - goto done; - } - - for (item = component->local_candidates; item; item = item->next) { - NiceCandidate *cand = item->data; - - if (agent->force_relay && cand->type != NICE_CANDIDATE_TYPE_RELAYED) - continue; - - ret = g_slist_append (ret, nice_candidate_copy (cand)); - } - - done: - agent_unlock_and_emit (agent); - return ret; -} - - -NICEAPI_EXPORT GSList * -nice_agent_get_remote_candidates ( - NiceAgent *agent, - guint stream_id, - guint component_id) -{ - NiceComponent *component; - GSList *ret = NULL, *item = NULL; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - g_return_val_if_fail (component_id >= 1, NULL); - - agent_lock (agent); - if (!agent_find_component (agent, stream_id, component_id, NULL, &component)) - { - goto done; - } - - for (item = component->remote_candidates; item; item = item->next) - ret = g_slist_append (ret, nice_candidate_copy (item->data)); - - done: - agent_unlock_and_emit (agent); - return ret; -} - -gboolean -nice_agent_restart ( - NiceAgent *agent) -{ - GSList *i; - - agent_lock (agent); - - /* step: regenerate tie-breaker value */ - priv_generate_tie_breaker (agent); - - /* step: reset controlling mode from the property value */ - agent->controlling_mode = agent->saved_controlling_mode; - nice_debug ("Agent %p : ICE restart, reset role to \"%s\".", - agent, agent->controlling_mode ? "controlling" : "controlled"); - - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - - /* step: reset local credentials for the stream and - * clean up the list of remote candidates */ - nice_stream_restart (stream, agent); - } - - agent_unlock_and_emit (agent); - return TRUE; -} - -gboolean -nice_agent_restart_stream ( - NiceAgent *agent, - guint stream_id) -{ - gboolean res = FALSE; - NiceStream *stream; - - agent_lock (agent); - - stream = agent_find_stream (agent, stream_id); - if (!stream) { - g_warning ("Could not find stream %u", stream_id); - goto done; - } - - /* step: reset local credentials for the stream and - * clean up the list of remote candidates */ - nice_stream_restart (stream, agent); - - res = TRUE; - done: - agent_unlock_and_emit (agent); - return res; -} - - -static void -nice_agent_dispose (GObject *object) -{ - GSList *i; - QueuedSignal *sig; - NiceAgent *agent = NICE_AGENT (object); - - agent_lock (agent); - - /* step: free resources for the binding discovery timers */ - discovery_free (agent); - g_assert (agent->discovery_list == NULL); - - /* step: free resources for the connectivity check timers */ - conn_check_free (agent); - - priv_remove_keepalive_timer (agent); - - for (i = agent->local_addresses; i; i = i->next) - { - NiceAddress *a = i->data; - - nice_address_free (a); - } - - g_slist_free (agent->local_addresses); - agent->local_addresses = NULL; - - while (agent->streams) { - NiceStream *s = agent->streams->data; - - nice_stream_close (agent, s); - g_object_unref (s); - - agent->streams = g_slist_delete_link(agent->streams, agent->streams); - } - - while (agent->pruning_streams) { - NiceStream *s = agent->pruning_streams->data; - - nice_stream_close (agent, s); - g_object_unref (s); - - agent->pruning_streams = g_slist_delete_link(agent->pruning_streams, - agent->pruning_streams); - } - - while ((sig = g_queue_pop_head (&agent->pending_signals))) { - free_queued_signal (sig); - } - - g_free (agent->stun_server_ip); - agent->stun_server_ip = NULL; - - g_free (agent->proxy_ip); - agent->proxy_ip = NULL; - g_free (agent->proxy_username); - agent->proxy_username = NULL; - g_free (agent->proxy_password); - agent->proxy_password = NULL; - - nice_rng_free (agent->rng); - agent->rng = NULL; - - priv_stop_upnp (agent); - -#ifdef HAVE_GUPNP - if (agent->upnp) { - g_object_unref (agent->upnp); - agent->upnp = NULL; - } -#endif - - g_free (agent->software_attribute); - agent->software_attribute = NULL; - - if (agent->main_context != NULL) - g_main_context_unref (agent->main_context); - agent->main_context = NULL; - - agent_unlock (agent); - - g_mutex_clear (&agent->agent_mutex); - - if (G_OBJECT_CLASS (nice_agent_parent_class)->dispose) - G_OBJECT_CLASS (nice_agent_parent_class)->dispose (object); - -} - -gboolean -component_io_cb (GSocket *gsocket, GIOCondition condition, gpointer user_data) -{ - SocketSource *socket_source = user_data; - NiceComponent *component; - NiceAgent *agent; - NiceStream *stream; - gboolean has_io_callback; - gboolean remove_source = FALSE; - - component = socket_source->component; - - agent = g_weak_ref_get (&component->agent_ref); - if (agent == NULL) - return G_SOURCE_REMOVE; - - agent_lock (agent); - - stream = agent_find_stream (agent, component->stream_id); - - if (stream == NULL) { - nice_debug ("%s: stream %d destroyed", G_STRFUNC, component->stream_id); - - agent_unlock (agent); - g_object_unref (agent); - return G_SOURCE_REMOVE; - } - - if (g_source_is_destroyed (g_main_current_source ())) { - /* Silently return FALSE. */ - nice_debug ("%s: source %p destroyed", G_STRFUNC, g_main_current_source ()); - - agent_unlock (agent); - g_object_unref (agent); - return G_SOURCE_REMOVE; - } - - /* Remove disconnected sockets when we get a HUP */ - if (condition & G_IO_HUP) { - nice_debug ("Agent %p: NiceSocket %p has received HUP", agent, - socket_source->socket); - if (component->selected_pair.local && - component->selected_pair.local->sockptr == socket_source->socket && - component->state == NICE_COMPONENT_STATE_READY) { - nice_debug ("Agent %p: Selected pair socket %p has HUP, declaring failed", - agent, socket_source->socket); - agent_signal_component_state_change (agent, - stream->id, component->id, NICE_COMPONENT_STATE_FAILED); - } - - nice_component_remove_socket (agent, component, socket_source->socket); - agent_unlock (agent); - g_object_unref (agent); - return G_SOURCE_REMOVE; - } - - has_io_callback = nice_component_has_io_callback (component); - - /* Choose which receive buffer to use. If we’re reading for - * nice_agent_attach_recv(), use a local static buffer. If we’re reading for - * nice_agent_recv_messages(), use the buffer provided by the client. - * - * has_io_callback cannot change throughout this function, as we operate - * entirely with the agent lock held, and nice_component_set_io_callback() - * would need to take the agent lock to change the Component’s - * io_callback. */ - g_assert (!has_io_callback || component->recv_messages == NULL); - - if (agent->reliable && !nice_socket_is_reliable (socket_source->socket)) { -#define TCP_HEADER_SIZE 24 /* bytes */ - guint8 local_header_buf[TCP_HEADER_SIZE]; - /* FIXME: Currently, the critical path for reliable packet delivery has two - * memcpy()s: one into the pseudo-TCP receive buffer, and one out of it. - * This could moderately easily be reduced to one memcpy() in the common - * case of in-order packet delivery, by replacing local_body_buf with a - * pointer into the pseudo-TCP receive buffer. If it turns out the packet - * is out-of-order (which we can only know after parsing its header), the - * data will need to be moved in the buffer. If the packet *is* in order, - * however, the only memcpy() then needed is from the pseudo-TCP receive - * buffer to the client’s message buffers. - * - * In fact, in the case of a reliable agent with I/O callbacks, zero - * memcpy()s can be achieved (for in-order packet delivery) by emittin the - * I/O callback directly from the pseudo-TCP receive buffer. */ - guint8 local_body_buf[MAX_BUFFER_SIZE]; - GInputVector local_bufs[] = { - { local_header_buf, sizeof (local_header_buf) }, - { local_body_buf, sizeof (local_body_buf) }, - }; - NiceInputMessage local_message = { - local_bufs, G_N_ELEMENTS (local_bufs), NULL, 0 - }; - RecvStatus retval = 0; - - if (pseudo_tcp_socket_is_closed (component->tcp)) { - nice_debug ("Agent %p: not handling incoming packet for s%d:%d " - "because pseudo-TCP socket does not exist in reliable mode.", agent, - stream->id, component->id); - remove_source = TRUE; - goto done; - } - - while (has_io_callback || - (component->recv_messages != NULL && - !nice_input_message_iter_is_at_end (&component->recv_messages_iter, - component->recv_messages, component->n_recv_messages))) { - /* Receive a single message. This will receive it into the given - * @local_bufs then, for pseudo-TCP, emit I/O callbacks or copy it into - * component->recv_messages in pseudo_tcp_socket_readable(). STUN packets - * will be parsed in-place. */ - retval = agent_recv_message_unlocked (agent, stream, component, - socket_source->socket, &local_message); - - nice_debug_verbose ("%s: %p: received %d valid messages with %" G_GSSIZE_FORMAT - " bytes", G_STRFUNC, agent, retval, local_message.length); - - /* Don’t expect any valid messages to escape pseudo_tcp_socket_readable() - * when in reliable mode. */ - g_assert_cmpint (retval, !=, RECV_SUCCESS); - - if (retval == RECV_WOULD_BLOCK) { - /* EWOULDBLOCK. */ - break; - } else if (retval == RECV_ERROR) { - /* Other error. */ - nice_debug ("%s: error receiving message", G_STRFUNC); - remove_source = TRUE; - break; - } - - has_io_callback = nice_component_has_io_callback (component); - } - } else if (has_io_callback) { - while (has_io_callback) { - guint8 local_buf[MAX_BUFFER_SIZE]; - GInputVector local_bufs = { local_buf, sizeof (local_buf) }; - NiceInputMessage local_message = { &local_bufs, 1, NULL, 0 }; - RecvStatus retval; - - /* Receive a single message. */ - retval = agent_recv_message_unlocked (agent, stream, component, - socket_source->socket, &local_message); - - if (retval == RECV_WOULD_BLOCK) { - /* EWOULDBLOCK. */ - nice_debug_verbose ("%s: %p: no message available on read attempt", - G_STRFUNC, agent); - break; - } else if (retval == RECV_ERROR) { - /* Other error. */ - nice_debug ("%s: %p: error receiving message", G_STRFUNC, agent); - remove_source = TRUE; - break; - } - - if (retval == RECV_SUCCESS) { - nice_debug_verbose ("%s: %p: received a valid message with %" G_GSSIZE_FORMAT - " bytes", G_STRFUNC, agent, local_message.length); - - if (local_message.length > 0) { - nice_component_emit_io_callback (agent, component, local_buf, - local_message.length); - } - } - - if (g_source_is_destroyed (g_main_current_source ())) { - nice_debug ("Component IO source disappeared during the callback"); - goto out; - } - has_io_callback = nice_component_has_io_callback (component); - } - } else if (component->recv_messages != NULL) { - RecvStatus retval; - - /* Don’t want to trample over partially-valid buffers. */ - g_assert_cmpuint (component->recv_messages_iter.buffer, ==, 0); - g_assert_cmpint (component->recv_messages_iter.offset, ==, 0); - - while (!nice_input_message_iter_is_at_end (&component->recv_messages_iter, - component->recv_messages, component->n_recv_messages)) { - /* Receive a single message. This will receive it into the given - * user-provided #NiceInputMessage, which it’s the user’s responsibility - * to ensure is big enough to avoid data loss (since we’re in non-reliable - * mode). Iterate to receive as many messages as possible. - * - * STUN packets will be parsed in-place. */ - retval = agent_recv_message_unlocked (agent, stream, component, - socket_source->socket, - &component->recv_messages[component->recv_messages_iter.message]); - - nice_debug_verbose ("%s: %p: received %d valid messages", G_STRFUNC, agent, - retval); - - if (retval == RECV_SUCCESS) { - /* Successfully received a single message. */ - component->recv_messages_iter.message++; - g_clear_error (component->recv_buf_error); - } else if (retval == RECV_WOULD_BLOCK) { - /* EWOULDBLOCK. */ - if (component->recv_messages_iter.message == 0 && - component->recv_buf_error != NULL && - *component->recv_buf_error == NULL) { - g_set_error_literal (component->recv_buf_error, G_IO_ERROR, - G_IO_ERROR_WOULD_BLOCK, g_strerror (EAGAIN)); - } - break; - } else if (retval == RECV_ERROR) { - /* Other error. */ - remove_source = TRUE; - break; - } /* else if (retval == RECV_OOB) { ignore me and continue; } */ - } - } - -done: - - if (remove_source) - nice_component_remove_socket (agent, component, socket_source->socket); - - /* If we’re in the middle of a read, don’t emit any signals, or we could cause - * re-entrancy by (e.g.) emitting component-state-changed and having the - * client perform a read. */ - if (component->n_recv_messages == 0 && component->recv_messages == NULL) { - agent_unlock_and_emit (agent); - } else { - agent_unlock (agent); - } - - g_object_unref (agent); - - return !remove_source; - -out: - agent_unlock_and_emit (agent); - - g_object_unref (agent); - - return G_SOURCE_REMOVE; -} - -NICEAPI_EXPORT gboolean -nice_agent_attach_recv ( - NiceAgent *agent, - guint stream_id, - guint component_id, - GMainContext *ctx, - NiceAgentRecvFunc func, - gpointer data) -{ - NiceComponent *component = NULL; - NiceStream *stream = NULL; - gboolean ret = FALSE; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id >= 1, FALSE); - g_return_val_if_fail (component_id >= 1, FALSE); - - agent_lock (agent); - - /* attach candidates */ - - /* step: check that params specify an existing pair */ - if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) { - g_warning ("Could not find component %u in stream %u", component_id, - stream_id); - goto done; - } - - if (ctx == NULL) - ctx = g_main_context_default (); - - /* Set the component’s I/O context. */ - nice_component_set_io_context (component, ctx); - nice_component_set_io_callback (component, func, data, NULL, 0, NULL); - ret = TRUE; - - if (func) { - /* If we got detached, maybe our readable callback didn't finish reading - * all available data in the pseudotcp, so we need to make sure we free - * our recv window, so the readable callback can be triggered again on the - * next incoming data. - * but only do this if we know we're already readable, otherwise we might - * trigger an error in the initial, pre-connection attach. */ - if (agent->reliable && !pseudo_tcp_socket_is_closed (component->tcp) && - component->tcp_readable) - pseudo_tcp_socket_readable (component->tcp, component); - } - - done: - agent_unlock_and_emit (agent); - return ret; -} - -NICEAPI_EXPORT gboolean -nice_agent_set_selected_pair ( - NiceAgent *agent, - guint stream_id, - guint component_id, - const gchar *lfoundation, - const gchar *rfoundation) -{ - NiceComponent *component; - NiceStream *stream; - CandidatePair pair; - gboolean ret = FALSE; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id >= 1, FALSE); - g_return_val_if_fail (component_id >= 1, FALSE); - g_return_val_if_fail (lfoundation, FALSE); - g_return_val_if_fail (rfoundation, FALSE); - - agent_lock (agent); - - /* step: check that params specify an existing pair */ - if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) { - goto done; - } - - if (!nice_component_find_pair (component, agent, lfoundation, rfoundation, &pair)){ - goto done; - } - - /* step: stop connectivity checks (note: for the whole stream) */ - conn_check_prune_stream (agent, stream); - - if (agent->reliable && !nice_socket_is_reliable (pair.local->sockptr) && - pseudo_tcp_socket_is_closed (component->tcp)) { - nice_debug ("Agent %p: not setting selected pair for s%d:%d because " - "pseudo tcp socket does not exist in reliable mode", agent, - stream->id, component->id); - goto done; - } - - /* step: change component state; we could be in STATE_DISCONNECTED; skip - * STATE_GATHERING and continue through the states to give client code a nice - * logical progression. See http://phabricator.freedesktop.org/D218 for - * discussion. */ - if (component->state < NICE_COMPONENT_STATE_CONNECTING || - component->state == NICE_COMPONENT_STATE_FAILED) - agent_signal_component_state_change (agent, stream_id, component_id, - NICE_COMPONENT_STATE_CONNECTING); - if (component->state < NICE_COMPONENT_STATE_CONNECTED) - agent_signal_component_state_change (agent, stream_id, component_id, - NICE_COMPONENT_STATE_CONNECTED); - agent_signal_component_state_change (agent, stream_id, component_id, - NICE_COMPONENT_STATE_READY); - - /* step: set the selected pair */ - nice_component_update_selected_pair (agent, component, &pair); - agent_signal_new_selected_pair (agent, stream_id, component_id, - pair.local, pair.remote); - - ret = TRUE; - - done: - agent_unlock_and_emit (agent); - return ret; -} - -NICEAPI_EXPORT gboolean -nice_agent_get_selected_pair (NiceAgent *agent, guint stream_id, - guint component_id, NiceCandidate **local, NiceCandidate **remote) -{ - NiceComponent *component; - NiceStream *stream; - gboolean ret = FALSE; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id >= 1, FALSE); - g_return_val_if_fail (component_id >= 1, FALSE); - g_return_val_if_fail (local != NULL, FALSE); - g_return_val_if_fail (remote != NULL, FALSE); - - agent_lock (agent); - - /* step: check that params specify an existing pair */ - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) - goto done; - - if (component->selected_pair.local && component->selected_pair.remote) { - *local = component->selected_pair.local; - *remote = component->selected_pair.remote; - ret = TRUE; - } - - done: - agent_unlock_and_emit (agent); - - return ret; -} - -NICEAPI_EXPORT GSocket * -nice_agent_get_selected_socket (NiceAgent *agent, guint stream_id, - guint component_id) -{ - NiceComponent *component; - NiceStream *stream; - NiceSocket *nice_socket; - GSocket *g_socket = NULL; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - g_return_val_if_fail (component_id >= 1, NULL); - - agent_lock (agent); - - /* Reliable streams are pseudotcp or MUST use RFC 4571 framing */ - if (agent->reliable) - goto done; - - /* step: check that params specify an existing pair */ - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) - goto done; - - if (!component->selected_pair.local || !component->selected_pair.remote) - goto done; - - if (component->selected_pair.local->type == NICE_CANDIDATE_TYPE_RELAYED) - goto done; - - /* ICE-TCP requires RFC4571 framing, even if unreliable */ - if (component->selected_pair.local->transport != NICE_CANDIDATE_TRANSPORT_UDP) - goto done; - - nice_socket = (NiceSocket *)component->selected_pair.local->sockptr; - if (nice_socket->fileno) - g_socket = g_object_ref (nice_socket->fileno); - - done: - agent_unlock_and_emit (agent); - - return g_socket; -} - -typedef struct _TimeoutData -{ - GWeakRef/**/ agent_ref; - NiceTimeoutLockedCallback function; - gpointer user_data; -} TimeoutData; - -static void -timeout_data_destroy (TimeoutData *data) -{ - g_weak_ref_clear (&data->agent_ref); - g_slice_free (TimeoutData, data); -} - -static TimeoutData * -timeout_data_new (NiceAgent *agent, NiceTimeoutLockedCallback function, - gpointer user_data) -{ - TimeoutData *data = g_slice_new0 (TimeoutData); - - g_weak_ref_init (&data->agent_ref, agent); - data->function = function; - data->user_data = user_data; - - return data; -} - -static gboolean -timeout_cb (gpointer user_data) -{ - TimeoutData *data = user_data; - NiceAgent *agent; - gboolean ret = G_SOURCE_REMOVE; - - agent = g_weak_ref_get (&data->agent_ref); - if (agent == NULL) { - return G_SOURCE_REMOVE; - } - - agent_lock (agent); - - /* A race condition might happen where the mutex above waits for the lock - * and in the meantime another thread destroys the source. - * In that case, we don't need to run the function since it should - * have been cancelled */ - if (g_source_is_destroyed (g_main_current_source ())) { - nice_debug ("Source was destroyed. Avoided race condition in timeout_cb"); - - agent_unlock (agent); - goto end; - } - - ret = data->function (agent, data->user_data); - - agent_unlock_and_emit (agent); - - end: - g_object_unref (agent); - - return ret; -} - -/* Create a new timer GSource with the given @name, @interval, callback - * @function and @data, and assign it to @out, destroying and freeing any - * existing #GSource in @out first. - * - * This guarantees that a timer won’t be overwritten without being destroyed. - * - * @interval is given in milliseconds. - */ -static void agent_timeout_add_with_context_internal (NiceAgent *agent, - GSource **out, const gchar *name, guint interval, gboolean seconds, - NiceTimeoutLockedCallback function, gpointer user_data) -{ - GSource *source; - TimeoutData *data; - - g_return_if_fail (function != NULL); - g_return_if_fail (out != NULL); - - /* Destroy any existing source. */ - if (*out != NULL) { - g_source_destroy (*out); - g_source_unref (*out); - *out = NULL; - } - - /* Create the new source. */ - if (seconds) - source = g_timeout_source_new_seconds (interval); - else - source = g_timeout_source_new (interval); - - g_source_set_name (source, name); - data = timeout_data_new (agent, function, user_data); - g_source_set_callback (source, timeout_cb, data, - (GDestroyNotify)timeout_data_destroy); - g_source_attach (source, agent->main_context); - - /* Return it! */ - *out = source; -} - -void agent_timeout_add_with_context (NiceAgent *agent, - GSource **out, const gchar *name, guint interval, - NiceTimeoutLockedCallback function, gpointer user_data) -{ - agent_timeout_add_with_context_internal (agent, out, name, interval, FALSE, - function, user_data); -} - -void agent_timeout_add_seconds_with_context (NiceAgent *agent, - GSource **out, const gchar *name, guint interval, - NiceTimeoutLockedCallback function, gpointer user_data) -{ - agent_timeout_add_with_context_internal (agent, out, name, interval, TRUE, - function, user_data); -} - -NICEAPI_EXPORT gboolean -nice_agent_set_selected_remote_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceCandidate *candidate) -{ - NiceComponent *component; - NiceStream *stream; - NiceCandidate *lcandidate = NULL; - gboolean ret = FALSE; - NiceCandidate *local = NULL, *remote = NULL; - guint64 priority; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id != 0, FALSE); - g_return_val_if_fail (component_id != 0, FALSE); - g_return_val_if_fail (candidate != NULL, FALSE); - - agent_lock (agent); - - /* step: check if the component exists*/ - if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) { - goto done; - } - - /* step: stop connectivity checks (note: for the whole stream) */ - conn_check_prune_stream (agent, stream); - - /* Store previous selected pair */ - local = component->selected_pair.local; - remote = component->selected_pair.remote; - priority = component->selected_pair.priority; - - /* step: set the selected pair */ - lcandidate = nice_component_set_selected_remote_candidate (component, agent, - candidate); - if (!lcandidate) - goto done; - - if (agent->reliable && !nice_socket_is_reliable (lcandidate->sockptr) && - pseudo_tcp_socket_is_closed (component->tcp)) { - nice_debug ("Agent %p: not setting selected remote candidate s%d:%d because" - " pseudo tcp socket does not exist in reliable mode", agent, - stream->id, component->id); - /* Revert back to previous selected pair */ - /* FIXME: by doing this, we lose the keepalive tick */ - component->selected_pair.local = local; - component->selected_pair.remote = remote; - component->selected_pair.priority = priority; - goto done; - } - - /* step: change component state; we could be in STATE_DISCONNECTED; skip - * STATE_GATHERING and continue through the states to give client code a nice - * logical progression. See http://phabricator.freedesktop.org/D218 for - * discussion. */ - if (component->state < NICE_COMPONENT_STATE_CONNECTING || - component->state == NICE_COMPONENT_STATE_FAILED) - agent_signal_component_state_change (agent, stream_id, component_id, - NICE_COMPONENT_STATE_CONNECTING); - if (component->state < NICE_COMPONENT_STATE_CONNECTED) - agent_signal_component_state_change (agent, stream_id, component_id, - NICE_COMPONENT_STATE_CONNECTED); - agent_signal_component_state_change (agent, stream_id, component_id, - NICE_COMPONENT_STATE_READY); - - agent_signal_new_selected_pair (agent, stream_id, component_id, - lcandidate, candidate); - - ret = TRUE; - - done: - agent_unlock_and_emit (agent); - return ret; -} - -void -_priv_set_socket_tos (NiceAgent *agent, NiceSocket *sock, gint tos) -{ - if (sock->fileno == NULL) - return; - - if (setsockopt (g_socket_get_fd (sock->fileno), IPPROTO_IP, - IP_TOS, (const char *) &tos, sizeof (tos)) < 0) { - nice_debug ("Agent %p: Could not set socket ToS: %s", agent, - g_strerror (errno)); - } -#ifdef IPV6_TCLASS - if (setsockopt (g_socket_get_fd (sock->fileno), IPPROTO_IPV6, - IPV6_TCLASS, (const char *) &tos, sizeof (tos)) < 0) { - nice_debug ("Agent %p: Could not set IPV6 socket ToS: %s", agent, - g_strerror (errno)); - } -#endif -} - - -NICEAPI_EXPORT void -nice_agent_set_stream_tos (NiceAgent *agent, - guint stream_id, gint tos) -{ - GSList *i, *j; - NiceStream *stream; - - g_return_if_fail (NICE_IS_AGENT (agent)); - g_return_if_fail (stream_id >= 1); - - agent_lock (agent); - - stream = agent_find_stream (agent, stream_id); - if (stream == NULL) - goto done; - - stream->tos = tos; - for (i = stream->components; i; i = i->next) { - NiceComponent *component = i->data; - - for (j = component->local_candidates; j; j = j->next) { - NiceCandidate *local_candidate = j->data; - - _priv_set_socket_tos (agent, local_candidate->sockptr, tos); - } - } - - done: - agent_unlock_and_emit (agent); -} - -NICEAPI_EXPORT void -nice_agent_set_software (NiceAgent *agent, const gchar *software) -{ - g_return_if_fail (NICE_IS_AGENT (agent)); - - agent_lock (agent); - - g_free (agent->software_attribute); - if (software) - agent->software_attribute = g_strdup_printf ("%s/%s", - software, PACKAGE_STRING); - else - agent->software_attribute = NULL; - - nice_agent_reset_all_stun_agents (agent, TRUE); - - agent_unlock_and_emit (agent); -} - -NICEAPI_EXPORT gboolean -nice_agent_set_stream_name (NiceAgent *agent, guint stream_id, - const gchar *name) -{ - NiceStream *stream_to_name = NULL; - GSList *i; - gboolean ret = FALSE; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id >= 1, FALSE); - g_return_val_if_fail (name, FALSE); - - if (strcmp (name, "audio") && - strcmp (name, "video") && - strcmp (name, "text") && - strcmp (name, "application") && - strcmp (name, "message") && - strcmp (name, "image")) { - g_critical ("Stream name %s will produce invalid SDP, only \"audio\"," - " \"video\", \"text\", \"application\", \"image\" and \"message\"" - " are valid", name); - } - - agent_lock (agent); - - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - - if (stream->id != stream_id && - g_strcmp0 (stream->name, name) == 0) - goto done; - else if (stream->id == stream_id) - stream_to_name = stream; - } - - if (stream_to_name == NULL) - goto done; - - if (stream_to_name->name) - g_free (stream_to_name->name); - stream_to_name->name = g_strdup (name); - ret = TRUE; - - done: - agent_unlock_and_emit (agent); - - return ret; -} - -NICEAPI_EXPORT const gchar * -nice_agent_get_stream_name (NiceAgent *agent, guint stream_id) -{ - NiceStream *stream; - gchar *name = NULL; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - - agent_lock (agent); - - stream = agent_find_stream (agent, stream_id); - if (stream == NULL) - goto done; - - name = stream->name; - - done: - agent_unlock_and_emit (agent); - return name; -} - -static NiceCandidate * -_get_default_local_candidate_locked (NiceAgent *agent, - NiceStream *stream, NiceComponent *component) -{ - GSList *i; - NiceCandidate *default_candidate = NULL; - NiceCandidate *default_rtp_candidate = NULL; - - if (component->id != NICE_COMPONENT_TYPE_RTP) { - NiceComponent *rtp_component; - - if (!agent_find_component (agent, stream->id, NICE_COMPONENT_TYPE_RTP, - NULL, &rtp_component)) - goto done; - - default_rtp_candidate = _get_default_local_candidate_locked (agent, stream, - rtp_component); - if (default_rtp_candidate == NULL) - goto done; - } - - - for (i = component->local_candidates; i; i = i->next) { - NiceCandidate *local_candidate = i->data; - - if (agent->force_relay && - local_candidate->type != NICE_CANDIDATE_TYPE_RELAYED) - continue; - - /* Only check for ipv4 candidates */ - if (nice_address_ip_version (&local_candidate->addr) != 4) - continue; - if (component->id == NICE_COMPONENT_TYPE_RTP) { - if (default_candidate == NULL || - local_candidate->priority < default_candidate->priority) { - default_candidate = local_candidate; - } - } else if (strncmp (local_candidate->foundation, - default_rtp_candidate->foundation, - NICE_CANDIDATE_MAX_FOUNDATION) == 0) { - default_candidate = local_candidate; - break; - } - } - - done: - return default_candidate; -} - -NICEAPI_EXPORT NiceCandidate * -nice_agent_get_default_local_candidate (NiceAgent *agent, - guint stream_id, guint component_id) -{ - NiceStream *stream = NULL; - NiceComponent *component = NULL; - NiceCandidate *default_candidate = NULL; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - g_return_val_if_fail (component_id >= 1, NULL); - - agent_lock (agent); - - /* step: check if the component exists*/ - if (!agent_find_component (agent, stream_id, component_id, - &stream, &component)) - goto done; - - default_candidate = _get_default_local_candidate_locked (agent, stream, - component); - if (default_candidate) - default_candidate = nice_candidate_copy (default_candidate); - - done: - agent_unlock_and_emit (agent); - - return default_candidate; -} - -static const gchar * -_cand_type_to_sdp (NiceCandidateType type) { - switch(type) { - case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: - return "srflx"; - case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE: - return "prflx"; - case NICE_CANDIDATE_TYPE_RELAYED: - return "relay"; - case NICE_CANDIDATE_TYPE_HOST: - default: - return "host"; - } -} - -static const gchar * -_transport_to_sdp (NiceCandidateTransport type) { - switch(type) { - case NICE_CANDIDATE_TRANSPORT_UDP: - return "UDP"; - case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE: - case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE: - case NICE_CANDIDATE_TRANSPORT_TCP_SO: - return "TCP"; - default: - return "???"; - } -} - -static const gchar * -_transport_to_sdp_tcptype (NiceCandidateTransport type) { - switch(type) { - case NICE_CANDIDATE_TRANSPORT_UDP: - return ""; - case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE: - return "active"; - case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE: - return "passive"; - case NICE_CANDIDATE_TRANSPORT_TCP_SO: - return "so"; - default: - return ""; - } -} - -static void -_generate_candidate_sdp (NiceAgent *agent, - NiceCandidate *candidate, GString *sdp) -{ - gchar ip4[INET6_ADDRSTRLEN]; - guint16 port; - - nice_address_to_string (&candidate->addr, ip4); - port = nice_address_get_port (&candidate->addr); - g_string_append_printf (sdp, "a=candidate:%.*s %d %s %d %s %d", - NICE_CANDIDATE_MAX_FOUNDATION, candidate->foundation, - candidate->component_id, - _transport_to_sdp (candidate->transport), - candidate->priority, ip4, port == 0 ? 9 : port); - g_string_append_printf (sdp, " typ %s", _cand_type_to_sdp (candidate->type)); - if (nice_address_is_valid (&candidate->base_addr) && - !nice_address_equal (&candidate->addr, &candidate->base_addr)) { - port = nice_address_get_port (&candidate->base_addr); - nice_address_to_string (&candidate->base_addr, ip4); - g_string_append_printf (sdp, " raddr %s rport %d", ip4, - port == 0 ? 9 : port); - } - if (candidate->transport != NICE_CANDIDATE_TRANSPORT_UDP) { - g_string_append_printf (sdp, " tcptype %s", - _transport_to_sdp_tcptype (candidate->transport)); - } -} - -static void -_generate_stream_sdp (NiceAgent *agent, NiceStream *stream, - GString *sdp, gboolean include_non_ice) -{ - GSList *i, *j; - - if (include_non_ice) { - NiceAddress rtp, rtcp; - gchar ip4[INET6_ADDRSTRLEN] = ""; - - nice_address_init (&rtp); - nice_address_set_ipv4 (&rtp, 0); - nice_address_init (&rtcp); - nice_address_set_ipv4 (&rtcp, 0); - - /* Find default candidates */ - for (i = stream->components; i; i = i->next) { - NiceComponent *component = i->data; - NiceCandidate *default_candidate; - - if (component->id == NICE_COMPONENT_TYPE_RTP) { - default_candidate = _get_default_local_candidate_locked (agent, stream, - component); - if (default_candidate) - rtp = default_candidate->addr; - } else if (component->id == NICE_COMPONENT_TYPE_RTCP) { - default_candidate = _get_default_local_candidate_locked (agent, stream, - component); - if (default_candidate) - rtcp = default_candidate->addr; - } - } - - nice_address_to_string (&rtp, ip4); - g_string_append_printf (sdp, "m=%s %d ICE/SDP\n", - stream->name ? stream->name : "-", nice_address_get_port (&rtp)); - g_string_append_printf (sdp, "c=IN IP4 %s\n", ip4); - if (nice_address_get_port (&rtcp) != 0) - g_string_append_printf (sdp, "a=rtcp:%d\n", - nice_address_get_port (&rtcp)); - } - - g_string_append_printf (sdp, "a=ice-ufrag:%s\n", stream->local_ufrag); - g_string_append_printf (sdp, "a=ice-pwd:%s\n", stream->local_password); - - for (i = stream->components; i; i = i->next) { - NiceComponent *component = i->data; - - for (j = component->local_candidates; j; j = j->next) { - NiceCandidate *candidate = j->data; - - if (agent->force_relay && candidate->type != NICE_CANDIDATE_TYPE_RELAYED) - continue; - - _generate_candidate_sdp (agent, candidate, sdp); - g_string_append (sdp, "\n"); - } - } -} - -NICEAPI_EXPORT gchar * -nice_agent_generate_local_sdp (NiceAgent *agent) -{ - GString * sdp = g_string_new (NULL); - GSList *i; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - - agent_lock (agent); - - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - - _generate_stream_sdp (agent, stream, sdp, TRUE); - } - - agent_unlock_and_emit (agent); - - return g_string_free (sdp, FALSE); -} - -NICEAPI_EXPORT gchar * -nice_agent_generate_local_stream_sdp (NiceAgent *agent, guint stream_id, - gboolean include_non_ice) -{ - GString *sdp = NULL; - gchar *ret = NULL; - NiceStream *stream; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - - agent_lock (agent); - - stream = agent_find_stream (agent, stream_id); - if (stream == NULL) - goto done; - - sdp = g_string_new (NULL); - _generate_stream_sdp (agent, stream, sdp, include_non_ice); - ret = g_string_free (sdp, FALSE); - - done: - agent_unlock_and_emit (agent); - - return ret; -} - -NICEAPI_EXPORT gchar * -nice_agent_generate_local_candidate_sdp (NiceAgent *agent, - NiceCandidate *candidate) -{ - GString *sdp = NULL; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (candidate != NULL, NULL); - - agent_lock (agent); - - sdp = g_string_new (NULL); - _generate_candidate_sdp (agent, candidate, sdp); - - agent_unlock_and_emit (agent); - - return g_string_free (sdp, FALSE); -} - -NICEAPI_EXPORT gint -nice_agent_parse_remote_sdp (NiceAgent *agent, const gchar *sdp) -{ - NiceStream *current_stream = NULL; - gchar **sdp_lines = NULL; - GSList *stream_item = NULL; - gint i; - gint ret = 0; - - g_return_val_if_fail (NICE_IS_AGENT (agent), -1); - g_return_val_if_fail (sdp != NULL, -1); - - agent_lock (agent); - - sdp_lines = g_strsplit (sdp, "\n", 0); - for (i = 0; sdp_lines && sdp_lines[i]; i++) { - if (g_str_has_prefix (sdp_lines[i], "m=")) { - if (stream_item == NULL) - stream_item = agent->streams; - else - stream_item = stream_item->next; - if (!stream_item) { - g_critical("More streams in SDP than in agent"); - ret = -1; - goto done; - } - current_stream = stream_item->data; - } else if (g_str_has_prefix (sdp_lines[i], "a=ice-ufrag:")) { - if (current_stream == NULL) { - ret = -1; - goto done; - } - g_strlcpy (current_stream->remote_ufrag, sdp_lines[i] + 12, - NICE_STREAM_MAX_UFRAG); - } else if (g_str_has_prefix (sdp_lines[i], "a=ice-pwd:")) { - if (current_stream == NULL) { - ret = -1; - goto done; - } - g_strlcpy (current_stream->remote_password, sdp_lines[i] + 10, - NICE_STREAM_MAX_PWD); - } else if (g_str_has_prefix (sdp_lines[i], "a=candidate:")) { - NiceCandidate *candidate = NULL; - NiceComponent *component = NULL; - GSList *cands = NULL; - gint added; - - if (current_stream == NULL) { - ret = -1; - goto done; - } - candidate = nice_agent_parse_remote_candidate_sdp (agent, - current_stream->id, sdp_lines[i]); - if (candidate == NULL) { - ret = -1; - goto done; - } - - if (!agent_find_component (agent, candidate->stream_id, - candidate->component_id, NULL, &component)) { - nice_candidate_free (candidate); - ret = -1; - goto done; - } - cands = g_slist_prepend (cands, candidate); - added = _set_remote_candidates_locked (agent, current_stream, - component, cands); - g_slist_free_full(cands, (GDestroyNotify)&nice_candidate_free); - if (added > 0) - ret++; - } - } - - done: - if (sdp_lines) - g_strfreev(sdp_lines); - - agent_unlock_and_emit (agent); - - return ret; -} - -NICEAPI_EXPORT GSList * -nice_agent_parse_remote_stream_sdp (NiceAgent *agent, guint stream_id, - const gchar *sdp, gchar **ufrag, gchar **pwd) -{ - NiceStream *stream = NULL; - gchar **sdp_lines = NULL; - GSList *candidates = NULL; - gint i; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - g_return_val_if_fail (sdp != NULL, NULL); - - agent_lock (agent); - - stream = agent_find_stream (agent, stream_id); - if (stream == NULL) { - goto done; - } - - sdp_lines = g_strsplit (sdp, "\n", 0); - for (i = 0; sdp_lines && sdp_lines[i]; i++) { - if (ufrag && g_str_has_prefix (sdp_lines[i], "a=ice-ufrag:")) { - *ufrag = g_strdup (sdp_lines[i] + 12); - } else if (pwd && g_str_has_prefix (sdp_lines[i], "a=ice-pwd:")) { - *pwd = g_strdup (sdp_lines[i] + 10); - } else if (g_str_has_prefix (sdp_lines[i], "a=candidate:")) { - NiceCandidate *candidate = NULL; - - candidate = nice_agent_parse_remote_candidate_sdp (agent, stream->id, - sdp_lines[i]); - if (candidate == NULL) { - g_slist_free_full(candidates, (GDestroyNotify)&nice_candidate_free); - candidates = NULL; - break; - } - candidates = g_slist_prepend (candidates, candidate); - } - } - - done: - if (sdp_lines) - g_strfreev(sdp_lines); - - agent_unlock_and_emit (agent); - - return candidates; -} - -NICEAPI_EXPORT NiceCandidate * -nice_agent_parse_remote_candidate_sdp (NiceAgent *agent, guint stream_id, - const gchar *sdp) -{ - NiceCandidate *candidate = NULL; - int ntype = -1; - gchar **tokens = NULL; - const gchar *foundation = NULL; - guint component_id = 0; - const gchar *transport = NULL; - guint32 priority = 0; - const gchar *addr = NULL; - guint16 port = 0; - const gchar *type = NULL; - const gchar *tcptype = NULL; - const gchar *raddr = NULL; - guint16 rport = 0; - static const gchar *type_names[] = {"host", "srflx", "prflx", "relay"}; - NiceCandidateTransport ctransport; - guint i; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - g_return_val_if_fail (sdp != NULL, NULL); - - if (!g_str_has_prefix (sdp, "a=candidate:")) - goto done; - - tokens = g_strsplit (sdp + 12, " ", 0); - for (i = 0; tokens && tokens[i]; i++) { - switch (i) { - case 0: - foundation = tokens[i]; - break; - case 1: - component_id = (guint) g_ascii_strtoull (tokens[i], NULL, 10); - break; - case 2: - transport = tokens[i]; - break; - case 3: - priority = (guint32) g_ascii_strtoull (tokens[i], NULL, 10); - break; - case 4: - addr = tokens[i]; - break; - case 5: - port = (guint16) g_ascii_strtoull (tokens[i], NULL, 10); - break; - default: - if (tokens[i + 1] == NULL) - goto done; - - if (g_strcmp0 (tokens[i], "typ") == 0) { - type = tokens[i + 1]; - } else if (g_strcmp0 (tokens[i], "raddr") == 0) { - raddr = tokens[i + 1]; - } else if (g_strcmp0 (tokens[i], "rport") == 0) { - rport = (guint16) g_ascii_strtoull (tokens[i + 1], NULL, 10); - } else if (g_strcmp0 (tokens[i], "tcptype") == 0) { - tcptype = tokens[i + 1]; - } - i++; - break; - } - } - if (type == NULL) - goto done; - - ntype = -1; - for (i = 0; i < G_N_ELEMENTS (type_names); i++) { - if (g_strcmp0 (type, type_names[i]) == 0) { - ntype = i; - break; - } - } - if (ntype == -1) - goto done; - - if (g_ascii_strcasecmp (transport, "UDP") == 0) - ctransport = NICE_CANDIDATE_TRANSPORT_UDP; - else if (g_ascii_strcasecmp (transport, "TCP-SO") == 0) - ctransport = NICE_CANDIDATE_TRANSPORT_TCP_SO; - else if (g_ascii_strcasecmp (transport, "TCP-ACT") == 0) - ctransport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; - else if (g_ascii_strcasecmp (transport, "TCP-PASS") == 0) - ctransport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE; - else if (g_ascii_strcasecmp (transport, "TCP") == 0) { - if (g_ascii_strcasecmp (tcptype, "so") == 0) - ctransport = NICE_CANDIDATE_TRANSPORT_TCP_SO; - else if (g_ascii_strcasecmp (tcptype, "active") == 0) - ctransport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; - else if (g_ascii_strcasecmp (tcptype, "passive") == 0) - ctransport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE; - else - goto done; - } else - goto done; - - candidate = nice_candidate_new(ntype); - candidate->component_id = component_id; - candidate->stream_id = stream_id; - candidate->transport = ctransport; - g_strlcpy(candidate->foundation, foundation, NICE_CANDIDATE_MAX_FOUNDATION); - candidate->priority = priority; - - if (!nice_address_set_from_string (&candidate->addr, addr)) { - nice_candidate_free (candidate); - candidate = NULL; - goto done; - } - nice_address_set_port (&candidate->addr, port); - - if (raddr && rport) { - if (!nice_address_set_from_string (&candidate->base_addr, raddr)) { - nice_candidate_free (candidate); - candidate = NULL; - goto done; - } - nice_address_set_port (&candidate->base_addr, rport); - } - - done: - if (tokens) - g_strfreev(tokens); - - return candidate; -} - - -NICEAPI_EXPORT GIOStream * -nice_agent_get_io_stream (NiceAgent *agent, guint stream_id, - guint component_id) -{ - GIOStream *iostream = NULL; - NiceComponent *component; - - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - g_return_val_if_fail (component_id >= 1, NULL); - - g_return_val_if_fail (agent->reliable, NULL); - - agent_lock (agent); - - if (!agent_find_component (agent, stream_id, component_id, NULL, &component)) - goto done; - - if (component->iostream == NULL) - component->iostream = nice_io_stream_new (agent, stream_id, component_id); - - iostream = g_object_ref (component->iostream); - - done: - agent_unlock_and_emit (agent); - - return iostream; -} - -NICEAPI_EXPORT gboolean -nice_agent_forget_relays (NiceAgent *agent, guint stream_id, guint component_id) -{ - NiceComponent *component; - gboolean ret = TRUE; - - g_return_val_if_fail (NICE_IS_AGENT (agent), FALSE); - g_return_val_if_fail (stream_id >= 1, FALSE); - g_return_val_if_fail (component_id >= 1, FALSE); - - agent_lock (agent); - - if (!agent_find_component (agent, stream_id, component_id, NULL, &component)) { - ret = FALSE; - goto done; - } - - nice_component_clean_turn_servers (agent, component); - - done: - agent_unlock_and_emit (agent); - - return ret; -} - -/* Helper function to allow us to send connchecks reliably. - * If the transport is reliable, then we request a reliable send, which will - * either send the data, or queue it in the case of unestablished http/socks5 - * proxies or tcp-turn. If the transport is not reliable, then it could be an - * unreliable tcp-bsd, so we still try a reliable send to see if it can succeed - * meaning the message was queued, or if it failed, then it was either udp-bsd - * or turn and so we retry with a non reliable send and let the retransmissions - * take care of the rest. - * This is in order to avoid having to retransmit something if the underlying - * socket layer can queue the message and send it once a connection is - * established. - */ -gssize -agent_socket_send (NiceSocket *sock, const NiceAddress *addr, gsize len, - const gchar *buf) -{ - if (nice_socket_is_reliable (sock)) { - guint16 rfc4571_frame = htons (len); - GOutputVector local_buf[2] = {{&rfc4571_frame, 2}, { buf, len }}; - NiceOutputMessage local_message = { local_buf, 2}; - gint ret; - - /* ICE-TCP requires that all packets be framed with RFC4571 */ - ret = nice_socket_send_messages_reliable (sock, addr, &local_message, 1); - if (ret == 1) - return len; - return ret; - } else { - gssize ret = nice_socket_send_reliable (sock, addr, len, buf); - if (ret < 0) - ret = nice_socket_send (sock, addr, len, buf); - return ret; - } -} - -NiceComponentState -nice_agent_get_component_state (NiceAgent *agent, - guint stream_id, guint component_id) -{ - NiceComponentState state = NICE_COMPONENT_STATE_FAILED; - NiceComponent *component; - - agent_lock (agent); - - if (agent_find_component (agent, stream_id, component_id, NULL, &component)) - state = component->state; - - agent_unlock (agent); - - return state; -} - -gboolean -nice_agent_peer_candidate_gathering_done (NiceAgent *agent, guint stream_id) -{ - NiceStream *stream; - gboolean result = FALSE; - - agent_lock (agent); - - stream = agent_find_stream (agent, stream_id); - if (stream) { - stream->peer_gathering_done = TRUE; - result = TRUE; - } - - agent_unlock (agent); - - return result; -} - -static gboolean -on_agent_refreshes_pruned (NiceAgent *agent, gpointer user_data) -{ - GTask *task = user_data; - - /* This is called from a timeout cb with agent lock held */ - - agent_unlock (agent); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); - - agent_lock (agent); - - return G_SOURCE_REMOVE; -} - -void -nice_agent_close_async (NiceAgent *agent, GAsyncReadyCallback callback, - gpointer callback_data) -{ - GTask *task; - - task = g_task_new (agent, NULL, callback, callback_data); - g_task_set_source_tag (task, nice_agent_close_async); - - agent_lock (agent); - - refresh_prune_agent_async (agent, on_agent_refreshes_pruned, task); - - agent_unlock (agent); -} - - -NICEAPI_EXPORT GPtrArray * -nice_agent_get_sockets (NiceAgent *agent, guint stream_id, guint component_id) -{ - GPtrArray *array = NULL; - NiceComponent *component; - - agent_lock (agent); - if (agent_find_component (agent, stream_id, component_id, NULL, &component)) - array = nice_component_get_sockets (component); - agent_unlock (agent); - - return array; -} diff --git a/agent/agent.h b/agent/agent.h deleted file mode 100644 index 1164138..0000000 --- a/agent/agent.h +++ /dev/null @@ -1,1709 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2010 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2010 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef __LIBNICE_AGENT_H__ -#define __LIBNICE_AGENT_H__ - -/** - * SECTION:agent - * @short_description: ICE agent API implementation - * @see_also: #NiceCandidate, #NiceAddress - * @include: agent.h - * @stability: Stable - * - * The #NiceAgent is your main object when using libnice. - * It is the agent that will take care of everything relating to ICE. - * It will take care of discovering your local candidates and do - * connectivity checks to create a stream of data between you and your peer. - * - * A #NiceAgent must always be used with a #GMainLoop running the #GMainContext - * passed into nice_agent_new() (or nice_agent_new_reliable()). Without the - * #GMainContext being iterated, the agent’s timers will not fire, etc. - * - * Streams and their components are referenced by integer IDs (with respect to a - * given #NiceAgent). These IDs are guaranteed to be positive (i.e. non-zero) - * for valid streams/components. - * - * To complete the ICE connectivity checks, the user must either register - * an I/O callback (with nice_agent_attach_recv()) or call nice_agent_recv_messages() - * in a loop on a dedicated thread. - * Technically, #NiceAgent does not poll the streams on its own, since - * user data could arrive at any time; to receive STUN packets - * required for establishing ICE connectivity, it is backpiggying - * on the facility chosen by the user. #NiceAgent will handle all STUN - * packets internally; they're never actually passed to the I/O callback - * or returned from nice_agent_recv_messages() and related functions. - * - * Each stream can receive data in one of two ways: using - * nice_agent_attach_recv() or nice_agent_recv_messages() (and the derived - * #NiceInputStream and #NiceIOStream classes accessible using - * nice_agent_get_io_stream()). nice_agent_attach_recv() is non-blocking: it - * takes a user-provided callback function and attaches the stream’s socket to - * the provided #GMainContext, invoking the callback in that context for every - * packet received. nice_agent_recv_messages() instead blocks on receiving a - * packet, and writes it directly into a user-provided buffer. This reduces the - * number of callback invokations and (potentially) buffer copies required to - * receive packets. nice_agent_recv_messages() (or #NiceInputStream) is designed - * to be used in a blocking loop in a separate thread. - * - * - * Simple example on how to use libnice - * - * guint stream_id; - * gchar buffer[] = "hello world!"; - * gchar *ufrag = NULL, *pwd = NULL; - * gchar *remote_ufrag, *remote_pwd; - * GSList *lcands = NULL; - * - * // Create a nice agent, passing in the global default GMainContext. - * NiceAgent *agent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); - * spawn_thread_to_run_main_loop (g_main_loop_new (NULL, FALSE)); - * - * // Connect the signals - * g_signal_connect (G_OBJECT (agent), "candidate-gathering-done", - * G_CALLBACK (cb_candidate_gathering_done), NULL); - * g_signal_connect (G_OBJECT (agent), "component-state-changed", - * G_CALLBACK (cb_component_state_changed), NULL); - * g_signal_connect (G_OBJECT (agent), "new-selected-pair", - * G_CALLBACK (cb_new_selected_pair), NULL); - * - * // Create a new stream with one component and start gathering candidates - * stream_id = nice_agent_add_stream (agent, 1); - * nice_agent_gather_candidates (agent, stream_id); - * - * // Attach I/O callback the component to ensure that: - * // 1) agent gets its STUN packets (not delivered to cb_nice_recv) - * // 2) you get your own data - * nice_agent_attach_recv (agent, stream_id, 1, NULL, - * cb_nice_recv, NULL); - * - * // ... Wait until the signal candidate-gathering-done is fired ... - * lcands = nice_agent_get_local_candidates(agent, stream_id, 1); - - * nice_agent_get_local_credentials(agent, stream_id, &ufrag, &pwd); - * - * // ... Send local candidates and credentials to the peer - * - * // Set the peer's remote credentials and remote candidates - * nice_agent_set_remote_credentials (agent, stream_id, remote_ufrag, remote_pwd); - * nice_agent_set_remote_candidates (agent, stream_id, 1, rcands); - * - * // ... Wait until the signal new-selected-pair is fired ... - * // Send our message! - * nice_agent_send (agent, stream_id, 1, sizeof(buffer), buffer); - * - * // Anything received will be received through the cb_nice_recv callback. - * // You must be running a GMainLoop on the global default GMainContext in - * // another thread for this to work. - * - * // Destroy the object - * g_object_unref(agent); - * - * - * - * - * Refer to the examples in the examples/ subdirectory of the libnice source for - * more complete examples. - * - */ - - -#include -#include - -/** - * NiceAgent: - * - * The #NiceAgent is the main GObject of the libnice library and represents - * the ICE agent. - */ -typedef struct _NiceAgent NiceAgent; - -#include "address.h" -#include "candidate.h" -#include "debug.h" - - -G_BEGIN_DECLS - -/** - * NiceInputMessage: - * @buffers: (array length=n_buffers): unowned array of #GInputVector buffers to - * store data in for this message - * @n_buffers: number of #GInputVectors in @buffers, or -1 to indicate @buffers - * is %NULL-terminated - * @from: (allow-none): return location to store the address of the peer who - * transmitted the message, or %NULL - * @length: total number of valid bytes contiguously stored in @buffers - * - * Represents a single message received off the network. For reliable - * connections, this is essentially just an array of buffers (specifically, - * @from can be ignored). for non-reliable connections, it represents a single - * packet as received from the OS. - * - * @n_buffers may be -1 to indicate that @buffers is terminated by a - * #GInputVector with a %NULL buffer pointer. - * - * By providing arrays of #NiceInputMessages to functions like - * nice_agent_recv_messages(), multiple messages may be received with a single - * call, which is more efficient than making multiple calls in a loop. In this - * manner, nice_agent_recv_messages() is analogous to recvmmsg(); and - * #NiceInputMessage to struct mmsghdr. - * - * Since: 0.1.5 - */ -typedef struct { - GInputVector *buffers; - gint n_buffers; /* may be -1 to indicate @buffers is NULL-terminated */ - NiceAddress *from; /* return location for address of message sender */ - gsize length; /* sum of the lengths of @buffers */ -} NiceInputMessage; - -/** - * NiceOutputMessage: - * @buffers: (array length=n_buffers): unowned array of #GOutputVector buffers - * which contain data to transmit for this message - * @n_buffers: number of #GOutputVectors in @buffers, or -1 to indicate @buffers - * is %NULL-terminated - * - * Represents a single message to transmit on the network. For - * reliable connections, this is essentially just an array of - * buffer. for non-reliable connections, it represents a single packet - * to send to the OS. - * - * @n_buffers may be -1 to indicate that @buffers is terminated by a - * #GOutputVector with a %NULL buffer pointer. - * - * By providing arrays of #NiceOutputMessages to functions like - * nice_agent_send_messages_nonblocking(), multiple messages may be transmitted - * with a single call, which is more efficient than making multiple calls in a - * loop. In this manner, nice_agent_send_messages_nonblocking() is analogous to - * sendmmsg(); and #NiceOutputMessage to struct mmsghdr. - * - * Since: 0.1.5 - */ -typedef struct { - GOutputVector *buffers; - gint n_buffers; -} NiceOutputMessage; - - -#define NICE_TYPE_AGENT nice_agent_get_type() - -#define NICE_AGENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ - NICE_TYPE_AGENT, NiceAgent)) - -#define NICE_AGENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), \ - NICE_TYPE_AGENT, NiceAgentClass)) - -#define NICE_IS_AGENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ - NICE_TYPE_AGENT)) - -#define NICE_IS_AGENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), \ - NICE_TYPE_AGENT)) - -#define NICE_AGENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), \ - NICE_TYPE_AGENT, NiceAgentClass)) - -typedef struct _NiceAgentClass NiceAgentClass; - -struct _NiceAgentClass -{ - GObjectClass parent_class; -}; - - -GType nice_agent_get_type (void); - - -/** - * NICE_AGENT_MAX_REMOTE_CANDIDATES: - * - * A hard limit for the number of remote candidates. This - * limit is enforced to protect against malevolent remote - * clients. - */ -#define NICE_AGENT_MAX_REMOTE_CANDIDATES 25 - -/** - * NiceComponentState: - * @NICE_COMPONENT_STATE_DISCONNECTED: No activity scheduled - * @NICE_COMPONENT_STATE_GATHERING: Gathering local candidates - * @NICE_COMPONENT_STATE_CONNECTING: Establishing connectivity - * @NICE_COMPONENT_STATE_CONNECTED: At least one working candidate pair - * @NICE_COMPONENT_STATE_READY: ICE concluded, candidate pair selection - * is now final - * @NICE_COMPONENT_STATE_FAILED: Connectivity checks have been completed, - * but connectivity was not established - * @NICE_COMPONENT_STATE_LAST: Dummy state - * - * An enum representing the state of a component. - * See also: #NiceAgent::component-state-changed - */ -typedef enum -{ - NICE_COMPONENT_STATE_DISCONNECTED, - NICE_COMPONENT_STATE_GATHERING, - NICE_COMPONENT_STATE_CONNECTING, - NICE_COMPONENT_STATE_CONNECTED, - NICE_COMPONENT_STATE_READY, - NICE_COMPONENT_STATE_FAILED, - NICE_COMPONENT_STATE_LAST -} NiceComponentState; - - -/** - * NiceComponentType: - * @NICE_COMPONENT_TYPE_RTP: RTP Component type - * @NICE_COMPONENT_TYPE_RTCP: RTCP Component type - * - * Convenience enum representing the type of a component for use as the - * component_id for RTP/RTCP usages. - - Example of use. - - nice_agent_send (agent, stream_id, NICE_COMPONENT_TYPE_RTP, len, buf); - - - */ -typedef enum -{ - NICE_COMPONENT_TYPE_RTP = 1, - NICE_COMPONENT_TYPE_RTCP = 2 -} NiceComponentType; - - -/** - * NiceCompatibility: - * @NICE_COMPATIBILITY_RFC5245: Use compatibility with the RFC5245 ICE-UDP specs - * and RFC6544 ICE-TCP specs - * @NICE_COMPATIBILITY_GOOGLE: Use compatibility for Google Talk specs - * @NICE_COMPATIBILITY_MSN: Use compatibility for MSN Messenger specs - * @NICE_COMPATIBILITY_WLM2009: Use compatibility with Windows Live Messenger - * 2009 - * @NICE_COMPATIBILITY_OC2007: Use compatibility with Microsoft Office Communicator 2007 - * @NICE_COMPATIBILITY_OC2007R2: Use compatibility with Microsoft Office Communicator 2007 R2 - * @NICE_COMPATIBILITY_DRAFT19: Use compatibility for ICE Draft 19 specs - * @NICE_COMPATIBILITY_LAST: Dummy last compatibility mode - * - * An enum to specify which compatible specifications the #NiceAgent should use. - * Use with nice_agent_new() - * - * @NICE_COMPATIBILITY_DRAFT19 is deprecated and should not be used - * in newly-written code. It is kept for compatibility reasons and - * represents the same compatibility as @NICE_COMPATIBILITY_RFC5245 - - - If @NICE_COMPATIBILITY_RFC5245 compatibility mode is used for a non-reliable - agent, then ICE-UDP will be used with higher priority and ICE-TCP will also - be used when the UDP connectivity fails. If it is used with a reliable agent, - then ICE-UDP will be used with the TCP-Over-UDP (#PseudoTcpSocket) if ICE-TCP - fails and ICE-UDP succeeds. - - - * - */ -typedef enum -{ - NICE_COMPATIBILITY_RFC5245 = 0, - NICE_COMPATIBILITY_DRAFT19 = NICE_COMPATIBILITY_RFC5245, - NICE_COMPATIBILITY_GOOGLE, - NICE_COMPATIBILITY_MSN, - NICE_COMPATIBILITY_WLM2009, - NICE_COMPATIBILITY_OC2007, - NICE_COMPATIBILITY_OC2007R2, - NICE_COMPATIBILITY_LAST = NICE_COMPATIBILITY_OC2007R2, -} NiceCompatibility; - -/** - * NiceProxyType: - * @NICE_PROXY_TYPE_NONE: Do not use a proxy - * @NICE_PROXY_TYPE_SOCKS5: Use a SOCKS5 proxy - * @NICE_PROXY_TYPE_HTTP: Use an HTTP proxy - * @NICE_PROXY_TYPE_LAST: Dummy last proxy type - * - * An enum to specify which proxy type to use for relaying. - * Note that the proxies will only be used with TCP TURN relaying. - * See also: #NiceAgent:proxy-type - * - * Since: 0.0.4 - */ -typedef enum -{ - NICE_PROXY_TYPE_NONE = 0, - NICE_PROXY_TYPE_SOCKS5, - NICE_PROXY_TYPE_HTTP, - NICE_PROXY_TYPE_LAST = NICE_PROXY_TYPE_HTTP, -} NiceProxyType; - -/** - * NiceNominationMode: - * @NICE_NOMINATION_MODE_AGGRESSIVE: Aggressive nomination mode - * @NICE_NOMINATION_MODE_REGULAR: Regular nomination mode - * - * An enum to specity the kind of nomination mode to use by - * the agent, as described in RFC 5245. Two modes exists, - * regular and aggressive. They differ by the way the controlling - * agent chooses to put the USE-CANDIDATE attribute in its STUN - * messages. The aggressive mode is supposed to nominate a pair - * faster, than the regular mode, potentially causing the nominated - * pair to change until the connection check completes. - * - * Since: 0.1.15 - */ -typedef enum -{ - NICE_NOMINATION_MODE_REGULAR = 0, - NICE_NOMINATION_MODE_AGGRESSIVE, -} NiceNominationMode; - -/** - * NiceAgentOption: - * @NICE_AGENT_OPTION_REGULAR_NOMINATION: Enables regular nomination, default - * is aggrssive mode (see #NiceNominationMode). - * @NICE_AGENT_OPTION_RELIABLE: Enables reliable mode, possibly using PseudoTCP, * see nice_agent_new_reliable(). - * @NICE_AGENT_OPTION_LITE_MODE: Enable lite mode - * @NICE_AGENT_OPTION_ICE_TRICKLE: Enable ICE trickle mode - * @NICE_AGENT_OPTION_SUPPORT_RENOMINATION: Enable renomination triggered by NOMINATION STUN attribute - * proposed here: https://tools.ietf.org/html/draft-thatcher-ice-renomination-00 - * - * These are options that can be passed to nice_agent_new_full(). They set - * various properties on the agent. Not including them sets the property to - * the other value. - * - * Since: 0.1.15 - */ -typedef enum { - NICE_AGENT_OPTION_REGULAR_NOMINATION = 1 << 0, - NICE_AGENT_OPTION_RELIABLE = 1 << 1, - NICE_AGENT_OPTION_LITE_MODE = 1 << 2, - NICE_AGENT_OPTION_ICE_TRICKLE = 1 << 3, - NICE_AGENT_OPTION_SUPPORT_RENOMINATION = 1 << 4, -} NiceAgentOption; - -/** - * NiceAgentRecvFunc: - * @agent: The #NiceAgent Object - * @stream_id: The id of the stream - * @component_id: The id of the component of the stream - * which received the data - * @len: The length of the data - * @buf: The buffer containing the data received - * @user_data: The user data set in nice_agent_attach_recv() - * - * Callback function when data is received on a component - * - */ -typedef void (*NiceAgentRecvFunc) ( - NiceAgent *agent, guint stream_id, guint component_id, guint len, - gchar *buf, gpointer user_data); - - -/** - * nice_agent_new: - * @ctx: The Glib Mainloop Context to use for timers - * @compat: The compatibility mode of the agent - * - * Create a new #NiceAgent. - * The returned object must be freed with g_object_unref() - * - * Returns: The new agent GObject - */ -NiceAgent * -nice_agent_new (GMainContext *ctx, NiceCompatibility compat); - - -/** - * nice_agent_new_reliable: - * @ctx: The Glib Mainloop Context to use for timers - * @compat: The compatibility mode of the agent - * - * Create a new #NiceAgent in reliable mode. If the connectivity is established - * through ICE-UDP, then a #PseudoTcpSocket will be transparently used to - * ensure reliability of the messages. - * The returned object must be freed with g_object_unref() - * See also: #NiceAgent::reliable-transport-writable - * - * Since: 0.0.11 - * - * Returns: The new agent GObject - */ -NiceAgent * -nice_agent_new_reliable (GMainContext *ctx, NiceCompatibility compat); - -/** - * nice_agent_new_full: - * @ctx: The Glib Mainloop Context to use for timers - * @compat: The compatibility mode of the agent - * @flags: Flags to set the properties - * - * Create a new #NiceAgent with parameters that must be be defined at - * construction time. - * The returned object must be freed with g_object_unref() - * See also: #NiceNominationMode and #NiceAgentOption - * - * Since: 0.1.15 - * - * Returns: The new agent GObject - */ -NiceAgent * -nice_agent_new_full (GMainContext *ctx, - NiceCompatibility compat, - NiceAgentOption flags); - -/** - * nice_agent_add_local_address: - * @agent: The #NiceAgent Object - * @addr: The address to listen to - * If the port is 0, then a random port will be chosen by the system - * - * Add a local address from which to derive local host candidates for - * candidate gathering. - * - * Since 0.0.5, if this method is not called, libnice will automatically - * discover the local addresses available - * - * - * See also: nice_agent_gather_candidates() - * Returns: %TRUE on success, %FALSE on fatal (memory allocation) errors - */ -gboolean -nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr); - -/** - * nice_agent_add_stream: - * @agent: The #NiceAgent Object - * @n_components: The number of components to add to the stream - * - * Adds a data stream to @agent containing @n_components components. The - * returned stream ID is guaranteed to be positive on success. - * - * Returns: The ID of the new stream, 0 on failure - **/ -guint -nice_agent_add_stream ( - NiceAgent *agent, - guint n_components); - -/** - * nice_agent_remove_stream: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream to remove - * - * Remove and free a previously created data stream from @agent. If any I/O - * streams have been created using nice_agent_get_io_stream(), they should be - * closed completely using g_io_stream_close() before this is called, or they - * will get broken pipe errors. - * - **/ -void -nice_agent_remove_stream ( - NiceAgent *agent, - guint stream_id); - - -/** - * nice_agent_set_port_range: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * @min_port: The minimum port to use - * @max_port: The maximum port to use - * - * Sets a preferred port range for allocating host candidates. - * - * If a local host candidate cannot be created on that port - * range, then the nice_agent_gather_candidates() call will fail. - * - * - * This MUST be called before nice_agent_gather_candidates() - * - * - */ -void -nice_agent_set_port_range ( - NiceAgent *agent, - guint stream_id, - guint component_id, - guint min_port, - guint max_port); - -/** - * nice_agent_set_relay_info: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * @server_ip: The IP address of the TURN server - * @server_port: The port of the TURN server - * @username: The TURN username to use for the allocate - * @password: The TURN password to use for the allocate - * @type: The type of relay to use - * - * Sets the settings for using a relay server during the candidate discovery. - * This may be called multiple times to add multiple relay servers to the - * discovery process; one TCP and one UDP, for example. - * - * Returns: %TRUE if the TURN settings were accepted. - * %FALSE if the address was invalid. - */ -gboolean nice_agent_set_relay_info( - NiceAgent *agent, - guint stream_id, - guint component_id, - const gchar *server_ip, - guint server_port, - const gchar *username, - const gchar *password, - NiceRelayType type); - -/** - * nice_agent_gather_candidates: - * @agent: The #NiceAgent object - * @stream_id: The ID of the stream to start - * - * Allocate and start listening on local candidate ports and start the remote - * candidate gathering process. - * Once done, #NiceAgent::candidate-gathering-done is called for the stream. - * As soon as this function is called, #NiceAgent::new-candidate signals may be - * emitted, even before this function returns. - * - * nice_agent_get_local_candidates() will only return non-empty results after - * calling this function. - * - * See also: nice_agent_add_local_address() - * See also: nice_agent_set_port_range() - * - * Returns: %FALSE if the stream ID is invalid or if a host candidate couldn't - * be allocated on the requested interfaces/ports; %TRUE otherwise - * - - - Local addresses can be previously set with nice_agent_add_local_address() - - - Since 0.0.5, If no local address was previously added, then the nice agent - will automatically detect the local address using - nice_interfaces_get_local_ips() - - - */ -gboolean -nice_agent_gather_candidates ( - NiceAgent *agent, - guint stream_id); - -/** - * nice_agent_set_remote_credentials: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @ufrag: nul-terminated string containing an ICE username fragment - * (length must be between 22 and 256 chars) - * @pwd: nul-terminated string containing an ICE password - * (length must be between 4 and 256 chars) - * - * Sets the remote credentials for stream @stream_id. - * - - - Stream credentials do not override per-candidate credentials if set - - - Due to the native of peer-reflexive candidates, any agent using a per-stream - credentials (RFC5245, WLM2009, OC2007R2 and DRAFT19) instead of - per-candidate credentials (GOOGLE, MSN, OC2007), must - use the nice_agent_set_remote_credentials() API instead of setting the - username and password on the candidates. - - - * - * Returns: %TRUE on success, %FALSE on error. - */ -gboolean -nice_agent_set_remote_credentials ( - NiceAgent *agent, - guint stream_id, - const gchar *ufrag, const gchar *pwd); - - -/** - * nice_agent_set_local_credentials: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @ufrag: nul-terminated string containing an ICE username fragment - * (length must be between 22 and 256 chars) - * @pwd: nul-terminated string containing an ICE password - * (length must be between 4 and 256 chars) - * - * Sets the local credentials for stream @stream_id. - * - - - This is only effective before ICE negotiation has started. - - - * - * Since 0.1.11 - * Returns: %TRUE on success, %FALSE on error. - */ -gboolean -nice_agent_set_local_credentials ( - NiceAgent *agent, - guint stream_id, - const gchar *ufrag, - const gchar *pwd); - - -/** - * nice_agent_get_local_credentials: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @ufrag: (out callee-allocates): return location for a nul-terminated string - * containing an ICE username fragment; must be freed with g_free() - * @pwd: (out callee-allocates): return location for a nul-terminated string - * containing an ICE password; must be freed with g_free() - * - * Gets the local credentials for stream @stream_id. This may be called any time - * after creating a stream using nice_agent_add_stream(). - * - * An error will be returned if this is called for a non-existent stream, or if - * either of @ufrag or @pwd are %NULL. - * - * Returns: %TRUE on success, %FALSE on error. - */ -gboolean -nice_agent_get_local_credentials ( - NiceAgent *agent, - guint stream_id, - gchar **ufrag, gchar **pwd); - -/** - * nice_agent_set_remote_candidates: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream the candidates are for - * @component_id: The ID of the component the candidates are for - * @candidates: (element-type NiceCandidate) (transfer none): a #GSList of - * #NiceCandidate items describing each candidate to add - * - * Sets, adds or updates the remote candidates for a component of a stream. - * - - - NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute maximum limit - for remote candidates. - - - You must first call nice_agent_gather_candidates() and wait for the - #NiceAgent::candidate-gathering-done signale before - calling nice_agent_set_remote_candidates() - - - Since 0.1.3, there is no need to wait for the candidate-gathering-done signal. - Remote candidates can be set even while gathering local candidates. - Newly discovered local candidates will automatically be paired with - existing remote candidates. - - - * - * Returns: The number of candidates added, negative on errors (memory - * allocation error or invalid component) - **/ -int -nice_agent_set_remote_candidates ( - NiceAgent *agent, - guint stream_id, - guint component_id, - const GSList *candidates); - - -/** - * nice_agent_send: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream to send to - * @component_id: The ID of the component to send to - * @len: The length of the buffer to send - * @buf: The buffer of data to send - * - * Sends a data payload over a stream's component. - * - - - Component state MUST be NICE_COMPONENT_STATE_READY, or as a special case, - in any state if component was in READY state before and was then restarted - - - In reliable mode, the -1 error value means either that you are not yet - connected or that the send buffer is full (equivalent to EWOULDBLOCK). - In both cases, you simply need to wait for the - #NiceAgent::reliable-transport-writable signal to be fired before resending - the data. - - - In non-reliable mode, it will virtually never happen with UDP sockets, but - it might happen if the active candidate is a TURN-TCP connection that got - disconnected. - - - In both reliable and non-reliable mode, a -1 error code could also mean that - the stream_id and/or component_id are invalid. - - - * - * Returns: The number of bytes sent, or negative error code - */ -gint -nice_agent_send ( - NiceAgent *agent, - guint stream_id, - guint component_id, - guint len, - const gchar *buf); - -/** - * nice_agent_send_messages_nonblocking: - * @agent: a #NiceAgent - * @stream_id: the ID of the stream to send to - * @component_id: the ID of the component to send to - * @messages: (array length=n_messages): array of messages to send, of at least - * @n_messages entries in length - * @n_messages: number of entries in @messages - * @cancellable: (allow-none): a #GCancellable to cancel the operation from - * another thread, or %NULL - * @error: (allow-none): return location for a #GError, or %NULL - * - * Sends multiple messages on the socket identified by the given - * stream/component pair. Transmission is non-blocking, so a - * %G_IO_ERROR_WOULD_BLOCK error may be returned if the send buffer is full. - * - * As with nice_agent_send(), the given component must be in - * %NICE_COMPONENT_STATE_READY or, as a special case, in any state if it was - * previously ready and was then restarted. - * - * On success, the number of messages written to the socket will be returned, - * which may be less than @n_messages if transmission would have blocked - * part-way through. Zero will be returned if @n_messages is zero, or if - * transmission would have blocked on the first message. - * - * In reliable mode, it is instead recommended to use - * nice_agent_send(). The return value can be less than @n_messages - * or 0 even if it is still possible to send a partial message. In - * this case, "nice-agent-writable" will never be triggered, so the - * application would have to use nice_agent_sent() to fill the buffer or have - * to retry sending at a later point. - * - * On failure, -1 will be returned and @error will be set. If the #NiceAgent is - * reliable and the socket is not yet connected, %G_IO_ERROR_BROKEN_PIPE will be - * returned; if the write buffer is full, %G_IO_ERROR_WOULD_BLOCK will be - * returned. In both cases, wait for the #NiceAgent::reliable-transport-writable - * signal before trying again. If the given @stream_id or @component_id are - * invalid or not yet connected, %G_IO_ERROR_BROKEN_PIPE will be returned. - * %G_IO_ERROR_FAILED will be returned for other errors. - * - * Returns: the number of messages sent (may be zero), or -1 on error - * - * Since: 0.1.5 - */ -gint -nice_agent_send_messages_nonblocking ( - NiceAgent *agent, - guint stream_id, - guint component_id, - const NiceOutputMessage *messages, - guint n_messages, - GCancellable *cancellable, - GError **error); - -/** - * nice_agent_get_local_candidates: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * - * Retrieve from the agent the list of all local candidates - * for a stream's component - * - - - The caller owns the returned GSList as well as the candidates contained - within it. - To get full results, the client should wait for the - #NiceAgent::candidate-gathering-done signal. - - - * - * Returns: (element-type NiceCandidate) (transfer full): a #GSList of - * #NiceCandidate objects representing the local candidates of @agent - **/ -GSList * -nice_agent_get_local_candidates ( - NiceAgent *agent, - guint stream_id, - guint component_id); - - -/** - * nice_agent_get_remote_candidates: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * - * Get a list of the remote candidates set on a stream's component - * - - - The caller owns the returned GSList as well as the candidates contained - within it. - - - The list of remote candidates can change during processing. - The client should register for the #NiceAgent::new-remote-candidate signal - to get notified of new remote candidates. - - - * - * Returns: (element-type NiceCandidate) (transfer full): a #GSList of - * #NiceCandidates objects representing the remote candidates set on the @agent - **/ -GSList * -nice_agent_get_remote_candidates ( - NiceAgent *agent, - guint stream_id, - guint component_id); - -/** - * nice_agent_restart: - * @agent: The #NiceAgent Object - * - * Restarts the session as defined in ICE draft 19. This function - * needs to be called both when initiating (ICE spec section 9.1.1.1. - * "ICE Restarts"), as well as when reacting (spec section 9.2.1.1. - * "Detecting ICE Restart") to a restart. - * - * Returns: %TRUE on success %FALSE on error - **/ -gboolean -nice_agent_restart ( - NiceAgent *agent); - -/** - * nice_agent_restart_stream: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * - * Restarts a single stream as defined in RFC 5245. This function - * needs to be called both when initiating (ICE spec section 9.1.1.1. - * "ICE Restarts"), as well as when reacting (spec section 9.2.1.1. - * "Detecting ICE Restart") to a restart. - * - * Unlike nice_agent_restart(), this applies to a single stream. It also - * does not generate a new tie breaker. - * - * Returns: %TRUE on success %FALSE on error - * - * Since: 0.1.6 - **/ -gboolean -nice_agent_restart_stream ( - NiceAgent *agent, - guint stream_id); - - -/** - * nice_agent_attach_recv: (skip) - * @agent: The #NiceAgent Object - * @stream_id: The ID of stream - * @component_id: The ID of the component - * @ctx: The Glib Mainloop Context to use for listening on the component - * @func: The callback function to be called when data is received on - * the stream's component (will not be called for STUN messages that - * should be handled by #NiceAgent itself) - * @data: user data associated with the callback - * - * Attaches the stream's component's sockets to the Glib Mainloop Context in - * order to be notified whenever data becomes available for a component, - * and to enable #NiceAgent to receive STUN messages (during the - * establishment of ICE connectivity). - * - * This must not be used in combination with nice_agent_recv_messages() (or - * #NiceIOStream or #NiceInputStream) on the same stream/component pair. - * - * Calling nice_agent_attach_recv() with a %NULL @func will detach any existing - * callback and cause reception to be paused for the given stream/component - * pair. You must iterate the previously specified #GMainContext sufficiently to - * ensure all pending I/O callbacks have been received before calling this - * function to unset @func, otherwise data loss of received packets may occur. - * - * Returns: %TRUE on success, %FALSE if the stream or component IDs are invalid. - */ -gboolean -nice_agent_attach_recv ( - NiceAgent *agent, - guint stream_id, - guint component_id, - GMainContext *ctx, - NiceAgentRecvFunc func, - gpointer data); - -/** - * nice_agent_recv: - * @agent: a #NiceAgent - * @stream_id: the ID of the stream to receive on - * @component_id: the ID of the component to receive on - * @buf: (array length=buf_len) (out caller-allocates): caller-allocated buffer - * to write the received data into, of length at least @buf_len - * @buf_len: length of @buf - * @cancellable: (allow-none): a #GCancellable to allow the operation to be - * cancelled from another thread, or %NULL - * @error: (allow-none): return location for a #GError, or %NULL - * - * A single-message version of nice_agent_recv_messages(). - * - * Returns: the number of bytes written to @buf on success (guaranteed to be - * greater than 0 unless @buf_len is 0), 0 if in reliable mode and the remote - * peer closed the stream, or -1 on error - * - * Since: 0.1.5 - */ -gssize -nice_agent_recv ( - NiceAgent *agent, - guint stream_id, - guint component_id, - guint8 *buf, - gsize buf_len, - GCancellable *cancellable, - GError **error); - -/** - * nice_agent_recv_messages: - * @agent: a #NiceAgent - * @stream_id: the ID of the stream to receive on - * @component_id: the ID of the component to receive on - * @messages: (array length=n_messages) (out caller-allocates): caller-allocated - * array of #NiceInputMessages to write the received messages into, of length at - * least @n_messages - * @n_messages: number of entries in @messages - * @cancellable: (allow-none): a #GCancellable to allow the operation to be - * cancelled from another thread, or %NULL - * @error: (allow-none): return location for a #GError, or %NULL - * - * Block on receiving data from the given stream/component combination on - * @agent, returning only once exactly @n_messages messages have been received - * and written into @messages, the stream is closed by the other end or by - * calling nice_agent_remove_stream(), or @cancellable is cancelled. - * - * Any STUN packets received will not be added to @messages; instead, - * they'll be passed for processing to #NiceAgent itself. Since #NiceAgent - * does not poll for messages on its own, it's therefore essential to keep - * calling this function for ICE connection establishment to work. - * - * In the non-error case, in reliable mode, this will block until all buffers in - * all @n_messages have been filled with received data (i.e. @messages is - * treated as a large, flat array of buffers). In non-reliable mode, it will - * block until @n_messages messages have been received, each of which does not - * have to fill all the buffers in its #NiceInputMessage. In the non-reliable - * case, each #NiceInputMessage must have enough buffers to contain an entire - * message (65536 bytes), or any excess data may be silently dropped. - * - * For each received message, #NiceInputMessage::length will be set to the - * number of valid bytes stored in the message’s buffers. The bytes are stored - * sequentially in the buffers; there are no gaps apart from at the end of the - * buffer array (in non-reliable mode). If non-%NULL on input, - * #NiceInputMessage::from will have the address of the sending peer stored in - * it. The base addresses, sizes, and number of buffers in each message will not - * be modified in any case. - * - * This must not be used in combination with nice_agent_attach_recv() on the - * same stream/component pair. - * - * If the stream/component pair doesn’t exist, or if a suitable candidate socket - * hasn’t yet been selected for it, a %G_IO_ERROR_BROKEN_PIPE error will be - * returned. A %G_IO_ERROR_CANCELLED error will be returned if the operation was - * cancelled. %G_IO_ERROR_FAILED will be returned for other errors. - * - * Returns: the number of valid messages written to @messages on success - * (guaranteed to be greater than 0 unless @n_messages is 0), 0 if the remote - * peer closed the stream, or -1 on error - * - * Since: 0.1.5 - */ -gint -nice_agent_recv_messages ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceInputMessage *messages, - guint n_messages, - GCancellable *cancellable, - GError **error); - -/** - * nice_agent_recv_nonblocking: - * @agent: a #NiceAgent - * @stream_id: the ID of the stream to receive on - * @component_id: the ID of the component to receive on - * @buf: (array length=buf_len) (out caller-allocates): caller-allocated buffer - * to write the received data into, of length at least @buf_len - * @buf_len: length of @buf - * @cancellable: (allow-none): a #GCancellable to allow the operation to be - * cancelled from another thread, or %NULL - * @error: (allow-none): return location for a #GError, or %NULL - * - * A single-message version of nice_agent_recv_messages_nonblocking(). - * - * Returns: the number of bytes received into @buf on success (guaranteed to be - * greater than 0 unless @buf_len is 0), 0 if in reliable mode and the remote - * peer closed the stream, or -1 on error - * - * Since: 0.1.5 - */ -gssize -nice_agent_recv_nonblocking ( - NiceAgent *agent, - guint stream_id, - guint component_id, - guint8 *buf, - gsize buf_len, - GCancellable *cancellable, - GError **error); - -/** - * nice_agent_recv_messages_nonblocking: - * @agent: a #NiceAgent - * @stream_id: the ID of the stream to receive on - * @component_id: the ID of the component to receive on - * @messages: (array length=n_messages) (out caller-allocates): caller-allocated - * array of #NiceInputMessages to write the received messages into, of length at - * least @n_messages - * @n_messages: number of entries in @messages - * @cancellable: (allow-none): a #GCancellable to allow the operation to be - * cancelled from another thread, or %NULL - * @error: (allow-none): return location for a #GError, or %NULL - * - * Try to receive data from the given stream/component combination on @agent, - * without blocking. If receiving data would block, -1 is returned and - * %G_IO_ERROR_WOULD_BLOCK is set in @error. If any other error occurs, -1 is - * returned and @error is set accordingly. Otherwise, 0 is returned if (and only - * if) @n_messages is 0. In all other cases, the number of valid messages stored - * in @messages is returned, and will be greater than 0. - * - * This function behaves similarly to nice_agent_recv_messages(), except that it - * will not block on filling (in reliable mode) or receiving (in non-reliable - * mode) exactly @n_messages messages. In reliable mode, it will receive bytes - * into @messages until it would block; in non-reliable mode, it will receive - * messages until it would block. - * - * Any STUN packets received will not be added to @messages; instead, - * they'll be passed for processing to #NiceAgent itself. Since #NiceAgent - * does not poll for messages on its own, it's therefore essential to keep - * calling this function for ICE connection establishment to work. - * - * As this function is non-blocking, @cancellable is included only for parity - * with nice_agent_recv_messages(). If @cancellable is cancelled before this - * function is called, a %G_IO_ERROR_CANCELLED error will be returned - * immediately. - * - * This must not be used in combination with nice_agent_attach_recv() on the - * same stream/component pair. - * - * Returns: the number of valid messages written to @messages on success - * (guaranteed to be greater than 0 unless @n_messages is 0), 0 if in reliable - * mode and the remote peer closed the stream, or -1 on error - * - * Since: 0.1.5 - */ -gint -nice_agent_recv_messages_nonblocking ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceInputMessage *messages, - guint n_messages, - GCancellable *cancellable, - GError **error); - -/** - * nice_agent_set_selected_pair: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * @lfoundation: The local foundation of the candidate to use - * @rfoundation: The remote foundation of the candidate to use - * - * Sets the selected candidate pair for media transmission - * for a given stream's component. Calling this function will - * disable all further ICE processing (connection check, - * state machine updates, etc). Note that keepalives will - * continue to be sent. - * - * Returns: %TRUE on success, %FALSE if the candidate pair cannot be found - */ -gboolean -nice_agent_set_selected_pair ( - NiceAgent *agent, - guint stream_id, - guint component_id, - const gchar *lfoundation, - const gchar *rfoundation); - -/** - * nice_agent_get_selected_pair: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * @local: The local selected candidate - * @remote: The remote selected candidate - * - * Retreive the selected candidate pair for media transmission - * for a given stream's component. - * - * Returns: %TRUE on success, %FALSE if there is no selected candidate pair - */ -gboolean -nice_agent_get_selected_pair ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceCandidate **local, - NiceCandidate **remote); - -/** - * nice_agent_get_selected_socket: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * - * Retreive the local socket associated with the selected candidate pair - * for media transmission for a given stream's component. - * - * This is useful for adding ICE support to legacy applications that already - * have a protocol that maintains a connection. If the socket is duplicated - * before unrefing the agent, the application can take over and continue to use - * it. New applications are encouraged to use the built in libnice stream - * handling instead and let libnice handle the connection maintenance. - * - * Users of this method are encouraged to not use a TURN relay or any kind - * of proxy, as in this case, the socket will not be available to the - * application because the packets are encapsulated. - * - * Returns: (transfer full) (nullable): pointer to the #GSocket, or %NULL if - * there is no selected candidate or if the selected candidate is a relayed - * candidate. - * - * Since: 0.1.5 - */ -GSocket * -nice_agent_get_selected_socket ( - NiceAgent *agent, - guint stream_id, - guint component_id); - -/** - * nice_agent_set_selected_remote_candidate: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * @candidate: The #NiceCandidate to select - * - * Sets the selected remote candidate for media transmission - * for a given stream's component. This is used to force the selection of - * a specific remote candidate even when connectivity checks are failing - * (e.g. non-ICE compatible candidates). - * Calling this function will disable all further ICE processing - * (connection check, state machine updates, etc). Note that keepalives will - * continue to be sent. - * - * Returns: %TRUE on success, %FALSE on failure - */ -gboolean -nice_agent_set_selected_remote_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceCandidate *candidate); - - -/** - * nice_agent_set_stream_tos: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @tos: The ToS to set - * - * Sets the IP_TOS and/or IPV6_TCLASS field on the stream's sockets' options - * - * Since: 0.0.9 - */ -void nice_agent_set_stream_tos ( - NiceAgent *agent, - guint stream_id, - gint tos); - - - -/** - * nice_agent_set_software: - * @agent: The #NiceAgent Object - * @software: The value of the SOFTWARE attribute to add. - * - * This function will set the value of the SOFTWARE attribute to be added to - * STUN requests, responses and error responses sent during connectivity checks. - * - * The SOFTWARE attribute will only be added in the #NICE_COMPATIBILITY_RFC5245 - * and #NICE_COMPATIBILITY_WLM2009 compatibility modes. - * - * - * - - The @software argument will be appended with the libnice version before - being sent. - - - The @software argument must be in UTF-8 encoding and only the first - 128 characters will be sent. - - - * - * Since: 0.0.10 - * - */ -void nice_agent_set_software ( - NiceAgent *agent, - const gchar *software); - -/** - * nice_agent_set_stream_name: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream to change - * @name: The new name of the stream or %NULL - * - * This function will assign a media type to a stream. The only values - * that can be used to produce a valid SDP are: "audio", "video", - * "text", "application", "image" and "message". - * - * This is only useful when parsing and generating an SDP of the - * candidates. - * - * See also: nice_agent_generate_local_sdp() - * See also: nice_agent_parse_remote_sdp() - * See also: nice_agent_get_stream_name() - * - * Returns: %TRUE if the name has been set. %FALSE in case of error - * (invalid stream or duplicate name). - * Since: 0.1.4 - */ -gboolean nice_agent_set_stream_name ( - NiceAgent *agent, - guint stream_id, - const gchar *name); - -/** - * nice_agent_get_stream_name: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream to change - * - * This function will return the name assigned to a stream. - - * See also: nice_agent_set_stream_name() - * - * Returns: The name of the stream. The name is only valid while the stream - * exists or until it changes through a call to nice_agent_set_stream_name(). - * - * - * Since: 0.1.4 - */ -const gchar *nice_agent_get_stream_name ( - NiceAgent *agent, - guint stream_id); - -/** - * nice_agent_get_default_local_candidate: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * - * This helper function will return the recommended default candidate to be - * used for non-ICE compatible clients. This will usually be the candidate - * with the lowest priority, since it will be the longest path but the one with - * the most chances of success. - * - - This function is only useful in order to manually generate the - local SDP - - * - * - * Returns: The candidate to be used as the default candidate, or %NULL in case - * of error. Must be freed with nice_candidate_free() once done. - * - */ -NiceCandidate * -nice_agent_get_default_local_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id); - -/** - * nice_agent_generate_local_sdp: - * @agent: The #NiceAgent Object - * - * Generate an SDP string containing the local candidates and credentials for - * all streams and components in the agent. - * - - - The SDP will not contain any codec lines and the 'm' line will not list - any payload types. - - - It is highly recommended to set names on the streams prior to calling this - function. Unnamed streams will show up as '-' in the 'm' line, but the SDP - will not be parseable with nice_agent_parse_remote_sdp() if a stream is - unnamed. - - - The default candidate in the SDP will be selected based on the lowest - priority candidate for the first component. - - - * - * See also: nice_agent_set_stream_name() - * See also: nice_agent_parse_remote_sdp() - * See also: nice_agent_generate_local_stream_sdp() - * See also: nice_agent_generate_local_candidate_sdp() - * See also: nice_agent_get_default_local_candidate() - * - * Returns: A string representing the local SDP. Must be freed with g_free() - * once done. - * - * Since: 0.1.4 - **/ -gchar * -nice_agent_generate_local_sdp ( - NiceAgent *agent); - -/** - * nice_agent_generate_local_stream_sdp: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @include_non_ice: Whether or not to include non ICE specific lines - * (m=, c= and a=rtcp: lines) - * - * Generate an SDP string containing the local candidates and credentials - * for a stream. - * - - - The SDP will not contain any codec lines and the 'm' line will not list - any payload types. - - - It is highly recommended to set the name of the stream prior to calling this - function. Unnamed streams will show up as '-' in the 'm' line. - - - The default candidate in the SDP will be selected based on the lowest - priority candidate. - - - * - * See also: nice_agent_set_stream_name() - * See also: nice_agent_parse_remote_stream_sdp() - * See also: nice_agent_generate_local_sdp() - * See also: nice_agent_generate_local_candidate_sdp() - * See also: nice_agent_get_default_local_candidate() - * - * Returns: A string representing the local SDP for the stream. Must be freed - * with g_free() once done. - * - * Since: 0.1.4 - **/ -gchar * -nice_agent_generate_local_stream_sdp ( - NiceAgent *agent, - guint stream_id, - gboolean include_non_ice); - -/** - * nice_agent_generate_local_candidate_sdp: - * @agent: The #NiceAgent Object - * @candidate: The candidate to generate - * - * Generate an SDP string representing a local candidate. - * - * See also: nice_agent_parse_remote_candidate_sdp() - * See also: nice_agent_generate_local_sdp() - * See also: nice_agent_generate_local_stream_sdp() - * - * Returns: A string representing the SDP for the candidate. Must be freed - * with g_free() once done. - * - * Since: 0.1.4 - **/ -gchar * -nice_agent_generate_local_candidate_sdp ( - NiceAgent *agent, - NiceCandidate *candidate); - -/** - * nice_agent_parse_remote_sdp: - * @agent: The #NiceAgent Object - * @sdp: The remote SDP to parse - * - * Parse an SDP string and extracts candidates and credentials from it and sets - * them on the agent. - * - * See also: nice_agent_set_stream_name() - * See also: nice_agent_generate_local_sdp() - * See also: nice_agent_parse_remote_stream_sdp() - * See also: nice_agent_parse_remote_candidate_sdp() - * - * Returns: The number of candidates added, negative on errors - * - * Since: 0.1.4 - **/ -int -nice_agent_parse_remote_sdp ( - NiceAgent *agent, - const gchar *sdp); - - -/** - * nice_agent_parse_remote_stream_sdp: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream to parse - * @sdp: The remote SDP to parse - * @ufrag: Pointer to store the ice ufrag if non %NULL. Must be freed with - * g_free() after use - * @pwd: Pointer to store the ice password if non %NULL. Must be freed with - * g_free() after use - * - * Parse an SDP string representing a single stream and extracts candidates - * and credentials from it. - * - * See also: nice_agent_generate_local_stream_sdp() - * See also: nice_agent_parse_remote_sdp() - * See also: nice_agent_parse_remote_candidate_sdp() - * - * Returns: (element-type NiceCandidate) (transfer full): A #GSList of - * candidates parsed from the SDP, or %NULL in case of errors - * - * Since: 0.1.4 - **/ -GSList * -nice_agent_parse_remote_stream_sdp ( - NiceAgent *agent, - guint stream_id, - const gchar *sdp, - gchar **ufrag, - gchar **pwd); - - -/** - * nice_agent_parse_remote_candidate_sdp: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream the candidate belongs to - * @sdp: The remote SDP to parse - * - * Parse an SDP string and extracts the candidate from it. - * - * See also: nice_agent_generate_local_candidate_sdp() - * See also: nice_agent_parse_remote_sdp() - * See also: nice_agent_parse_remote_stream_sdp() - * - * Returns: The parsed candidate or %NULL if there was an error. - * - * Since: 0.1.4 - **/ -NiceCandidate * -nice_agent_parse_remote_candidate_sdp ( - NiceAgent *agent, - guint stream_id, - const gchar *sdp); - -/** - * nice_agent_get_io_stream: - * @agent: A #NiceAgent - * @stream_id: The ID of the stream to wrap - * @component_id: The ID of the component to wrap - * - * Gets a #GIOStream wrapper around the given stream and component in - * @agent. The I/O stream will be valid for as long as @stream_id is valid. - * The #GInputStream and #GOutputStream implement #GPollableInputStream and - * #GPollableOutputStream. - * - * This function may only be called on reliable #NiceAgents. It is a - * programming error to try and create an I/O stream wrapper for an - * unreliable stream. - * - * Returns: (transfer full): A #GIOStream. - * - * Since: 0.1.5 - */ -GIOStream * -nice_agent_get_io_stream ( - NiceAgent *agent, - guint stream_id, - guint component_id); - -/** - * nice_component_state_to_string: - * @state: a #NiceComponentState - * - * Returns a string representation of the state, generally to use in debug - * messages. - * - * Returns: (transfer none): a string representation of @state - * Since: 0.1.6 - */ -const gchar * -nice_component_state_to_string (NiceComponentState state); - -/** - * nice_agent_forget_relays: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * - * Forget all the relay servers previously added using - * nice_agent_set_relay_info(). Currently connected streams will keep - * using the relay as long as they have not been restarted and haven't - * succesfully negotiated a different path. - * - * Returns: %FALSE if the component could not be found, %TRUE otherwise - * - * Since: 0.1.6 - */ -gboolean -nice_agent_forget_relays (NiceAgent *agent, - guint stream_id, - guint component_id); - -/** - * nice_agent_get_component_state: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * - * Retrieves the current state of a component. - * - * Returns: the #NiceComponentState of the component and - * %NICE_COMPONENT_STATE_FAILED if the component was invalid. - * - * Since: 0.1.8 - */ -NiceComponentState -nice_agent_get_component_state (NiceAgent *agent, - guint stream_id, - guint component_id); - -/** - * nice_agent_peer_candidate_gathering_done: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * - * Notifies the agent that the remote peer has concluded candidate gathering and - * thus no more remote candidates are expected to arrive for @stream_id. - * - * This will allow the stream components without a successful connectivity check - * to stop waiting for more candidates to come and finally transit into - * %NICE_COMPONENT_STATE_FAILED. - * - * Calling the function has an effect only when #NiceAgent:trickle-ice is %TRUE. - * - * Returns: %FALSE if the stream could not be found, %TRUE otherwise - * - * Since: 0.1.16 - */ -gboolean -nice_agent_peer_candidate_gathering_done ( - NiceAgent *agent, - guint stream_id); - -/** - * nice_agent_close_async: - * @agent: The #NiceAgent object - * @callback: (nullable): A callback that will be called when the closing is - * complete - * @callback_data: (nullable): A pointer that will be passed to the callback - * - * Asynchronously closes resources the agent has allocated on remote servers. - * - * The agent will call the callback in the current #GMainContext in - * which this function is called. The #GAsyncResult in the callback - * can be ignored as this operation never fails. - * - * Calling this function before freeing the agent makes sure the allocated relay - * ports aren't left behind on TURN server but properly removed. - * - * Since: 0.1.16 - */ -void -nice_agent_close_async (NiceAgent *agent, GAsyncReadyCallback callback, - gpointer callback_data); - -/** - * nice_agent_get_sockets: - * @agent: The #NiceAgent Object - * @stream_id: The ID of the stream - * @component_id: The ID of the component - * - * Each component can have multiple sockets, this is an API to retrieve them all - * to be able to set properties. Most of the sockets for a component are created when - * calling nice_agent_gather_candidates(), so this API should be called right after to - * able to set properties on the sockets before they are used. - * - * These sockets can be a mix of UDP & TCP sockets depending on the compatibility mode - * and options that have been set. - * - * Returns: (element-type GSocket) (transfer full): An array - * containing all of the sockets for this component. Free with - * g_ptr_array_unref() when done. - * - * Since: 0.1.17 - */ -GPtrArray * -nice_agent_get_sockets (NiceAgent *agent, guint stream_id, guint component_id); - -G_END_DECLS - -#endif /* __LIBNICE_AGENT_H__ */ diff --git a/agent/candidate.c b/agent/candidate.c deleted file mode 100644 index 940c39c..0000000 --- a/agent/candidate.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * @file candidate.c - * @brief ICE candidate functions - */ - -#ifdef HAVE_CONFIG_H -# include -#else -#define NICEAPI_EXPORT -#endif - -#include - -#include "agent.h" -#include "component.h" -#include "interfaces.h" - -G_DEFINE_BOXED_TYPE (NiceCandidate, nice_candidate, nice_candidate_copy, - nice_candidate_free); - -/* (ICE 4.1.1 "Gathering Candidates") ""Every candidate is a transport - * address. It also has a type and a base. Three types are defined and - * gathered by this specification - host candidates, server reflexive - * candidates, and relayed candidates."" (ID-19) */ - -NICEAPI_EXPORT NiceCandidate * -nice_candidate_new (NiceCandidateType type) -{ - NiceCandidate *candidate; - - candidate = g_slice_new0 (NiceCandidate); - candidate->type = type; - return candidate; -} - - -NICEAPI_EXPORT void -nice_candidate_free (NiceCandidate *candidate) -{ - /* better way of checking if socket is allocated? */ - - if (candidate->username) - g_free (candidate->username); - - if (candidate->password) - g_free (candidate->password); - - if (candidate->turn) - turn_server_unref (candidate->turn); - - g_slice_free (NiceCandidate, candidate); -} - - -guint32 -nice_candidate_jingle_priority (NiceCandidate *candidate) -{ - switch (candidate->type) - { - case NICE_CANDIDATE_TYPE_HOST: return 1000; - case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: return 900; - case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE: return 900; - case NICE_CANDIDATE_TYPE_RELAYED: return 500; - default: return 0; - } -} - -guint32 -nice_candidate_msn_priority (NiceCandidate *candidate) -{ - switch (candidate->type) - { - case NICE_CANDIDATE_TYPE_HOST: return 830; - case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: return 550; - case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE: return 550; - case NICE_CANDIDATE_TYPE_RELAYED: return 450; - default: return 0; - } -} - - -/* - * ICE 4.1.2.1. "Recommended Formula" (ID-19): - * returns number between 1 and 0x7effffff - */ -guint32 -nice_candidate_ice_priority_full ( - // must be ∈ (0, 126) (max 2^7 - 2) - guint type_preference, - // must be ∈ (0, 65535) (max 2^16 - 1) - guint local_preference, - // must be ∈ (0, 255) (max 2 ^ 8 - 1) - guint component_id) -{ - return ( - 0x1000000 * type_preference + - 0x100 * local_preference + - (0x100 - component_id)); -} - -static guint16 -nice_candidate_ice_local_preference_full (guint direction_preference, - guint turn_preference, guint other_preference) -{ - /* - * bits 0- 5: other_preference (ip local preference) - * 6- 8: turn_preference - * 9-12: - * 13-15: direction_preference - */ - g_assert_cmpuint (other_preference, <, NICE_CANDIDATE_MAX_LOCAL_ADDRESSES); - g_assert_cmpuint (turn_preference, <, NICE_CANDIDATE_MAX_TURN_SERVERS); - g_assert_cmpuint (direction_preference, <, 8); - - return (direction_preference << 13) + - (turn_preference << 6) + - other_preference; -} - -static guint -nice_candidate_ip_local_preference (const NiceCandidate *candidate) -{ - guint preference = 0; - gchar ip_string[INET6_ADDRSTRLEN]; - GList/**/ *ips = NULL; - GList/**/ *iter; - - /* Ensure otherwise identical host candidates with only different IP addresses - * (multihomed host) get assigned different priorities. Position of the IP in - * the list obtained from nice_interfaces_get_local_ips() serves here as the - * distinguishing value of other_preference. Reflexive and relayed candidates - * are likewise differentiated by their base address. - * - * This is required by RFC 5245 Section 4.1.2.1: - * https://tools.ietf.org/html/rfc5245#section-4.1.2.1 - */ - if (candidate->type == NICE_CANDIDATE_TYPE_HOST) { - nice_address_to_string (&candidate->addr, ip_string); - } else { - nice_address_to_string (&candidate->base_addr, ip_string); - } - - ips = nice_interfaces_get_local_ips (TRUE); - - for (iter = ips; iter; iter = g_list_next (iter)) { - /* Strip the IPv6 link-local scope string */ - gchar **tokens = g_strsplit (iter->data, "%", 2); - gboolean match = (g_strcmp0 (ip_string, tokens[0]) == 0); - g_strfreev (tokens); - if (match) - break; - ++preference; - } - - g_list_free_full (ips, g_free); - - return preference; -} - -static guint16 -nice_candidate_ice_local_preference (const NiceCandidate *candidate) -{ - guint direction_preference = 0; - guint turn_preference = 0; - - switch (candidate->transport) - { - case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE: - if (candidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE || - candidate->type == NICE_CANDIDATE_TYPE_HOST) - direction_preference = 4; - else - direction_preference = 6; - break; - case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE: - if (candidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE || - candidate->type == NICE_CANDIDATE_TYPE_HOST) - direction_preference = 2; - else - direction_preference = 4; - break; - case NICE_CANDIDATE_TRANSPORT_TCP_SO: - if (candidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE || - candidate->type == NICE_CANDIDATE_TYPE_HOST) - direction_preference = 6; - else - direction_preference = 2; - break; - case NICE_CANDIDATE_TRANSPORT_UDP: - default: - direction_preference = 1; - break; - } - - /* Relay candidates are assigned a unique local preference at - * creation time. - */ - if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED) { - g_assert (candidate->turn); - turn_preference = candidate->turn->preference; - } - - return nice_candidate_ice_local_preference_full (direction_preference, - turn_preference, nice_candidate_ip_local_preference (candidate)); -} - -static guint16 -nice_candidate_ms_ice_local_preference_full (guint transport_preference, - guint direction_preference, guint turn_preference, guint other_preference) -{ - /* - * bits 0- 5: other_preference (ip local preference) - * 6- 8: turn_preference - * 9-11: direction_preference - * 12-15: transport_preference - */ - g_assert_cmpuint (other_preference, <, NICE_CANDIDATE_MAX_LOCAL_ADDRESSES); - g_assert_cmpuint (turn_preference, <, NICE_CANDIDATE_MAX_TURN_SERVERS); - g_assert_cmpuint (direction_preference, <, 8); - g_assert_cmpuint (transport_preference, <, 16); - - return (transport_preference << 12) + - (direction_preference << 9) + - (turn_preference << 6) + - other_preference; -} - -static guint32 -nice_candidate_ms_ice_local_preference (const NiceCandidate *candidate) -{ - guint transport_preference = 0; - guint direction_preference = 0; - guint turn_preference = 0; - - switch (candidate->transport) - { - case NICE_CANDIDATE_TRANSPORT_TCP_SO: - case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE: - transport_preference = NICE_CANDIDATE_TRANSPORT_MS_PREF_TCP; - direction_preference = NICE_CANDIDATE_DIRECTION_MS_PREF_ACTIVE; - break; - case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE: - transport_preference = NICE_CANDIDATE_TRANSPORT_MS_PREF_TCP; - direction_preference = NICE_CANDIDATE_DIRECTION_MS_PREF_PASSIVE; - break; - case NICE_CANDIDATE_TRANSPORT_UDP: - default: - transport_preference = NICE_CANDIDATE_TRANSPORT_MS_PREF_UDP; - break; - } - - /* Relay candidates are assigned a unique local preference at - * creation time. - */ - if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED) { - g_assert (candidate->turn); - turn_preference = candidate->turn->preference; - } - - return nice_candidate_ms_ice_local_preference_full(transport_preference, - direction_preference, turn_preference, - nice_candidate_ip_local_preference (candidate)); -} - -static guint8 -nice_candidate_ice_type_preference (const NiceCandidate *candidate, - gboolean reliable, gboolean nat_assisted) -{ - guint8 type_preference; - - switch (candidate->type) - { - case NICE_CANDIDATE_TYPE_HOST: - type_preference = NICE_CANDIDATE_TYPE_PREF_HOST; - break; - case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE: - type_preference = NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE; - break; - case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: - if (nat_assisted) - type_preference = NICE_CANDIDATE_TYPE_PREF_NAT_ASSISTED; - else - type_preference = NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE; - break; - case NICE_CANDIDATE_TYPE_RELAYED: - if (candidate->turn->type == NICE_RELAY_TYPE_TURN_UDP) - type_preference = NICE_CANDIDATE_TYPE_PREF_RELAYED_UDP; - else - type_preference = NICE_CANDIDATE_TYPE_PREF_RELAYED; - break; - default: - type_preference = 0; - break; - } - - if ((reliable && candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP) || - (!reliable && candidate->transport != NICE_CANDIDATE_TRANSPORT_UDP)) { - type_preference = type_preference / 2; - } - - return type_preference; -} - -guint32 -nice_candidate_ice_priority (const NiceCandidate *candidate, - gboolean reliable, gboolean nat_assisted) -{ - guint8 type_preference; - guint16 local_preference; - - type_preference = nice_candidate_ice_type_preference (candidate, reliable, - nat_assisted); - local_preference = nice_candidate_ice_local_preference (candidate); - - return nice_candidate_ice_priority_full (type_preference, local_preference, - candidate->component_id); -} - -guint32 -nice_candidate_ms_ice_priority (const NiceCandidate *candidate, - gboolean reliable, gboolean nat_assisted) -{ - guint8 type_preference; - guint16 local_preference; - - type_preference = nice_candidate_ice_type_preference (candidate, reliable, - nat_assisted); - local_preference = nice_candidate_ms_ice_local_preference (candidate); - - return nice_candidate_ice_priority_full (type_preference, local_preference, - candidate->component_id); -} - -/* - * Calculates the pair priority as specified in ICE - * sect 5.7.2. "Computing Pair Priority and Ordering Pairs" (ID-19). - */ -guint64 -nice_candidate_pair_priority (guint32 o_prio, guint32 a_prio) -{ - guint32 max = o_prio > a_prio ? o_prio : a_prio; - guint32 min = o_prio < a_prio ? o_prio : a_prio; - /* These two constants are here explictly to make some version of GCC happy */ - const guint64 one = 1; - const guint64 thirtytwo = 32; - - return (one << thirtytwo) * min + 2 * max + (o_prio > a_prio ? 1 : 0); -} - -void -nice_candidate_pair_priority_to_string (guint64 prio, gchar *string) -{ - g_snprintf (string, NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE, - "%08" G_GINT64_MODIFIER "x:%08" G_GINT64_MODIFIER "x:%" G_GUINT64_FORMAT, - prio >> 32, (prio >> 1) & 0x7fffffff, prio & 1); -} - -/* - * Copies a candidate - */ -NICEAPI_EXPORT NiceCandidate * -nice_candidate_copy (const NiceCandidate *candidate) -{ - NiceCandidate *copy; - - g_return_val_if_fail (candidate != NULL, NULL); - - copy = nice_candidate_new (candidate->type); - memcpy (copy, candidate, sizeof(NiceCandidate)); - - copy->turn = NULL; - copy->username = g_strdup (copy->username); - copy->password = g_strdup (copy->password); - - return copy; -} - -NICEAPI_EXPORT gboolean -nice_candidate_equal_target (const NiceCandidate *candidate1, - const NiceCandidate *candidate2) -{ - g_return_val_if_fail (candidate1 != NULL, FALSE); - g_return_val_if_fail (candidate2 != NULL, FALSE); - - return (candidate1->transport == candidate2->transport && - nice_address_equal (&candidate1->addr, &candidate2->addr)); -} diff --git a/agent/candidate.h b/agent/candidate.h deleted file mode 100644 index bd99123..0000000 --- a/agent/candidate.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef __LIBNICE_CANDIDATE_H__ -#define __LIBNICE_CANDIDATE_H__ - -#include -#include - - -/** - * SECTION:candidate - * @short_description: ICE candidate representation - * @see_also: #NiceAddress - * @stability: Stable - * - * A representation of an ICE candidate. Make sure you read the ICE drafts[1] to - * understand correctly the concept of ICE candidates. - * - * [1] http://tools.ietf.org/wg/mmusic/draft-ietf-mmusic-ice/ - */ - - -G_BEGIN_DECLS - -/* Constants for determining candidate priorities */ -#define NICE_CANDIDATE_TYPE_PREF_HOST 120 -#define NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE 110 -#define NICE_CANDIDATE_TYPE_PREF_NAT_ASSISTED 105 -#define NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE 100 -#define NICE_CANDIDATE_TYPE_PREF_RELAYED_UDP 30 -#define NICE_CANDIDATE_TYPE_PREF_RELAYED 20 - -/* Priority preference constants for MS-ICE compatibility */ -#define NICE_CANDIDATE_TRANSPORT_MS_PREF_UDP 15 -#define NICE_CANDIDATE_TRANSPORT_MS_PREF_TCP 6 -#define NICE_CANDIDATE_DIRECTION_MS_PREF_PASSIVE 2 -#define NICE_CANDIDATE_DIRECTION_MS_PREF_ACTIVE 5 - -/* Max foundation size '1*32ice-char' plus terminating NULL, ICE ID-19 */ -/** - * NICE_CANDIDATE_MAX_FOUNDATION: - * - * The maximum size a candidate foundation can have. - */ -#define NICE_CANDIDATE_MAX_FOUNDATION (32+1) - -/** - * NICE_CANDIDATE_MAX_TURN_SERVERS - * - * The maximum number of turns servers. - */ -#define NICE_CANDIDATE_MAX_TURN_SERVERS 8 - -/** - * NICE_CANDIDATE_MAX_LOCAL_ADDRESSES - * - * The maximum number of local addresses. The constraint is that the - * maximum number of local addresses and number of turn servers must - * fit on 9 bits, to ensure candidate priority uniqueness. See also - * @NICE_CANDIDATE_MAX_TURN_SERVERS. We choose 6 bits for the number of - * local addresses, and 3 bits for the number of turn servers. - */ -#define NICE_CANDIDATE_MAX_LOCAL_ADDRESSES 64 - -/** - * NiceCandidateType: - * @NICE_CANDIDATE_TYPE_HOST: A host candidate - * @NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: A server reflexive candidate - * @NICE_CANDIDATE_TYPE_PEER_REFLEXIVE: A peer reflexive candidate - * @NICE_CANDIDATE_TYPE_RELAYED: A relay candidate - * - * An enum represneting the type of a candidate - */ -typedef enum -{ - NICE_CANDIDATE_TYPE_HOST, - NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE, - NICE_CANDIDATE_TYPE_PEER_REFLEXIVE, - NICE_CANDIDATE_TYPE_RELAYED, -} NiceCandidateType; - -/** - * NiceCandidateTransport: - * @NICE_CANDIDATE_TRANSPORT_UDP: UDP transport - * @NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE: TCP Active transport - * @NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE: TCP Passive transport - * @NICE_CANDIDATE_TRANSPORT_TCP_SO: TCP Simultaneous-Open transport - * - * An enum representing the type of transport to use - */ -typedef enum -{ - NICE_CANDIDATE_TRANSPORT_UDP, - NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE, - NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE, - NICE_CANDIDATE_TRANSPORT_TCP_SO, -} NiceCandidateTransport; - -/** - * NiceRelayType: - * @NICE_RELAY_TYPE_TURN_UDP: A TURN relay using UDP - * @NICE_RELAY_TYPE_TURN_TCP: A TURN relay using TCP - * @NICE_RELAY_TYPE_TURN_TLS: A TURN relay using TLS over TCP - * - * An enum representing the type of relay to use - */ -typedef enum { - NICE_RELAY_TYPE_TURN_UDP, - NICE_RELAY_TYPE_TURN_TCP, - NICE_RELAY_TYPE_TURN_TLS -} NiceRelayType; - - -typedef struct _NiceCandidate NiceCandidate; - -typedef struct _TurnServer TurnServer; - -/** - * TurnServer: - * @ref_count: Reference count for the structure. - * @server: The #NiceAddress of the TURN server - * @username: The TURN username - * @password: The TURN password - * @decoded_username: The base64 decoded TURN username - * @decoded_password: The base64 decoded TURN password - * @decoded_username_len: The length of @decoded_username - * @decoded_password_len: The length of @decoded_password - * @type: The #NiceRelayType of the server - * @preference: A unique identifier used to compute priority - * - * A structure to store the TURN relay settings - */ -struct _TurnServer -{ - gint ref_count; - - NiceAddress server; - gchar *username; - gchar *password; - guint8 *decoded_username; - guint8 *decoded_password; - gsize decoded_username_len; - gsize decoded_password_len; - NiceRelayType type; - guint preference; -}; - -/** - * NiceCandidate: - * @type: The type of candidate - * @transport: The transport being used for the candidate - * @addr: The #NiceAddress of the candidate - * @base_addr: The #NiceAddress of the base address used by the candidate - * @priority: The priority of the candidate see note - * @stream_id: The ID of the stream to which belongs the candidate - * @component_id: The ID of the component to which belongs the candidate - * @foundation: The foundation of the candidate - * @username: The candidate-specific username to use (overrides the one set - * by nice_agent_set_local_credentials() or nice_agent_set_remote_credentials()) - * @password: The candidate-specific password to use (overrides the one set - * by nice_agent_set_local_credentials() or nice_agent_set_remote_credentials()) - * @turn: The #TurnServer settings if the candidate is - * of type %NICE_CANDIDATE_TYPE_RELAYED - * @sockptr: The underlying socket - * @keepalive_next_tick: The timestamp for the next keepalive - * - * A structure to represent an ICE candidate - - - The @priority is an integer as specified in the ICE draft 19. If you are - using the MSN or the GOOGLE compatibility mode (which are based on ICE - draft 6, which uses a floating point qvalue as priority), then the @priority - value will represent the qvalue multiplied by 1000. - - - */ -struct _NiceCandidate -{ - NiceCandidateType type; - NiceCandidateTransport transport; - NiceAddress addr; - NiceAddress base_addr; - guint32 priority; - guint stream_id; - guint component_id; - gchar foundation[NICE_CANDIDATE_MAX_FOUNDATION]; - gchar *username; /* pointer to a nul-terminated username string */ - gchar *password; /* pointer to a nul-terminated password string */ - TurnServer *turn; - gpointer sockptr; - guint64 keepalive_next_tick; /* next tick timestamp */ -}; - -/** - * nice_candidate_new: - * @type: The #NiceCandidateType of the candidate to create - * - * Creates a new candidate. Must be freed with nice_candidate_free() - * - * Returns: A new #NiceCandidate - */ -NiceCandidate * -nice_candidate_new (NiceCandidateType type); - -/** - * nice_candidate_free: - * @candidate: The candidate to free - * - * Frees a #NiceCandidate - */ -void -nice_candidate_free (NiceCandidate *candidate); - -/** - * nice_candidate_copy: - * @candidate: The candidate to copy - * - * Makes a copy of a #NiceCandidate - * - * Returns: A new #NiceCandidate, a copy of @candidate - */ -NiceCandidate * -nice_candidate_copy (const NiceCandidate *candidate); - -/** - * nice_candidate_equal_target: - * @candidate1: A candidate - * @candidate2: A candidate - * - * Verifies that the candidates point to the same place, meaning they have - * the same transport and the same address. It ignores all other aspects. - * - * Returns: %TRUE if the candidates point to the same place - * - * Since: 0.1.15 - */ -gboolean -nice_candidate_equal_target (const NiceCandidate *candidate1, - const NiceCandidate *candidate2); - - GType nice_candidate_get_type (void); - -/** - * NICE_TYPE_CANDIDATE: - * - * A boxed type for a #NiceCandidate. - */ -#define NICE_TYPE_CANDIDATE nice_candidate_get_type () - -G_END_DECLS - -#endif /* __LIBNICE_CANDIDATE_H__ */ - diff --git a/agent/component.c b/agent/component.c deleted file mode 100644 index 27d6218..0000000 --- a/agent/component.c +++ /dev/null @@ -1,1642 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * @file component.c - * @brief ICE component functions - */ - -/* Simple tracking for the number of alive components. These must be accessed - * atomically. */ -static volatile unsigned int n_components_created = 0; -static volatile unsigned int n_components_destroyed = 0; - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "debug.h" - -#include "component.h" -#include "discovery.h" -#include "agent-priv.h" - -G_DEFINE_TYPE (NiceComponent, nice_component, G_TYPE_OBJECT); - -typedef enum { - PROP_ID = 1, - PROP_AGENT, - PROP_STREAM, -} NiceComponentProperty; - -static void -nice_component_constructed (GObject *obj); -static void -nice_component_get_property (GObject *obj, - guint property_id, GValue *value, GParamSpec *pspec); -static void -nice_component_set_property (GObject *obj, - guint property_id, const GValue *value, GParamSpec *pspec); -static void -nice_component_finalize (GObject *obj); - -static void -nice_component_schedule_io_callback (NiceComponent *component); -static void -nice_component_deschedule_io_callback (NiceComponent *component); -static void -nice_component_detach_socket (NiceComponent *component, NiceSocket *nicesock); -static void -nice_component_clear_selected_pair (NiceComponent *component); - - -void -incoming_check_free (IncomingCheck *icheck) -{ - g_free (icheck->username); - g_slice_free (IncomingCheck, icheck); -} - -/* Must *not* take the agent lock, since it’s called from within - * nice_component_set_io_context(), which holds the Component’s I/O lock. */ -static void -socket_source_attach (SocketSource *socket_source, GMainContext *context) -{ - GSource *source; - - if (socket_source->socket->fileno == NULL) - return; - - /* Do not create a GSource for UDP turn socket, because it - * would duplicate the packets already received on the base - * UDP socket. - */ - if (socket_source->socket->type == NICE_SOCKET_TYPE_UDP_TURN) - return; - - /* Create a source. */ - source = g_socket_create_source (socket_source->socket->fileno, - G_IO_IN, NULL); - g_source_set_callback (source, (GSourceFunc) G_CALLBACK (component_io_cb), - socket_source, NULL); - - /* Add the source. */ - nice_debug ("Attaching source %p (socket %p, FD %d) to context %p", source, - socket_source->socket, g_socket_get_fd (socket_source->socket->fileno), - context); - - g_assert (socket_source->source == NULL); - socket_source->source = source; - g_source_attach (source, context); -} - -static void -socket_source_detach (SocketSource *source) -{ - nice_debug ("Detaching source %p (socket %p, FD %d) from context %p", - source->source, source->socket, - (source->socket->fileno != NULL) ? - g_socket_get_fd (source->socket->fileno) : 0, - (source->source != NULL) ? g_source_get_context (source->source) : 0); - - if (source->source != NULL) { - g_source_destroy (source->source); - g_source_unref (source->source); - } - source->source = NULL; -} - -static void -socket_source_free (SocketSource *source) -{ - socket_source_detach (source); - nice_socket_free (source->socket); - - g_slice_free (SocketSource, source); -} - -NiceComponent * -nice_component_new (guint id, NiceAgent *agent, NiceStream *stream) -{ - return g_object_new (NICE_TYPE_COMPONENT, - "id", id, - "agent", agent, - "stream", stream, - NULL); -} - -void -nice_component_remove_socket (NiceAgent *agent, NiceComponent *cmp, - NiceSocket *nsocket) -{ - GSList *i; - NiceStream *stream; - - stream = agent_find_stream (agent, cmp->stream_id); - - discovery_prune_socket (agent, nsocket); - if (stream) - conn_check_prune_socket (agent, stream, cmp, nsocket); - - for (i = cmp->local_candidates; i;) { - NiceCandidate *candidate = i->data; - GSList *next = i->next; - - if (!nice_socket_is_based_on (candidate->sockptr, nsocket)) { - i = next; - continue; - } - - if (candidate == cmp->selected_pair.local) { - nice_component_clear_selected_pair (cmp); - agent_signal_component_state_change (agent, cmp->stream_id, - cmp->id, NICE_COMPONENT_STATE_FAILED); - } - - refresh_prune_candidate (agent, candidate); - if (candidate->sockptr != nsocket && stream) { - discovery_prune_socket (agent, candidate->sockptr); - conn_check_prune_socket (agent, stream, cmp, - candidate->sockptr); - nice_component_detach_socket (cmp, candidate->sockptr); - } - agent_remove_local_candidate (agent, candidate); - nice_candidate_free (candidate); - - cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i); - i = next; - } - - /* The nsocket to be removed may also come from a - * peer-reflexive remote candidate - */ - for (i = cmp->remote_candidates; i;) { - NiceCandidate *candidate = i->data; - GSList *next = i->next; - - if (candidate->sockptr != nsocket) { - i = next; - continue; - } - - if (candidate == cmp->selected_pair.remote) { - nice_component_clear_selected_pair (cmp); - agent_signal_component_state_change (agent, cmp->stream_id, - cmp->id, NICE_COMPONENT_STATE_FAILED); - } - - if (stream) - conn_check_prune_socket (agent, stream, cmp, candidate->sockptr); - - nice_candidate_free (candidate); - - cmp->remote_candidates = g_slist_delete_link (cmp->remote_candidates, i); - i = next; - } - - nice_component_detach_socket (cmp, nsocket); -} - -static gboolean -on_candidate_refreshes_pruned (NiceAgent *agent, NiceCandidate *candidate) -{ - NiceComponent *component; - - if (agent_find_component (agent, candidate->stream_id, - candidate->component_id, NULL, &component)) { - nice_component_detach_socket (component, candidate->sockptr); - } - - nice_candidate_free (candidate); - - return G_SOURCE_REMOVE; -} - -void -nice_component_clean_turn_servers (NiceAgent *agent, NiceComponent *cmp) -{ - GSList *i; - GSList *relay_candidates = NULL; - NiceStream *stream; - - stream = agent_find_stream (agent, cmp->stream_id); - - g_list_free_full (cmp->turn_servers, (GDestroyNotify) turn_server_unref); - cmp->turn_servers = NULL; - - for (i = cmp->local_candidates; i;) { - NiceCandidate *candidate = i->data; - GSList *next = i->next; - - if (candidate->type != NICE_CANDIDATE_TYPE_RELAYED) { - i = next; - continue; - } - - /* note: do not remove the remote candidate that is - * currently part of the 'selected pair', see ICE - * 9.1.1.1. "ICE Restarts" (ID-19) - * - * So what we do instead is that we put the selected candidate - * in a special location and keep it "alive" that way. This is - * especially important for TURN, because refresh requests to the - * server need to keep happening. - */ - if (candidate == cmp->selected_pair.local) { - if (cmp->turn_candidate) { - relay_candidates = g_slist_append(relay_candidates, cmp->turn_candidate); - } - /* Bring the priority down to 0, so that it will be replaced - * on the new run. - */ - cmp->selected_pair.priority = 0; - cmp->turn_candidate = candidate; - } else { - agent_remove_local_candidate (agent, candidate); - relay_candidates = g_slist_append(relay_candidates, candidate); - } - cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, i); - i = next; - } - - for (i = relay_candidates; i; i = i->next) { - NiceCandidate * candidate = i->data; - - discovery_prune_socket (agent, candidate->sockptr); - if (stream) { - conn_check_prune_socket (agent, stream, cmp, candidate->sockptr); - } - - refresh_prune_candidate_async (agent, candidate, - (NiceTimeoutLockedCallback) on_candidate_refreshes_pruned); - } -} - -static void -nice_component_clear_selected_pair (NiceComponent *component) -{ - if (component->selected_pair.keepalive.tick_source != NULL) { - g_source_destroy (component->selected_pair.keepalive.tick_source); - g_source_unref (component->selected_pair.keepalive.tick_source); - component->selected_pair.keepalive.tick_source = NULL; - } - - memset (&component->selected_pair, 0, sizeof(CandidatePair)); -} - -/* Must be called with the agent lock held as it touches internal Component - * state. */ -void -nice_component_close (NiceAgent *agent, NiceComponent *cmp) -{ - IOCallbackData *data; - GOutputVector *vec; - IncomingCheck *c; - - /* Start closing the pseudo-TCP socket first. FIXME: There is a very big and - * reliably triggerable race here. pseudo_tcp_socket_close() does not block - * on the socket closing — it only sends the first packet of the FIN - * handshake. nice_component_close() will immediately afterwards close the - * underlying component sockets, aborting the handshake. - * - * On the principle that starting the FIN handshake is better than not - * starting it, even if it’s later truncated, call pseudo_tcp_socket_close(). - * A long-term fix is needed in the form of making nice_component_close() (and - * all its callers) async, so we can properly block on closure. */ - if (cmp->tcp) { - pseudo_tcp_socket_close (cmp->tcp, TRUE); - } - - if (cmp->restart_candidate) - nice_candidate_free (cmp->restart_candidate), - cmp->restart_candidate = NULL; - - if (cmp->turn_candidate) - nice_candidate_free (cmp->turn_candidate), - cmp->turn_candidate = NULL; - - while (cmp->local_candidates) { - agent_remove_local_candidate (agent, cmp->local_candidates->data); - nice_candidate_free (cmp->local_candidates->data); - cmp->local_candidates = g_slist_delete_link (cmp->local_candidates, - cmp->local_candidates); - } - - g_slist_free_full (cmp->remote_candidates, - (GDestroyNotify) nice_candidate_free); - cmp->remote_candidates = NULL; - nice_component_free_socket_sources (cmp); - - while ((c = g_queue_pop_head (&cmp->incoming_checks))) - incoming_check_free (c); - - nice_component_clean_turn_servers (agent, cmp); - - if (cmp->tcp_clock) { - g_source_destroy (cmp->tcp_clock); - g_source_unref (cmp->tcp_clock); - cmp->tcp_clock = NULL; - } - if (cmp->tcp_writable_cancellable) { - g_cancellable_cancel (cmp->tcp_writable_cancellable); - g_clear_object (&cmp->tcp_writable_cancellable); - } - - while ((data = g_queue_pop_head (&cmp->pending_io_messages)) != NULL) - io_callback_data_free (data); - - nice_component_deschedule_io_callback (cmp); - - g_cancellable_cancel (cmp->stop_cancellable); - - while ((vec = g_queue_pop_head (&cmp->queued_tcp_packets)) != NULL) { - g_free ((gpointer) vec->buffer); - g_slice_free (GOutputVector, vec); - } -} - -/* - * Finds a candidate pair that has matching foundation ids. - * - * @return TRUE if pair found, pointer to pair stored at 'pair' - */ -gboolean -nice_component_find_pair (NiceComponent *cmp, NiceAgent *agent, const gchar *lfoundation, const gchar *rfoundation, CandidatePair *pair) -{ - GSList *i; - CandidatePair result = { 0, }; - - for (i = cmp->local_candidates; i; i = i->next) { - NiceCandidate *candidate = i->data; - if (strncmp (candidate->foundation, lfoundation, NICE_CANDIDATE_MAX_FOUNDATION) == 0) { - result.local = candidate; - break; - } - } - - for (i = cmp->remote_candidates; i; i = i->next) { - NiceCandidate *candidate = i->data; - if (strncmp (candidate->foundation, rfoundation, NICE_CANDIDATE_MAX_FOUNDATION) == 0) { - result.remote = candidate; - break; - } - } - - if (result.local && result.remote) { - result.priority = agent_candidate_pair_priority (agent, result.local, result.remote); - if (pair) - *pair = result; - return TRUE; - } - - return FALSE; -} - -/* - * Resets the component state to that of a ICE restarted - * session. - */ -void -nice_component_restart (NiceComponent *cmp) -{ - GSList *i; - IncomingCheck *c; - - for (i = cmp->remote_candidates; i; i = i->next) { - NiceCandidate *candidate = i->data; - - /* note: do not remove the remote candidate that is - * currently part of the 'selected pair', see ICE - * 9.1.1.1. "ICE Restarts" (ID-19) */ - if (candidate == cmp->selected_pair.remote) { - if (cmp->restart_candidate) - nice_candidate_free (cmp->restart_candidate); - cmp->restart_candidate = candidate; - } - else - nice_candidate_free (candidate); - } - g_slist_free (cmp->remote_candidates), - cmp->remote_candidates = NULL; - - while ((c = g_queue_pop_head (&cmp->incoming_checks))) - incoming_check_free (c); - - /* Reset the priority to 0 to make sure we get a new pair */ - cmp->selected_pair.priority = 0; - - /* note: component state managed by agent */ -} - -/* - * Changes the selected pair for the component to 'pair'. Does not - * emit the "selected-pair-changed" signal. - */ -void -nice_component_update_selected_pair (NiceAgent *agent, NiceComponent *component, const CandidatePair *pair) -{ - NiceStream *stream; - gchar priority[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE]; - - g_assert (component); - g_assert (pair); - - stream = agent_find_stream (agent, component->stream_id); - - nice_candidate_pair_priority_to_string (pair->priority, priority); - nice_debug ("setting SELECTED PAIR for component %u: %s:%s (prio:%s).", - component->id, pair->local->foundation, - pair->remote->foundation, priority); - - if (component->selected_pair.local && - component->selected_pair.local == component->turn_candidate) { - discovery_prune_socket (agent, - component->turn_candidate->sockptr); - if (stream) - conn_check_prune_socket (agent, stream, component, - component->turn_candidate->sockptr); - refresh_prune_candidate_async (agent, component->turn_candidate, - (NiceTimeoutLockedCallback) on_candidate_refreshes_pruned); - component->turn_candidate = NULL; - } - - nice_component_clear_selected_pair (component); - - component->selected_pair.local = pair->local; - component->selected_pair.remote = pair->remote; - component->selected_pair.priority = pair->priority; - component->selected_pair.stun_priority = pair->stun_priority; - - nice_component_add_valid_candidate (agent, component, pair->remote); -} - -/* - * Finds a remote candidate with matching address and - * transport. - * - * @return pointer to candidate or NULL if not found - */ -NiceCandidate * -nice_component_find_remote_candidate (NiceComponent *component, const NiceAddress *addr, NiceCandidateTransport transport) -{ - GSList *i; - - for (i = component->remote_candidates; i; i = i->next) { - NiceCandidate *candidate = i->data; - - if (nice_address_equal(&candidate->addr, addr) && - candidate->transport == transport) - return candidate; - - } - - return NULL; -} - -/* - * Sets the desired remote candidate as the selected pair - * - * It will start sending on the highest priority pair available with - * this candidate. - */ - -NiceCandidate * -nice_component_set_selected_remote_candidate (NiceComponent *component, - NiceAgent *agent, NiceCandidate *candidate) -{ - NiceCandidate *local = NULL; - NiceCandidate *remote = NULL; - guint64 priority = 0; - GSList *item = NULL; - - g_assert (candidate != NULL); - - for (item = component->local_candidates; item; item = g_slist_next (item)) { - NiceCandidate *tmp = item->data; - guint64 tmp_prio = 0; - - if (tmp->transport != conn_check_match_transport(candidate->transport) || - tmp->addr.s.addr.sa_family != candidate->addr.s.addr.sa_family || - tmp->type != NICE_CANDIDATE_TYPE_HOST) - continue; - - tmp_prio = agent_candidate_pair_priority (agent, tmp, candidate); - - if (tmp_prio > priority) { - priority = tmp_prio; - local = tmp; - } - } - - if (local == NULL) - return NULL; - - remote = nice_component_find_remote_candidate (component, &candidate->addr, - candidate->transport); - - if (!remote) { - remote = nice_candidate_copy (candidate); - component->remote_candidates = g_slist_append (component->remote_candidates, - remote); - agent_signal_new_remote_candidate (agent, remote); - } - - nice_component_clear_selected_pair (component); - - component->selected_pair.local = local; - component->selected_pair.remote = remote; - component->selected_pair.priority = priority; - - /* Get into fallback mode where packets from any source is accepted once - * this has been called. This is the expected behavior of pre-ICE SIP. - */ - component->fallback_mode = TRUE; - - return local; -} - -static gint -_find_socket_source (gconstpointer a, gconstpointer b) -{ - const SocketSource *source_a = a; - const NiceSocket *socket_b = b; - - return (source_a->socket == socket_b) ? 0 : 1; -} - -/* This takes ownership of the socket. - * It creates and attaches a source to the component’s context. */ -void -nice_component_attach_socket (NiceComponent *component, NiceSocket *nicesock) -{ - GSList *l; - SocketSource *socket_source; - - g_assert (component != NULL); - g_assert (nicesock != NULL); - - g_assert (component->ctx != NULL); - - /* Find an existing SocketSource in the component which contains @socket, or - * create a new one. - * - * Whenever a source is added or remove to socket_sources, socket_sources_age - * must be incremented. - */ - l = g_slist_find_custom (component->socket_sources, nicesock, - _find_socket_source); - if (l != NULL) { - socket_source = l->data; - } else { - socket_source = g_slice_new0 (SocketSource); - socket_source->socket = nicesock; - socket_source->component = component; - component->socket_sources = - g_slist_prepend (component->socket_sources, socket_source); - if (nicesock->fileno != NULL) - component->socket_sources_age++; - } - - /* Create and attach a source */ - nice_debug ("Component %p: Attach source (stream %u).", - component, component->stream_id); - socket_source_attach (socket_source, component->ctx); -} - -/* Reattaches socket handles of @component to the main context. - * - * Must *not* take the agent lock, since it’s called from within - * nice_component_set_io_context(), which holds the Component’s I/O lock. */ -static void -nice_component_reattach_all_sockets (NiceComponent *component) -{ - GSList *i; - - for (i = component->socket_sources; i != NULL; i = i->next) { - SocketSource *socket_source = i->data; - nice_debug ("Reattach source %p.", socket_source->source); - socket_source_detach (socket_source); - socket_source_attach (socket_source, component->ctx); - } -} - -/** - * nice_component_detach_socket: - * @component: a #NiceComponent - * @socket: the socket to detach the source for - * - * Detach the #GSource for the single specified @socket. It also closes it - * and frees it! - * - * If the @socket doesn’t exist in this @component, do nothing. - */ -static void -nice_component_detach_socket (NiceComponent *component, NiceSocket *nicesock) -{ - GList *l; - GSList *s; - SocketSource *socket_source; - - nice_debug ("Detach socket %p.", nicesock); - - /* Remove the socket from various lists. */ - for (l = component->incoming_checks.head; l != NULL;) { - IncomingCheck *icheck = l->data; - GList *next = l->next; - - if (icheck->local_socket == nicesock) { - g_queue_delete_link (&component->incoming_checks, l); - incoming_check_free (icheck); - } - - l = next; - } - - /* Find the SocketSource for the socket. */ - s = g_slist_find_custom (component->socket_sources, nicesock, - _find_socket_source); - if (s == NULL) - return; - - /* Detach the source. */ - socket_source = s->data; - component->socket_sources = g_slist_delete_link (component->socket_sources, s); - component->socket_sources_age++; - - socket_source_free (socket_source); -} - -/* - * Detaches socket handles of @component from the main context. Leaves the - * sockets themselves untouched. - * - * Must *not* take the agent lock, since it’s called from within - * nice_component_set_io_context(), which holds the Component’s I/O lock. - */ -void -nice_component_detach_all_sockets (NiceComponent *component) -{ - GSList *i; - - for (i = component->socket_sources; i != NULL; i = i->next) { - SocketSource *socket_source = i->data; - nice_debug ("Detach source %p, socket %p.", socket_source->source, - socket_source->socket); - socket_source_detach (socket_source); - } -} - -void -nice_component_free_socket_sources (NiceComponent *component) -{ - nice_debug ("Free socket sources for component %p.", component); - - g_slist_free_full (component->socket_sources, - (GDestroyNotify) socket_source_free); - component->socket_sources = NULL; - component->socket_sources_age++; - - nice_component_clear_selected_pair (component); -} - -GMainContext * -nice_component_dup_io_context (NiceComponent *component) -{ - return g_main_context_ref (component->own_ctx); -} - -/* If @context is %NULL, it's own context is used, so component->ctx is always - * guaranteed to be non-%NULL. */ -void -nice_component_set_io_context (NiceComponent *component, GMainContext *context) -{ - g_mutex_lock (&component->io_mutex); - - if (component->ctx != context) { - if (context == NULL) - context = g_main_context_ref (component->own_ctx); - else - g_main_context_ref (context); - - nice_component_detach_all_sockets (component); - g_main_context_unref (component->ctx); - - component->ctx = context; - nice_component_reattach_all_sockets (component); - } - - g_mutex_unlock (&component->io_mutex); -} - -/* (func, user_data) and (recv_messages, n_recv_messages) are mutually - * exclusive. At most one of the two must be specified; if both are NULL, the - * Component will not receive any data (i.e. reception is paused). - * - * Apart from during setup, this must always be called with the agent lock held, - * and the I/O lock released (because it takes the I/O lock itself). Requiring - * the agent lock to be held means it can’t be called between a packet being - * dequeued from the kernel buffers in agent.c, and an I/O callback being - * emitted for it (which could cause data loss if the I/O callback function was - * unset in that time). */ -void -nice_component_set_io_callback (NiceComponent *component, - NiceAgentRecvFunc func, gpointer user_data, - NiceInputMessage *recv_messages, guint n_recv_messages, - GError **error) -{ - g_assert (func == NULL || recv_messages == NULL); - g_assert (n_recv_messages == 0 || recv_messages != NULL); - g_assert (error == NULL || *error == NULL); - - g_mutex_lock (&component->io_mutex); - - if (func != NULL) { - component->io_callback = func; - component->io_user_data = user_data; - component->recv_messages = NULL; - component->n_recv_messages = 0; - - nice_component_schedule_io_callback (component); - } else { - component->io_callback = NULL; - component->io_user_data = NULL; - component->recv_messages = recv_messages; - component->n_recv_messages = n_recv_messages; - - nice_component_deschedule_io_callback (component); - } - - nice_input_message_iter_reset (&component->recv_messages_iter); - component->recv_buf_error = error; - - g_mutex_unlock (&component->io_mutex); -} - -gboolean -nice_component_has_io_callback (NiceComponent *component) -{ - gboolean has_io_callback; - - g_mutex_lock (&component->io_mutex); - has_io_callback = (component->io_callback != NULL); - g_mutex_unlock (&component->io_mutex); - - return has_io_callback; -} - -IOCallbackData * -io_callback_data_new (const guint8 *buf, gsize buf_len) -{ - IOCallbackData *data; - - data = g_slice_new0 (IOCallbackData); - data->buf = g_memdup (buf, buf_len); - data->buf_len = buf_len; - data->offset = 0; - - return data; -} - -void -io_callback_data_free (IOCallbackData *data) -{ - g_free (data->buf); - g_slice_free (IOCallbackData, data); -} - -/* This is called with the global agent lock released. It does not take that - * lock, but does take the io_mutex. */ -static gboolean -emit_io_callback_cb (gpointer user_data) -{ - NiceComponent *component = user_data; - IOCallbackData *data; - NiceAgentRecvFunc io_callback; - gpointer io_user_data; - guint stream_id, component_id; - NiceAgent *agent; - - agent = g_weak_ref_get (&component->agent_ref); - if (agent == NULL) { - nice_debug ("Agent for component %p is gone", component); - return FALSE; - } - - stream_id = component->stream_id; - component_id = component->id; - - g_mutex_lock (&component->io_mutex); - - /* The members of Component are guaranteed not to have changed since this - * GSource was attached in nice_component_emit_io_callback(). The Component’s agent - * and stream are immutable after construction, as are the stream and - * component IDs. The callback and its user data may have changed, but are - * guaranteed to be non-%NULL at the start as the idle source is removed when - * the callback is set to %NULL. They may become %NULL during the io_callback, - * so must be re-checked every loop iteration. The data buffer is copied into - * the #IOCallbackData closure. - * - * If the component is destroyed (which happens if the agent or stream are - * destroyed) between attaching the GSource and firing it, the GSource is - * detached during dispose and this callback is never invoked. If the - * agent is destroyed during an io_callback, its weak pointer will be - * nullified. Similarly, the Component needs to be re-queried for after every - * iteration, just in case the client has removed the stream in the - * callback. */ - while (TRUE) { - io_callback = component->io_callback; - io_user_data = component->io_user_data; - data = g_queue_peek_head (&component->pending_io_messages); - - if (data == NULL || io_callback == NULL) - break; - - g_mutex_unlock (&component->io_mutex); - - io_callback (agent, stream_id, component_id, - data->buf_len - data->offset, (gchar *) data->buf + data->offset, - io_user_data); - - /* Check for the user destroying things underneath our feet. */ - if (!agent_find_component (agent, stream_id, component_id, - NULL, &component)) { - nice_debug ("%s: Agent or component destroyed.", G_STRFUNC); - goto done; - } - - g_queue_pop_head (&component->pending_io_messages); - io_callback_data_free (data); - - g_mutex_lock (&component->io_mutex); - } - - component->io_callback_id = 0; - g_mutex_unlock (&component->io_mutex); - - done: - g_object_unref (agent); - - return G_SOURCE_REMOVE; -} - -/* This must be called with the agent lock *held*. */ -void -nice_component_emit_io_callback (NiceAgent *agent, NiceComponent *component, - const guint8 *buf, gsize buf_len) -{ - guint stream_id, component_id; - NiceAgentRecvFunc io_callback; - gpointer io_user_data; - - g_assert (component != NULL); - g_assert (buf != NULL); - g_assert (buf_len > 0); - - stream_id = component->stream_id; - component_id = component->id; - - g_mutex_lock (&component->io_mutex); - io_callback = component->io_callback; - io_user_data = component->io_user_data; - g_mutex_unlock (&component->io_mutex); - - /* Allow this to be called with a NULL io_callback, since the caller can’t - * lock io_mutex to check beforehand. */ - if (io_callback == NULL) - return; - - g_assert (NICE_IS_AGENT (agent)); - g_assert_cmpuint (stream_id, >, 0); - g_assert_cmpuint (component_id, >, 0); - g_assert (io_callback != NULL); - - /* Only allocate a closure if the callback is being deferred to an idle - * handler. */ - if (g_main_context_is_owner (component->ctx)) { - /* Thread owns the main context, so invoke the callback directly. */ - agent_unlock_and_emit (agent); - io_callback (agent, stream_id, - component_id, buf_len, (gchar *) buf, io_user_data); - agent_lock (agent); - } else { - IOCallbackData *data; - - g_mutex_lock (&component->io_mutex); - - /* Slow path: Current thread doesn’t own the Component’s context at the - * moment, so schedule the callback in an idle handler. */ - data = io_callback_data_new (buf, buf_len); - g_queue_push_tail (&component->pending_io_messages, - data); /* transfer ownership */ - - nice_debug ("%s: **WARNING: SLOW PATH**", G_STRFUNC); - - nice_component_schedule_io_callback (component); - - g_mutex_unlock (&component->io_mutex); - } -} - -/* Note: Must be called with the io_mutex held. */ -static void -nice_component_schedule_io_callback (NiceComponent *component) -{ - GSource *source; - - /* Already scheduled or nothing to schedule? */ - if (component->io_callback_id != 0 || - g_queue_is_empty (&component->pending_io_messages)) - return; - - /* Add the idle callback. If nice_agent_attach_recv() is called with a - * NULL callback before this source is dispatched, the source will be - * destroyed, but any pending data will remain in - * component->pending_io_messages, ready to be picked up when a callback - * is re-attached, or if nice_agent_recv() is called. */ - source = g_idle_source_new (); - g_source_set_priority (source, G_PRIORITY_DEFAULT); - g_source_set_callback (source, emit_io_callback_cb, component, NULL); - component->io_callback_id = g_source_attach (source, component->ctx); - g_source_unref (source); -} - -/* Note: Must be called with the io_mutex held. */ -static void -nice_component_deschedule_io_callback (NiceComponent *component) -{ - /* Already descheduled? */ - if (component->io_callback_id == 0) - return; - - g_source_remove (component->io_callback_id); - component->io_callback_id = 0; -} - -static void -nice_component_class_init (NiceComponentClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->constructed = nice_component_constructed; - object_class->get_property = nice_component_get_property; - object_class->set_property = nice_component_set_property; - object_class->finalize = nice_component_finalize; - - /** - * NiceComponent:id: - * - * The unique numeric ID of the component. - * - * Since: 0.1.14 - */ - g_object_class_install_property (object_class, PROP_ID, - g_param_spec_uint ( - "id", - "ID", - "The unique numeric ID of the component.", - 1, G_MAXUINT, 1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /** - * NiceComponent:agent: - * - * The #NiceAgent this component belongs to. - * - * Since: 0.1.14 - */ - g_object_class_install_property (object_class, PROP_AGENT, - g_param_spec_object ( - "agent", - "Agent", - "The NiceAgent this component belongs to.", - NICE_TYPE_AGENT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /** - * NiceComponent:stream: - * - * The #NiceStream this component belongs to. - * - * Since: 0.1.14 - */ - g_object_class_install_property (object_class, PROP_STREAM, - g_param_spec_object ( - "stream", - "Stream", - "The NiceStream this component belongs to.", - NICE_TYPE_STREAM, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} - -static gboolean -dummy_callback (gpointer data) -{ - return G_SOURCE_CONTINUE; -} - -static void -source_set_dummy_callback (GSource *source) -{ - g_source_set_callback (source, dummy_callback, NULL, NULL); -} - -static void -nice_component_init (NiceComponent *component) -{ - g_atomic_int_inc (&n_components_created); - nice_debug ("Created NiceComponent (%u created, %u destroyed)", - n_components_created, n_components_destroyed); - - component->id = 0; - component->state = NICE_COMPONENT_STATE_DISCONNECTED; - component->restart_candidate = NULL; - component->tcp = NULL; - g_weak_ref_init (&component->agent_ref, NULL); - - g_mutex_init (&component->io_mutex); - g_queue_init (&component->pending_io_messages); - component->io_callback_id = 0; - - component->own_ctx = g_main_context_new (); - component->stop_cancellable = g_cancellable_new (); - component->stop_cancellable_source = - g_cancellable_source_new (component->stop_cancellable); - source_set_dummy_callback (component->stop_cancellable_source); - g_source_attach (component->stop_cancellable_source, component->own_ctx); - component->ctx = g_main_context_ref (component->own_ctx); - - /* Start off with a fresh main context and all I/O paused. This - * will be updated when nice_agent_attach_recv() or nice_agent_recv_messages() - * are called. */ - nice_component_set_io_context (component, NULL); - nice_component_set_io_callback (component, NULL, NULL, NULL, 0, NULL); - - g_queue_init (&component->queued_tcp_packets); - g_queue_init (&component->incoming_checks); -} - -static void -nice_component_constructed (GObject *obj) -{ - NiceComponent *component; - NiceAgent *agent; - - component = NICE_COMPONENT (obj); - - agent = g_weak_ref_get (&component->agent_ref); - g_assert (agent != NULL); - nice_agent_init_stun_agent (agent, &component->stun_agent); - - g_object_unref (agent); - - G_OBJECT_CLASS (nice_component_parent_class)->constructed (obj); -} - -static void -nice_component_get_property (GObject *obj, - guint property_id, GValue *value, GParamSpec *pspec) -{ - NiceComponent *component; - - component = NICE_COMPONENT (obj); - - switch ((NiceComponentProperty) property_id) - { - case PROP_ID: - g_value_set_uint (value, component->id); - break; - - case PROP_AGENT: - { - NiceAgent *agent; - - agent = g_weak_ref_get (&component->agent_ref); - if (agent) - g_value_take_object (value, agent); - break; - } - case PROP_STREAM: - { - NiceAgent *agent; - NiceStream *stream = NULL; - - agent = g_weak_ref_get (&component->agent_ref); - if (agent) { - stream = agent_find_stream (agent, component->stream_id); - g_value_set_object (value, stream); - g_object_unref (agent); - } - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); - } -} - -static void -nice_component_set_property (GObject *obj, - guint property_id, const GValue *value, GParamSpec *pspec) -{ - NiceComponent *component; - - component = NICE_COMPONENT (obj); - - switch ((NiceComponentProperty) property_id) - { - case PROP_ID: - component->id = g_value_get_uint (value); - break; - - case PROP_AGENT: - g_weak_ref_set (&component->agent_ref, g_value_get_object (value)); - break; - - case PROP_STREAM: - { - NiceStream *stream = g_value_get_object (value); - component->stream_id = stream->id; - } - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); - } -} - -/* Must be called with the agent lock released as it could dispose of - * NiceIOStreams. */ -static void -nice_component_finalize (GObject *obj) -{ - NiceComponent *cmp; - - cmp = NICE_COMPONENT (obj); - - /* Component should have been closed already. */ - g_warn_if_fail (cmp->local_candidates == NULL); - g_warn_if_fail (cmp->remote_candidates == NULL); - g_warn_if_fail (g_queue_get_length (&cmp->incoming_checks) == 0); - - g_list_free_full (cmp->valid_candidates, - (GDestroyNotify) nice_candidate_free); - - g_clear_object (&cmp->tcp); - g_clear_object (&cmp->stop_cancellable); - g_clear_object (&cmp->iostream); - g_mutex_clear (&cmp->io_mutex); - - if (cmp->stop_cancellable_source != NULL) { - g_source_destroy (cmp->stop_cancellable_source); - g_source_unref (cmp->stop_cancellable_source); - } - - if (cmp->ctx != NULL) { - g_main_context_unref (cmp->ctx); - cmp->ctx = NULL; - } - - g_main_context_unref (cmp->own_ctx); - - g_weak_ref_clear (&cmp->agent_ref); - - g_atomic_int_inc (&n_components_destroyed); - nice_debug ("Destroyed NiceComponent (%u created, %u destroyed)", - n_components_created, n_components_destroyed); - - G_OBJECT_CLASS (nice_component_parent_class)->finalize (obj); -} - -/** - * ComponentSource: - * - * This is a GSource which wraps a single Component and is dispatched whenever - * any of its NiceSockets are dispatched, i.e. it proxies all poll() events for - * every socket in the Component. It is designed for use by GPollableInputStream - * and GPollableOutputStream, so that a Component can be incorporated into a - * custom main context iteration. - * - * The callbacks dispatched by a ComponentSource have type GPollableSourceFunc. - * - * ComponentSource supports adding a GCancellable child source which will - * additionally dispatch if a provided GCancellable is cancelled. - * - * Internally, ComponentSource adds a new GSocketSource for each socket in the - * Component. Changes to the Component’s list of sockets are detected on each - * call to component_source_prepare(), which compares a stored age with the - * current age of the Component’s socket list — if the socket list has changed, - * the age will have increased (indicating added sockets) or will have been - * reset to 0 (indicating all sockets have been closed). - */ -typedef struct { - GSource parent; - - GObject *pollable_stream; /* owned */ - - GWeakRef agent_ref; - guint stream_id; - guint component_id; - guint component_socket_sources_age; - - /* SocketSource, free with free_child_socket_source() */ - GSList *socket_sources; - - GIOCondition condition; -} ComponentSource; - -static gboolean -component_source_prepare (GSource *source, gint *timeout_) -{ - ComponentSource *component_source = (ComponentSource *) source; - NiceAgent *agent; - NiceComponent *component; - GSList *parentl, *childl; - - agent = g_weak_ref_get (&component_source->agent_ref); - if (!agent) - return FALSE; - - /* Needed due to accessing the Component. */ - agent_lock (agent); - - if (!agent_find_component (agent, - component_source->stream_id, component_source->component_id, NULL, - &component)) - goto done; - - - if (component->socket_sources_age == - component_source->component_socket_sources_age) - goto done; - - /* If the age has changed, either - * - one or more new socket has been prepended - * - old sockets have been removed - */ - - /* Add the new child sources. */ - - for (parentl = component->socket_sources; parentl; parentl = parentl->next) { - SocketSource *parent_socket_source = parentl->data; - SocketSource *child_socket_source; - - if (parent_socket_source->socket->fileno == NULL) - continue; - - /* Iterating the list of socket sources every time isn't a big problem - * because the number of pairs is limited ~100 normally, so there will - * rarely be more than 10. - */ - childl = g_slist_find_custom (component_source->socket_sources, - parent_socket_source->socket, _find_socket_source); - - /* If we have reached this state, then all sources new sources have been - * added, because they are always prepended. - */ - if (childl) - break; - - child_socket_source = g_slice_new0 (SocketSource); - child_socket_source->socket = parent_socket_source->socket; - child_socket_source->source = - g_socket_create_source (child_socket_source->socket->fileno, G_IO_IN, - NULL); - source_set_dummy_callback (child_socket_source->source); - g_source_add_child_source (source, child_socket_source->source); - g_source_unref (child_socket_source->source); - component_source->socket_sources = - g_slist_prepend (component_source->socket_sources, child_socket_source); - } - - - for (childl = component_source->socket_sources; - childl;) { - SocketSource *child_socket_source = childl->data; - GSList *next = childl->next; - - parentl = g_slist_find_custom (component->socket_sources, - child_socket_source->socket, _find_socket_source); - - /* If this is not a currently used socket, remove the relevant source */ - if (!parentl) { - g_source_remove_child_source (source, child_socket_source->source); - g_slice_free (SocketSource, child_socket_source); - component_source->socket_sources = - g_slist_delete_link (component_source->socket_sources, childl); - } - - childl = next; - } - - - /* Update the age. */ - component_source->component_socket_sources_age = component->socket_sources_age; - - done: - - agent_unlock_and_emit (agent); - g_object_unref (agent); - - /* We can’t be sure if the ComponentSource itself needs to be dispatched until - * poll() is called on all the child sources. */ - return FALSE; -} - -static gboolean -component_source_dispatch (GSource *source, GSourceFunc callback, - gpointer user_data) -{ - ComponentSource *component_source = (ComponentSource *) source; - GPollableSourceFunc func = (GPollableSourceFunc) G_CALLBACK (callback); - - return func (component_source->pollable_stream, user_data); -} - -static void -free_child_socket_source (gpointer data) -{ - g_slice_free (SocketSource, data); -} - -static void -component_source_finalize (GSource *source) -{ - ComponentSource *component_source = (ComponentSource *) source; - - g_slist_free_full (component_source->socket_sources, free_child_socket_source); - - g_weak_ref_clear (&component_source->agent_ref); - g_object_unref (component_source->pollable_stream); - component_source->pollable_stream = NULL; -} - -static gboolean -component_source_closure_callback (GObject *pollable_stream, gpointer user_data) -{ - GClosure *closure = user_data; - GValue param_value = G_VALUE_INIT; - GValue result_value = G_VALUE_INIT; - gboolean retval; - - g_value_init (&result_value, G_TYPE_BOOLEAN); - g_value_init (¶m_value, G_TYPE_OBJECT); - g_value_set_object (¶m_value, pollable_stream); - - g_closure_invoke (closure, &result_value, 1, ¶m_value, NULL); - retval = g_value_get_boolean (&result_value); - - g_value_unset (¶m_value); - g_value_unset (&result_value); - - return retval; -} - -static GSourceFuncs component_source_funcs = { - component_source_prepare, - NULL, /* check */ - component_source_dispatch, - component_source_finalize, - (GSourceFunc) G_CALLBACK (component_source_closure_callback), -}; - -/** - * nice_component_source_new: - * @agent: a #NiceAgent - * @stream_id: The stream's id - * @component_id: The component's number - * @pollable_stream: a #GPollableInputStream or #GPollableOutputStream to pass - * to dispatched callbacks - * @cancellable: (allow-none): a #GCancellable, or %NULL - * - * Create a new #ComponentSource, a type of #GSource which proxies poll events - * from all sockets in the given @component. - * - * A callback function of type #GPollableSourceFunc must be connected to the - * returned #GSource using g_source_set_callback(). @pollable_stream is passed - * to all callbacks dispatched from the #GSource, and a reference is held on it - * by the #GSource. - * - * The #GSource will automatically update to poll sockets as they’re added to - * the @component (e.g. during peer discovery). - * - * Returns: (transfer full): a new #ComponentSource; unref with g_source_unref() - */ -GSource * -nice_component_input_source_new (NiceAgent *agent, guint stream_id, - guint component_id, GPollableInputStream *pollable_istream, - GCancellable *cancellable) -{ - ComponentSource *component_source; - - g_assert (G_IS_POLLABLE_INPUT_STREAM (pollable_istream)); - - component_source = - (ComponentSource *) - g_source_new (&component_source_funcs, sizeof (ComponentSource)); - g_source_set_name ((GSource *) component_source, "ComponentSource"); - - component_source->component_socket_sources_age = 0; - component_source->pollable_stream = g_object_ref (pollable_istream); - g_weak_ref_init (&component_source->agent_ref, agent); - component_source->stream_id = stream_id; - component_source->component_id = component_id; - - /* Add a cancellable source. */ - if (cancellable != NULL) { - GSource *cancellable_source; - - cancellable_source = g_cancellable_source_new (cancellable); - source_set_dummy_callback (cancellable_source); - g_source_add_child_source ((GSource *) component_source, - cancellable_source); - g_source_unref (cancellable_source); - } - - return (GSource *) component_source; -} - - -TurnServer * -turn_server_new (const gchar *server_ip, guint server_port, - const gchar *username, const gchar *password, NiceRelayType type) -{ - TurnServer *turn = g_slice_new (TurnServer); - - nice_address_init (&turn->server); - - turn->ref_count = 1; - if (nice_address_set_from_string (&turn->server, server_ip)) { - nice_address_set_port (&turn->server, server_port); - } else { - g_slice_free (TurnServer, turn); - return NULL; - } - turn->username = g_strdup (username); - turn->password = g_strdup (password); - turn->decoded_username = - g_base64_decode ((gchar *)username, &turn->decoded_username_len); - turn->decoded_password = - g_base64_decode ((gchar *)password, &turn->decoded_password_len); - turn->type = type; - - return turn; -} - -TurnServer * -turn_server_ref (TurnServer *turn) -{ - turn->ref_count++; - - return turn; -} - -void -turn_server_unref (TurnServer *turn) -{ - turn->ref_count--; - - if (turn->ref_count == 0) { - g_free (turn->username); - g_free (turn->password); - g_free (turn->decoded_username); - g_free (turn->decoded_password); - g_slice_free (TurnServer, turn); - } -} - -void -nice_component_add_valid_candidate (NiceAgent *agent, NiceComponent *component, - const NiceCandidate *candidate) -{ - guint count = 0; - GList *item, *last = NULL; - - for (item = component->valid_candidates; item; item = item->next) { - NiceCandidate *cand = item->data; - - last = item; - count++; - if (nice_candidate_equal_target (cand, candidate)) - return; - } - - /* New candidate */ - - if (nice_debug_is_enabled ()) { - char str[INET6_ADDRSTRLEN]; - nice_address_to_string (&candidate->addr, str); - nice_debug ("Agent %p : %d:%d Adding valid source" - " candidate: %s:%d trans: %d", agent, - candidate->stream_id, candidate->component_id, str, - nice_address_get_port (&candidate->addr), candidate->transport); - } - - component->valid_candidates = g_list_prepend ( - component->valid_candidates, nice_candidate_copy (candidate)); - - /* Delete the last one to make sure we don't have a list that is too long, - * the candidates are not freed on ICE restart as this would be more complex, - * we just keep the list not too long. - */ - if (count > NICE_COMPONENT_MAX_VALID_CANDIDATES) { - NiceCandidate *cand = last->data; - - component->valid_candidates = g_list_delete_link ( - component->valid_candidates, last); - nice_candidate_free (cand); - } -} - -gboolean -nice_component_verify_remote_candidate (NiceComponent *component, - const NiceAddress *address, NiceSocket *nicesock) -{ - GList *item; - - if (component->fallback_mode) - return TRUE; - - for (item = component->valid_candidates; item; item = item->next) { - NiceCandidate *cand = item->data; - - if ((((nicesock->type == NICE_SOCKET_TYPE_TCP_BSD || - nicesock->type == NICE_SOCKET_TYPE_UDP_TURN) && - (cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE || - cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE || - cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_SO)) || - cand->transport == NICE_CANDIDATE_TRANSPORT_UDP) && - nice_address_equal (address, &cand->addr)) { - /* fast return if it's already the first */ - if (item == component->valid_candidates) - return TRUE; - - /* Put the current candidate at the top so that in the normal use-case, - * this function becomes O(1). - */ - component->valid_candidates = g_list_remove_link ( - component->valid_candidates, item); - component->valid_candidates = g_list_concat (item, - component->valid_candidates); - - return TRUE; - } - } - - return FALSE; -} - -/* Must be called with agent lock held */ -/* Returns a transfer full GPtrArray of GSocket */ -GPtrArray * -nice_component_get_sockets (NiceComponent *component) -{ - GPtrArray *array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - GSList *item; - - for (item = component->local_candidates; item; item = item->next) { - NiceCandidate *cand = item->data; - NiceSocket *nicesock = cand->sockptr; - - if (nicesock->fileno && !g_ptr_array_find (array, nicesock->fileno, NULL)) - g_ptr_array_add (array, g_object_ref (nicesock->fileno)); - } - - return array; -} diff --git a/agent/component.h b/agent/component.h deleted file mode 100644 index b35eb11..0000000 --- a/agent/component.h +++ /dev/null @@ -1,319 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2010 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2010 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _NICE_COMPONENT_H -#define _NICE_COMPONENT_H - -#include - -typedef struct _NiceComponent NiceComponent; - -#include "agent.h" -#include "agent-priv.h" -#include "candidate.h" -#include "stun/stunagent.h" -#include "stun/usages/timer.h" -#include "pseudotcp.h" -#include "stream.h" -#include "socket.h" - -G_BEGIN_DECLS - - -/* (ICE §4.1.1.1, ID-19) - * ""For RTP-based media streams, the RTP itself has a component - * ID of 1, and RTCP a component ID of 2. If an agent is using RTCP it MUST - * obtain a candidate for it. If an agent is using both RTP and RTCP, it - * would end up with 2*K host candidates if an agent has K interfaces."" - */ - -typedef struct _CandidatePair CandidatePair; -typedef struct _CandidatePairKeepalive CandidatePairKeepalive; -typedef struct _IncomingCheck IncomingCheck; - -struct _CandidatePairKeepalive -{ - guint64 next_tick; /* next tick timestamp */ - GSource *tick_source; - guint stream_id; - guint component_id; - StunTimer timer; - uint8_t stun_buffer[STUN_MAX_MESSAGE_SIZE_IPV6]; - StunMessage stun_message; -}; - -struct _CandidatePair -{ - NiceCandidate *local; - NiceCandidate *remote; - guint64 priority; /* candidate pair priority */ - guint32 stun_priority; - CandidatePairKeepalive keepalive; -}; - -struct _IncomingCheck -{ - NiceAddress from; - NiceSocket *local_socket; - guint32 priority; - gboolean use_candidate; - uint8_t *username; - uint16_t username_len; -}; - -void -incoming_check_free (IncomingCheck *icheck); - -/* A pair of a socket and the GSource which polls it from the main loop. All - * GSources in a Component must be attached to the same main context: - * component->ctx. - * - * Socket must be non-NULL, but source may be NULL if it has been detached. - * - * The Component is stored so this may be used as the user data for a GSource - * callback. */ -typedef struct { - NiceSocket *socket; - GSource *source; - NiceComponent *component; -} SocketSource; - - -/* A message which has been received and processed (so is guaranteed not - * to be a STUN packet, or to contain pseudo-TCP header bytes, for example), but - * which hasn’t yet been sent to the client in an I/O callback. This could be - * due to the main context not being run, or due to the I/O callback being - * detached. - * - * The @offset member gives the byte offset into @buf which has already been - * sent to the client. #IOCallbackData buffers remain in the - * #Component::pending_io_messages queue until all of their bytes have been sent - * to the client. - * - * @offset is guaranteed to be smaller than @buf_len. */ -typedef struct { - guint8 *buf; /* owned */ - gsize buf_len; - gsize offset; -} IOCallbackData; - -IOCallbackData * -io_callback_data_new (const guint8 *buf, gsize buf_len); -void -io_callback_data_free (IOCallbackData *data); - -#define NICE_TYPE_COMPONENT nice_component_get_type() -#define NICE_COMPONENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), NICE_TYPE_COMPONENT, NiceComponent)) -#define NICE_COMPONENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), NICE_TYPE_COMPONENT, NiceComponentClass)) -#define NICE_IS_COMPONENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NICE_TYPE_COMPONENT)) -#define NICE_IS_COMPONENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), NICE_TYPE_COMPONENT)) -#define NICE_COMPONENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), NICE_TYPE_COMPONENT, NiceComponentClass)) - -struct _NiceComponent { - /*< private >*/ - GObject parent; - - NiceComponentType type; - guint id; /* component id */ - NiceComponentState state; - GSList *local_candidates; /* list of NiceCandidate objs */ - GSList *remote_candidates; /* list of NiceCandidate objs */ - GList *valid_candidates; /* list of owned remote NiceCandidates that are part of valid pairs */ - GSList *socket_sources; /* list of SocketSource objs; must only grow monotonically */ - guint socket_sources_age; /* incremented when socket_sources changes */ - GQueue incoming_checks; /* list of IncomingCheck objs */ - GList *turn_servers; /* List of TurnServer objs */ - CandidatePair selected_pair; /* independent from checklists, - see ICE 11.1. "Sending Media" (ID-19) */ - gboolean fallback_mode; /* in this case, accepts packets from all, ignore candidate validation */ - NiceCandidate *restart_candidate; /* for storing active remote candidate during a restart */ - NiceCandidate *turn_candidate; /* for storing active turn candidate if turn servers have been cleared */ - /* I/O handling. The main context must always be non-NULL, and is used for all - * socket recv() operations. All io_callback emissions are invoked in this - * context too. - * - * recv_messages and io_callback are mutually exclusive, but it is allowed for - * both to be NULL if the Component is not currently ready to receive data. */ - GMutex io_mutex; /* protects io_callback, io_user_data, - pending_io_messages and io_callback_id. - immutable: can be accessed without - holding the agent lock; if the agent - lock is to be taken, it must always be - taken before this one */ - NiceAgentRecvFunc io_callback; /* function called on io cb */ - gpointer io_user_data; /* data passed to the io function */ - GQueue pending_io_messages; /* queue of messages which have been - received but not passed to the client - in an I/O callback or recv() call yet. - each element is an owned - IOCallbackData */ - guint io_callback_id; /* GSource ID of the I/O callback */ - - GMainContext *own_ctx; /* own context for GSources for this - component */ - GMainContext *ctx; /* context for GSources for this - component (possibly set from the app) */ - NiceInputMessage *recv_messages; /* unowned messages for receiving into */ - guint n_recv_messages; /* length of recv_messages */ - NiceInputMessageIter recv_messages_iter; /* current write position in - recv_messages */ - GError **recv_buf_error; /* error information about failed reads */ - - GWeakRef agent_ref; - guint stream_id; - - StunAgent stun_agent; /* This stun agent is used to validate all stun requests */ - - - GCancellable *stop_cancellable; - GSource *stop_cancellable_source; /* owned */ - - PseudoTcpSocket *tcp; - GSource* tcp_clock; - guint64 last_clock_timeout; - gboolean tcp_readable; - GCancellable *tcp_writable_cancellable; - - GIOStream *iostream; - - guint min_port; - guint max_port; - - /* Queue of messages received before a selected socket was available to send - * ACKs on. The messages are dequeued to the pseudo-TCP socket once a selected - * UDP socket is available. This is only used for reliable Components. */ - GQueue queued_tcp_packets; -}; - -typedef struct { - GObjectClass parent_class; -} NiceComponentClass; - -GType nice_component_get_type (void); - -NiceComponent * -nice_component_new (guint component_id, NiceAgent *agent, NiceStream *stream); - -void -nice_component_close (NiceAgent *agent, NiceComponent *component); - -gboolean -nice_component_find_pair (NiceComponent *component, NiceAgent *agent, - const gchar *lfoundation, const gchar *rfoundation, CandidatePair *pair); - -void -nice_component_restart (NiceComponent *component); - -void -nice_component_update_selected_pair (NiceAgent *agent, NiceComponent *component, - const CandidatePair *pair); - -NiceCandidate * -nice_component_find_remote_candidate (NiceComponent *component, - const NiceAddress *addr, NiceCandidateTransport transport); - -NiceCandidate * -nice_component_set_selected_remote_candidate (NiceComponent *component, - NiceAgent *agent, NiceCandidate *candidate); - -void -nice_component_attach_socket (NiceComponent *component, NiceSocket *nsocket); - -void -nice_component_remove_socket (NiceAgent *agent, NiceComponent *component, - NiceSocket *nsocket); -void -nice_component_detach_all_sockets (NiceComponent *component); - -void -nice_component_free_socket_sources (NiceComponent *component); - -GSource * -nice_component_input_source_new (NiceAgent *agent, guint stream_id, - guint component_id, GPollableInputStream *pollable_istream, - GCancellable *cancellable); - -GMainContext * -nice_component_dup_io_context (NiceComponent *component); -void -nice_component_set_io_context (NiceComponent *component, GMainContext *context); -void -nice_component_set_io_callback (NiceComponent *component, - NiceAgentRecvFunc func, gpointer user_data, - NiceInputMessage *recv_messages, guint n_recv_messages, - GError **error); -void -nice_component_emit_io_callback (NiceAgent *agent, NiceComponent *component, - const guint8 *buf, gsize buf_len); -gboolean -nice_component_has_io_callback (NiceComponent *component); -void -nice_component_clean_turn_servers (NiceAgent *agent, NiceComponent *component); - - -TurnServer * -turn_server_new (const gchar *server_ip, guint server_port, - const gchar *username, const gchar *password, NiceRelayType type); - -TurnServer * -turn_server_ref (TurnServer *turn); - -void -turn_server_unref (TurnServer *turn); - -void -nice_component_add_valid_candidate (NiceAgent *agent, NiceComponent *component, - const NiceCandidate *candidate); - -gboolean -nice_component_verify_remote_candidate (NiceComponent *component, - const NiceAddress *address, NiceSocket *nicesock); - -GPtrArray * -nice_component_get_sockets (NiceComponent *component); - -G_END_DECLS - -#endif /* _NICE_COMPONENT_H */ - diff --git a/agent/conncheck.c b/agent/conncheck.c deleted file mode 100644 index 4ad49d4..0000000 --- a/agent/conncheck.c +++ /dev/null @@ -1,4886 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Kai Vehmanen, Nokia - * Youness Alaoui, Collabora Ltd. - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * @file conncheck.c - * @brief ICE connectivity checks - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include - -#include - -#include "debug.h" - -#include "agent.h" -#include "agent-priv.h" -#include "conncheck.h" -#include "discovery.h" -#include "stun/stun5389.h" -#include "stun/usages/ice.h" -#include "stun/usages/bind.h" -#include "stun/usages/turn.h" - -static void priv_update_check_list_failed_components (NiceAgent *agent, NiceStream *stream); -static guint priv_prune_pending_checks (NiceAgent *agent, NiceStream *stream, NiceComponent *component); -static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *local_socket, NiceCandidate *remote_cand); -static void priv_mark_pair_nominated (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceCandidate *localcand, NiceCandidate *remotecand); -static size_t priv_create_username (NiceAgent *agent, NiceStream *stream, - guint component_id, NiceCandidate *remote, NiceCandidate *local, - uint8_t *dest, guint dest_len, gboolean inbound); -static size_t priv_get_password (NiceAgent *agent, NiceStream *stream, - NiceCandidate *remote, uint8_t **password); -static void candidate_check_pair_free (NiceAgent *agent, - CandidateCheckPair *pair); -static CandidateCheckPair *priv_conn_check_add_for_candidate_pair_matched ( - NiceAgent *agent, guint stream_id, NiceComponent *component, - NiceCandidate *local, NiceCandidate *remote, NiceCheckState initial_state); -static gboolean priv_conn_keepalive_tick_agent_locked (NiceAgent *agent, - gpointer pointer); - -static gint64 priv_timer_remainder (gint64 timer, gint64 now) -{ - if (now >= timer) - return 0; - - return (timer - now) / 1000; -} - -static gchar -priv_state_to_gchar (NiceCheckState state) -{ - switch (state) { - case NICE_CHECK_WAITING: - return 'W'; - case NICE_CHECK_IN_PROGRESS: - return 'I'; - case NICE_CHECK_SUCCEEDED: - return 'S'; - case NICE_CHECK_FAILED: - return 'F'; - case NICE_CHECK_FROZEN: - return 'Z'; - case NICE_CHECK_DISCOVERED: - return 'D'; - default: - g_assert_not_reached (); - } -} - -static const gchar * -priv_state_to_string (NiceCheckState state) -{ - switch (state) { - case NICE_CHECK_WAITING: - return "WAITING"; - case NICE_CHECK_IN_PROGRESS: - return "IN_PROGRESS"; - case NICE_CHECK_SUCCEEDED: - return "SUCCEEDED"; - case NICE_CHECK_FAILED: - return "FAILED"; - case NICE_CHECK_FROZEN: - return "FROZEN"; - case NICE_CHECK_DISCOVERED: - return "DISCOVERED"; - default: - g_assert_not_reached (); - } -} - -#define SET_PAIR_STATE( a, p, s ) G_STMT_START{\ - g_assert (p); \ - p->state = s; \ - nice_debug ("Agent %p : pair %p state %s (%s)", \ - a, p, priv_state_to_string (s), G_STRFUNC); \ -}G_STMT_END - -static const gchar * -priv_ice_return_to_string (StunUsageIceReturn ice_return) -{ - switch (ice_return) { - case STUN_USAGE_ICE_RETURN_SUCCESS: - return "success"; - case STUN_USAGE_ICE_RETURN_ERROR: - return "error"; - case STUN_USAGE_ICE_RETURN_INVALID: - return "invalid"; - case STUN_USAGE_ICE_RETURN_ROLE_CONFLICT: - return "role conflict"; - case STUN_USAGE_ICE_RETURN_INVALID_REQUEST: - return "invalid request"; - case STUN_USAGE_ICE_RETURN_INVALID_METHOD: - return "invalid method"; - case STUN_USAGE_ICE_RETURN_MEMORY_ERROR: - return "memory error"; - case STUN_USAGE_ICE_RETURN_INVALID_ADDRESS: - return "invalid address"; - case STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS: - return "no mapped address"; - default: - g_assert_not_reached (); - } -} - -static const gchar * -priv_candidate_type_to_string (NiceCandidateType type) -{ - switch (type) { - case NICE_CANDIDATE_TYPE_HOST: - return "host"; - case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: - return "srflx"; - case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE: - return "prflx"; - case NICE_CANDIDATE_TYPE_RELAYED: - return "relay"; - default: - g_assert_not_reached (); - } -} - -static const gchar * -priv_candidate_transport_to_string (NiceCandidateTransport transport) -{ - switch (transport) { - case NICE_CANDIDATE_TRANSPORT_UDP: - return "udp"; - case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE: - return "tcp-act"; - case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE: - return "tcp-pass"; - case NICE_CANDIDATE_TRANSPORT_TCP_SO: - return "tcp-so"; - default: - g_assert_not_reached (); - } -} - -static const gchar * -priv_socket_type_to_string (NiceSocketType type) -{ - switch (type) { - case NICE_SOCKET_TYPE_UDP_BSD: - return "udp"; - case NICE_SOCKET_TYPE_TCP_BSD: - return "tcp"; - case NICE_SOCKET_TYPE_PSEUDOSSL: - return "ssl"; - case NICE_SOCKET_TYPE_HTTP: - return "http"; - case NICE_SOCKET_TYPE_SOCKS5: - return "socks"; - case NICE_SOCKET_TYPE_UDP_TURN: - return "udp-turn"; - case NICE_SOCKET_TYPE_UDP_TURN_OVER_TCP: - return "tcp-turn"; - case NICE_SOCKET_TYPE_TCP_ACTIVE: - return "tcp-act"; - case NICE_SOCKET_TYPE_TCP_PASSIVE: - return "tcp-pass"; - case NICE_SOCKET_TYPE_TCP_SO: - return "tcp-so"; - default: - g_assert_not_reached (); - } -} - -/* - * Dump the component list of incoming checks - */ -static void -print_component_incoming_checks (NiceAgent *agent, NiceStream *stream, - NiceComponent *component) -{ - GList *i; - - for (i = component->incoming_checks.head; i; i = i->next) { - IncomingCheck *icheck = i->data; - gchar tmpbuf1[INET6_ADDRSTRLEN] = {0}; - gchar tmpbuf2[INET6_ADDRSTRLEN] = {0}; - - nice_address_to_string (&icheck->local_socket->addr, tmpbuf1); - nice_address_to_string (&icheck->from, tmpbuf2); - nice_debug ("Agent %p : *** sc=%d/%d : icheck %p : " - "sock %s [%s]:%u > [%s]:%u", - agent, stream->id, component->id, icheck, - priv_socket_type_to_string (icheck->local_socket->type), - tmpbuf1, nice_address_get_port (&icheck->local_socket->addr), - tmpbuf2, nice_address_get_port (&icheck->from)); - } -} - -/* - * Dump the conncheck lists of the agent - */ -static void -priv_print_conn_check_lists (NiceAgent *agent, const gchar *where, const gchar *detail) -{ - GSList *i, *k, *l; - guint j, m; - gint64 now; - - if (!nice_debug_is_verbose ()) - return; - - now = g_get_monotonic_time (); - -#define PRIORITY_LEN 32 - - nice_debug ("Agent %p : *** conncheck list DUMP (called from %s%s)", - agent, where, detail ? detail : ""); - nice_debug ("Agent %p : *** agent nomination mode %s, %s", - agent, agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE ? - "aggressive" : "regular", - agent->controlling_mode ? "controlling" : "controlled"); - for (i = agent->streams; i ; i = i->next) { - NiceStream *stream = i->data; - for (j = 1; j <= stream->n_components; j++) { - NiceComponent *component; - for (k = stream->conncheck_list; k ; k = k->next) { - CandidateCheckPair *pair = k->data; - if (pair->component_id == j) { - gchar local_addr[INET6_ADDRSTRLEN]; - gchar remote_addr[INET6_ADDRSTRLEN]; - gchar priority[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE]; - - nice_address_to_string (&pair->local->addr, local_addr); - nice_address_to_string (&pair->remote->addr, remote_addr); - nice_candidate_pair_priority_to_string (pair->priority, priority); - - nice_debug ("Agent %p : *** sc=%d/%d : pair %p : " - "f=%s t=%s:%s sock=%s " - "%s:[%s]:%u > %s:[%s]:%u prio=%s/%08x state=%c%s%s%s%s", - agent, pair->stream_id, pair->component_id, pair, - pair->foundation, - priv_candidate_type_to_string (pair->local->type), - priv_candidate_type_to_string (pair->remote->type), - priv_socket_type_to_string (pair->sockptr->type), - priv_candidate_transport_to_string (pair->local->transport), - local_addr, nice_address_get_port (&pair->local->addr), - priv_candidate_transport_to_string (pair->remote->transport), - remote_addr, nice_address_get_port (&pair->remote->addr), - priority, pair->stun_priority, - priv_state_to_gchar (pair->state), - pair->valid ? "V" : "", - pair->nominated ? "N" : "", - pair->use_candidate_on_next_check ? "C" : "", - g_slist_find (agent->triggered_check_queue, pair) ? "T" : ""); - - for (l = pair->stun_transactions, m = 0; l; l = l->next, m++) { - StunTransaction *stun = l->data; - nice_debug ("Agent %p : *** sc=%d/%d : pair %p : " - "stun#=%d timer=%d/%d %" G_GINT64_FORMAT "/%dms buf=%p %s", - agent, pair->stream_id, pair->component_id, pair, m, - stun->timer.retransmissions, stun->timer.max_retransmissions, - stun->timer.delay - priv_timer_remainder (stun->next_tick, now), - stun->timer.delay, - stun->message.buffer, - (m == 0 && pair->retransmit) ? "(R)" : ""); - } - } - } - if (agent_find_component (agent, stream->id, j, NULL, &component)) - print_component_incoming_checks (agent, stream, component); - } - } -} - -/* Add the pair to the triggered checks list, if not already present - */ -static void -priv_add_pair_to_triggered_check_queue (NiceAgent *agent, CandidateCheckPair *pair) -{ - g_assert (pair); - - if (agent->triggered_check_queue == NULL || - g_slist_find (agent->triggered_check_queue, pair) == NULL) - agent->triggered_check_queue = g_slist_append (agent->triggered_check_queue, pair); -} - -/* Remove the pair from the triggered checks list - */ -static void -priv_remove_pair_from_triggered_check_queue (NiceAgent *agent, CandidateCheckPair *pair) -{ - g_assert (pair); - agent->triggered_check_queue = g_slist_remove (agent->triggered_check_queue, pair); -} - -/* Get the pair from the triggered checks list - */ -static CandidateCheckPair * -priv_get_pair_from_triggered_check_queue (NiceAgent *agent) -{ - CandidateCheckPair *pair = NULL; - - if (agent->triggered_check_queue) { - pair = (CandidateCheckPair *)agent->triggered_check_queue->data; - priv_remove_pair_from_triggered_check_queue (agent, pair); - } - return pair; -} - -/* - * Finds the next connectivity check in WAITING state. - */ -static CandidateCheckPair *priv_conn_check_find_next_waiting (GSList *conn_check_list) -{ - GSList *i; - - /* note: list is sorted in priority order to first waiting check has - * the highest priority */ - for (i = conn_check_list; i ; i = i->next) { - CandidateCheckPair *p = i->data; - if (p->state == NICE_CHECK_WAITING) - return p; - } - - return NULL; -} - -/* - * Initiates a new connectivity check for a ICE candidate pair. - * - * @return TRUE on success, FALSE on error - */ -static gboolean -priv_conn_check_initiate (NiceAgent *agent, CandidateCheckPair *pair) -{ - SET_PAIR_STATE (agent, pair, NICE_CHECK_IN_PROGRESS); - if (conn_check_send (agent, pair)) { - SET_PAIR_STATE (agent, pair, NICE_CHECK_FAILED); - return FALSE; - } - return TRUE; -} - -/* - * Unfreezes the next connectivity check in the list. Follows the - * algorithm defined in sect 6.1.2.6 (Computing Candidate Pair States) - * and sect 6.1.4.2 (Performing Connectivity Checks) of the ICE spec - * (RFC8445) - * - * Note that this algorithm is slightly simplified compared to previous - * version of the spec (RFC5245), and this new version is now - * idempotent. - * - * @return TRUE on success, and FALSE if no frozen candidates were found. - */ -static gboolean -priv_conn_check_unfreeze_next (NiceAgent *agent) -{ - GSList *i, *j; - GSList *foundation_list = NULL; - gboolean result = FALSE; - - /* While a pair in state waiting exists, we do nothing */ - for (i = agent->streams; i ; i = i->next) { - NiceStream *s = i->data; - for (j = s->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - - if (p->state == NICE_CHECK_WAITING) - return TRUE; - } - } - - /* When there are no more pairs in waiting state, we unfreeze some - * pairs, so that we get a single waiting pair per foundation. - */ - for (i = agent->streams; i ; i = i->next) { - NiceStream *s = i->data; - for (j = s->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - - if (g_slist_find_custom (foundation_list, p->foundation, - (GCompareFunc)strcmp)) - continue; - - if (p->state == NICE_CHECK_FROZEN) { - nice_debug ("Agent %p : Pair %p with s/c-id %u/%u (%s) unfrozen.", - agent, p, p->stream_id, p->component_id, p->foundation); - SET_PAIR_STATE (agent, p, NICE_CHECK_WAITING); - foundation_list = g_slist_prepend (foundation_list, p->foundation); - result = TRUE; - } - } - } - g_slist_free (foundation_list); - - /* We dump the conncheck list when something interesting happened, ie - * when we unfroze some pairs. - */ - if (result) - priv_print_conn_check_lists (agent, G_STRFUNC, NULL); - - return result; -} - -/* - * Unfreezes the related connectivity check in the list after - * check 'success_check' has successfully completed. - * - * See sect 7.2.5.3.3 (Updating Candidate Pair States) of ICE spec (RFC8445). - * - * Note that this algorithm is slightly simplified compared to previous - * version of the spec (RFC5245) - * - * @param agent context - * @param pair a pair, whose connectivity check has just succeeded - * - */ -void -conn_check_unfreeze_related (NiceAgent *agent, CandidateCheckPair *pair) -{ - GSList *i, *j; - gboolean result = FALSE; - - g_assert (pair); - g_assert (pair->state == NICE_CHECK_SUCCEEDED); - - for (i = agent->streams; i ; i = i->next) { - NiceStream *s = i->data; - for (j = s->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - - /* The states for all other Frozen candidates pairs in all - * checklists with the same foundation is set to waiting - */ - if (p->state == NICE_CHECK_FROZEN && - strncmp (p->foundation, pair->foundation, - NICE_CANDIDATE_PAIR_MAX_FOUNDATION) == 0) { - nice_debug ("Agent %p : Unfreezing check %p " - "(after successful check %p).", agent, p, pair); - SET_PAIR_STATE (agent, p, NICE_CHECK_WAITING); - result = TRUE; - } - } - } - /* We dump the conncheck list when something interesting happened, ie - * when we unfroze some pairs. - */ - if (result) - priv_print_conn_check_lists (agent, G_STRFUNC, NULL); -} - -/* - * Unfreezes this connectivity check if its foundation is the same than - * the foundation of an already succeeded pair. - * - * See sect 7.2.5.3.3 (Updating Candidate Pair States) of ICE spec (RFC8445). - * - * @param agent context - * @param pair a pair, whose state is frozen - * - */ -static void -priv_conn_check_unfreeze_maybe (NiceAgent *agent, CandidateCheckPair *pair) -{ - GSList *i, *j; - gboolean result = FALSE; - - g_assert (pair); - g_assert (pair->state == NICE_CHECK_FROZEN); - - for (i = agent->streams; i ; i = i->next) { - NiceStream *s = i->data; - for (j = s->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - - if (p->state == NICE_CHECK_SUCCEEDED && - strncmp (p->foundation, pair->foundation, - NICE_CANDIDATE_PAIR_MAX_FOUNDATION) == 0) { - nice_debug ("Agent %p : Unfreezing check %p " - "(after successful check %p).", agent, pair, p); - SET_PAIR_STATE (agent, pair, NICE_CHECK_WAITING); - result = TRUE; - } - } - } - /* We dump the conncheck list when something interesting happened, ie - * when we unfroze some pairs. - */ - if (result) - priv_print_conn_check_lists (agent, G_STRFUNC, NULL); -} - -guint -conn_check_stun_transactions_count (NiceAgent *agent) -{ - GSList *i, *j; - guint count = 0; - - for (i = agent->streams; i ; i = i->next) { - NiceStream *s = i->data; - for (j = s->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - - if (p->stun_transactions) - count += g_slist_length (p->stun_transactions); - } - } - return count; -} - -/* - * Create a new STUN transaction and add it to the list - * of ongoing stun transactions of a pair. - * - * @pair the pair the new stun transaction should be added to. - * @return the created stun transaction. - */ -static StunTransaction * -priv_add_stun_transaction (CandidateCheckPair *pair) -{ - StunTransaction *stun = g_slice_new0 (StunTransaction); - pair->stun_transactions = g_slist_prepend (pair->stun_transactions, stun); - pair->retransmit = TRUE; - return stun; -} - -/* - * Forget a STUN transaction. - * - * @data the stun transaction to be forgotten. - * @user_data the component contained the concerned stun agent. - */ -static void -priv_forget_stun_transaction (gpointer data, gpointer user_data) -{ - StunTransaction *stun = data; - NiceComponent *component = user_data; - StunTransactionId id; - - if (stun->message.buffer != NULL) { - stun_message_id (&stun->message, id); - stun_agent_forget_transaction (&component->stun_agent, id); - } -} - -static void -priv_free_stun_transaction (gpointer data) -{ - g_slice_free (StunTransaction, data); -} - -/* - * Remove a STUN transaction from a pair, and forget it - * from the related component stun agent. - * - * @pair the pair the stun transaction should be removed from. - * @stun the stun transaction to be removed. - * @component the component containing the stun agent used to - * forget the stun transaction. - */ -static void -priv_remove_stun_transaction (CandidateCheckPair *pair, - StunTransaction *stun, NiceComponent *component) -{ - priv_forget_stun_transaction (stun, component); - pair->stun_transactions = g_slist_remove (pair->stun_transactions, stun); - priv_free_stun_transaction (stun); - if (pair->stun_transactions == NULL) - pair->retransmit = FALSE; -} - -/* - * Remove all STUN transactions from a pair, and forget them - * from the related component stun agent. - * - * @pair the pair the stun list should be cleared. - * @component the component containing the stun agent used to - * forget the stun transactions. - */ -static void -priv_free_all_stun_transactions (CandidateCheckPair *pair, - NiceComponent *component) -{ - if (component) - g_slist_foreach (pair->stun_transactions, priv_forget_stun_transaction, component); - g_slist_free_full (pair->stun_transactions, priv_free_stun_transaction); - pair->stun_transactions = NULL; - pair->retransmit = FALSE; -} - -static void -candidate_check_pair_fail (NiceStream *stream, NiceAgent *agent, CandidateCheckPair *p) -{ - NiceComponent *component; - - component = nice_stream_find_component_by_id (stream, p->component_id); - SET_PAIR_STATE (agent, p, NICE_CHECK_FAILED); - priv_free_all_stun_transactions (p, component); -} - -/* - * Helper function for connectivity check timer callback that - * runs through the stream specific part of the state machine. - * - * @param agent context pointer - * @param stream which stream (of the agent) - * @return will return TRUE if a new stun request has been sent - */ -static gboolean -priv_conn_check_tick_stream (NiceAgent *agent, NiceStream *stream) -{ - gboolean pair_failed = FALSE; - GSList *i, *j; - unsigned int timeout; - gint64 now; - - now = g_get_monotonic_time (); - - /* step: process ongoing STUN transactions */ - for (i = stream->conncheck_list; i ; i = i->next) { - CandidateCheckPair *p = i->data; - gchar tmpbuf1[INET6_ADDRSTRLEN], tmpbuf2[INET6_ADDRSTRLEN]; - NiceComponent *component; - guint index = 0, remaining = 0; - - if (p->stun_transactions == NULL) - continue; - - if (!agent_find_component (agent, p->stream_id, p->component_id, - NULL, &component)) - continue; - - j = p->stun_transactions; - while (j) { - StunTransaction *stun = j->data; - GSList *next = j->next; - - if (now < stun->next_tick) - remaining++; - else - switch (stun_timer_refresh (&stun->timer)) { - case STUN_USAGE_TIMER_RETURN_TIMEOUT: -timer_return_timeout: - priv_remove_stun_transaction (p, stun, component); - break; - case STUN_USAGE_TIMER_RETURN_RETRANSMIT: - /* case: retransmission stopped, due to the nomination of - * a pair with a higher priority than this in-progress pair, - * ICE spec, sect 8.1.2 "Updating States", item 2.2 - */ - if (!p->retransmit || index > 0) - goto timer_return_timeout; - - /* case: not ready, so schedule a new timeout */ - timeout = stun_timer_remainder (&stun->timer); - - nice_debug ("Agent %p :STUN transaction retransmitted on pair %p " - "(timer=%d/%d %d/%dms).", - agent, p, - stun->timer.retransmissions, stun->timer.max_retransmissions, - stun->timer.delay - timeout, stun->timer.delay); - - agent_socket_send (p->sockptr, &p->remote->addr, - stun_message_length (&stun->message), - (gchar *)stun->buffer); - - /* note: convert from milli to microseconds for g_time_val_add() */ - stun->next_tick = now + timeout * 1000; - - return TRUE; - case STUN_USAGE_TIMER_RETURN_SUCCESS: - timeout = stun_timer_remainder (&stun->timer); - /* note: convert from milli to microseconds for g_time_val_add() */ - stun->next_tick = now + timeout * 1000; - remaining++; - break; - default: - g_assert_not_reached(); - break; - } - j = next; - index++; - } - - if (remaining == 0) { - nice_address_to_string (&p->local->addr, tmpbuf1); - nice_address_to_string (&p->remote->addr, tmpbuf2); - nice_debug ("Agent %p : Retransmissions failed, giving up on pair %p", - agent, p); - nice_debug ("Agent %p : Failed pair is [%s]:%u --> [%s]:%u", agent, - tmpbuf1, nice_address_get_port (&p->local->addr), - tmpbuf2, nice_address_get_port (&p->remote->addr)); - candidate_check_pair_fail (stream, agent, p); - pair_failed = TRUE; - - /* perform a check if a transition state from connected to - * ready can be performed. This may happen here, when the last - * in-progress pair has expired its retransmission count - * in priv_conn_check_tick_stream(), which is a condition to - * make the transition connected to ready. - */ - conn_check_update_check_list_state_for_ready (agent, stream, component); - } - } - - if (pair_failed) - priv_print_conn_check_lists (agent, G_STRFUNC, ", retransmission failed"); - - return FALSE; -} - -static gboolean -priv_conn_check_ordinary_check (NiceAgent *agent, NiceStream *stream) -{ - CandidateCheckPair *pair; - gboolean stun_sent = FALSE; - - /* step: perform an ordinary check, sec 6.1.4.2 point 3. (Performing - * Connectivity Checks) of ICE spec (RFC8445) - * note: This code is executed when the triggered checks list is - * empty, and when no STUN message has been sent (pacing constraint) - */ - pair = priv_conn_check_find_next_waiting (stream->conncheck_list); - if (pair == NULL) { - /* step: there is no candidate in waiting state, try to unfreeze - * some pairs and retry, sect 6.1.4.2 point 2. (Performing Connectivity - * Checks) of ICE spec (RFC8445) - */ - priv_conn_check_unfreeze_next (agent); - pair = priv_conn_check_find_next_waiting (stream->conncheck_list); - } - - if (pair) { - stun_sent = priv_conn_check_initiate (agent, pair); - priv_print_conn_check_lists (agent, G_STRFUNC, - ", initiated an ordinary connection check"); - } - return stun_sent; -} - -static gboolean -priv_conn_check_triggered_check (NiceAgent *agent, NiceStream *stream) -{ - CandidateCheckPair *pair; - gboolean stun_sent = FALSE; - - /* step: perform a test from the triggered checks list, - * sect 6.1.4.2 point 1. (Performing Connectivity Checks) of ICE - * spec (RFC8445) - */ - pair = priv_get_pair_from_triggered_check_queue (agent); - - if (pair) { - stun_sent = priv_conn_check_initiate (agent, pair); - priv_print_conn_check_lists (agent, G_STRFUNC, - ", initiated a connection check from triggered check list"); - } - return stun_sent; -} - - -static gboolean -priv_conn_check_tick_stream_nominate (NiceAgent *agent, NiceStream *stream) -{ - gboolean keep_timer_going = FALSE; - /* s_xxx counters are stream-wide */ - guint s_inprogress = 0; - guint s_succeeded = 0; - guint s_discovered = 0; - guint s_nominated = 0; - guint s_waiting_for_nomination = 0; - guint s_valid = 0; - guint s_frozen = 0; - guint s_waiting = 0; - CandidateCheckPair *other_stream_pair = NULL; - GSList *i, *j; - - /* Search for a nominated pair (or selected to be nominated pair) - * from another stream. - */ - for (i = agent->streams; i ; i = i->next) { - NiceStream *s = i->data; - if (s->id == stream->id) - continue; - for (j = s->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - if (p->nominated || (p->use_candidate_on_next_check && - p->state != NICE_CHECK_FAILED)) { - other_stream_pair = p; - break; - } - } - if (other_stream_pair) - break; - } - - /* we compute some stream-wide counter values */ - for (i = stream->conncheck_list; i ; i = i->next) { - CandidateCheckPair *p = i->data; - if (p->state == NICE_CHECK_FROZEN) - s_frozen++; - else if (p->state == NICE_CHECK_IN_PROGRESS) - s_inprogress++; - else if (p->state == NICE_CHECK_WAITING) - s_waiting++; - else if (p->state == NICE_CHECK_SUCCEEDED) - s_succeeded++; - else if (p->state == NICE_CHECK_DISCOVERED) - s_discovered++; - if (p->valid) - s_valid++; - - if ((p->state == NICE_CHECK_SUCCEEDED || p->state == NICE_CHECK_DISCOVERED) - && p->nominated) - s_nominated++; - else if ((p->state == NICE_CHECK_SUCCEEDED || - p->state == NICE_CHECK_DISCOVERED) && !p->nominated) - s_waiting_for_nomination++; - } - - /* note: keep the timer going as long as there is work to be done */ - if (s_inprogress) - keep_timer_going = TRUE; - - if (s_nominated < stream->n_components && - s_waiting_for_nomination) { - if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) { - if (agent->nomination_mode == NICE_NOMINATION_MODE_REGULAR && - agent->controlling_mode) { -#define NICE_MIN_NUMBER_OF_VALID_PAIRS 2 - /* ICE 8.1.1.1 Regular nomination - * we choose to nominate the valid pair of a component if - * - there is no pair left frozen, waiting or in-progress, or - * - if there are at least two valid pairs, or - * - if there is at least one valid pair of type HOST-HOST - * - * This is the "stopping criterion" described in 8.1.1.1, and is - * a "local optimization" between accumulating more valid pairs, - * and limiting the time spent waiting for in-progress connections - * checks until they finally fail. - */ - for (i = stream->components; i; i = i->next) { - NiceComponent *component = i->data; - CandidateCheckPair *other_component_pair = NULL; - CandidateCheckPair *this_component_pair = NULL; - NiceCandidate *lcand1 = NULL; - NiceCandidate *rcand1 = NULL; - NiceCandidate *lcand2, *rcand2; - gboolean already_done = FALSE; - gboolean found_other_component_pair = FALSE; - gboolean found_other_stream_pair = FALSE; - gboolean first_nomination = FALSE; - gboolean stopping_criterion; - /* p_xxx counters are component-wide */ - guint p_valid = 0; - guint p_frozen = 0; - guint p_waiting = 0; - guint p_inprogress = 0; - guint p_host_host_valid = 0; - - /* we compute some component-wide counter values */ - for (j = stream->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - if (p->component_id == component->id) { - /* verify that the choice of the pair to be nominated - * has not already been done - */ - if (p->use_candidate_on_next_check) - already_done = TRUE; - if (p->state == NICE_CHECK_FROZEN) - p_frozen++; - else if (p->state == NICE_CHECK_WAITING) - p_waiting++; - else if (p->state == NICE_CHECK_IN_PROGRESS) - p_inprogress++; - if (p->valid) - p_valid++; - if (p->valid && - p->local->type == NICE_CANDIDATE_TYPE_HOST && - p->remote->type == NICE_CANDIDATE_TYPE_HOST) - p_host_host_valid++; - } - } - - if (already_done) - continue; - - /* Search for a nominated pair (or selected to be nominated pair) - * from another component of this stream. - */ - for (j = stream->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - if (p->component_id == component->id) - continue; - if (p->nominated || (p->use_candidate_on_next_check && - p->state != NICE_CHECK_FAILED)) { - other_component_pair = p; - break; - } - } - - if (other_stream_pair == NULL && other_component_pair == NULL) - first_nomination = TRUE; - - /* We choose a pair to be nominated in the list of valid - * pairs. - * - * this pair will be the one with the highest priority, - * when we don't have other nominated pairs in other - * components and in other streams - * - * this pair will be a pair compatible with another nominated - * pair from another component if we found one. - * - * else this pair will be a pair compatible with another - * nominated pair from another stream if we found one. - * - */ - for (j = stream->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - /* note: highest priority item selected (list always sorted) */ - if (p->component_id == component->id && - !p->nominated && - !p->use_candidate_on_next_check && - p->valid) { - /* According a ICE spec, sect 8.1.1.1. "Regular - * Nomination", we enqueue the check that produced this - * valid pair. When this pair has been discovered, we want - * to test its parent pair instead. - */ - if (p->succeeded_pair != NULL) { - g_assert_cmpint (p->state, ==, NICE_CHECK_DISCOVERED); - p = p->succeeded_pair; - } - g_assert_cmpint (p->state, ==, NICE_CHECK_SUCCEEDED); - - if (this_component_pair == NULL) - /* highest priority pair */ - this_component_pair = p; - - lcand1 = p->local; - rcand1 = p->remote; - - if (first_nomination) - /* use the highest priority pair */ - break; - - if (other_component_pair) { - lcand2 = other_component_pair->local; - rcand2 = other_component_pair->remote; - } - if (other_component_pair && - lcand1->transport == lcand2->transport && - nice_address_equal_no_port (&lcand1->addr, &lcand2->addr) && - nice_address_equal_no_port (&rcand1->addr, &rcand2->addr)) { - /* else continue the research with lower priority - * pairs, compatible with a nominated pair of - * another component - */ - this_component_pair = p; - found_other_component_pair = TRUE; - break; - } - - if (other_stream_pair) { - lcand2 = other_stream_pair->local; - rcand2 = other_stream_pair->remote; - } - if (other_stream_pair && - other_component_pair == NULL && - lcand1->transport == lcand2->transport && - nice_address_equal_no_port (&lcand1->addr, &lcand2->addr) && - nice_address_equal_no_port (&rcand1->addr, &rcand2->addr)) { - /* else continue the research with lower priority - * pairs, compatible with a nominated pair of - * another stream - */ - this_component_pair = p; - found_other_stream_pair = TRUE; - break; - } - } - } - - /* No valid pair for this component */ - if (this_component_pair == NULL) - continue; - - /* The stopping criterion tries to select a set of pairs of - * the same kind (transport/type) for all components of a - * stream, and for all streams, when possible (see last - * paragraph). - * - * When no stream has nominated a pair yet, we apply the - * following criterion : - * - stop if we have a valid host-host pair - * - or stop if we have at least "some* (2 in the current - * implementation) valid pairs, and select the best one - * - or stop if the conncheck cannot evolve more - * - * Else when the stream has a nominated pair in another - * component we apply this criterion: - * - stop if we have a valid pair of the same kind than this - * other nominated pair. - * - or stop if the conncheck cannot evolve more - * - * Else when another stream has a nominated pair we apply the - * following criterion: - * - stop if we have a valid pair of the same kind than the - * other nominated pair. - * - or stop if the conncheck cannot evolve more - * - * When no further evolution of the conncheck is possible, we - * prefer to select the best valid pair we have, *even* if it - * is not compatible with the transport of another stream of - * component. We think it's still a better choice than marking - * this component 'failed'. - */ - stopping_criterion = FALSE; - if (first_nomination && p_host_host_valid > 0) { - stopping_criterion = TRUE; - nice_debug ("Agent %p : stopping criterion: " - "valid host-host pair", agent); - } else if (first_nomination && - p_valid >= NICE_MIN_NUMBER_OF_VALID_PAIRS) { - stopping_criterion = TRUE; - nice_debug ("Agent %p : stopping criterion: " - "*some* valid pairs", agent); - } else if (found_other_component_pair) { - stopping_criterion = TRUE; - nice_debug ("Agent %p : stopping criterion: " - "matching pair in another component", agent); - } else if (found_other_stream_pair) { - stopping_criterion = TRUE; - nice_debug ("Agent %p : stopping criterion: " - "matching pair in another stream", agent); - } else if (p_waiting == 0 && p_inprogress == 0 && p_frozen == 0) { - stopping_criterion = TRUE; - nice_debug ("Agent %p : stopping criterion: " - "no more pairs to check", agent); - } - - if (!stopping_criterion) - continue; - - /* when the stopping criterion is reached, we add the - * selected pair for this component to the triggered checks - * list - */ - nice_debug ("Agent %p : restarting check of %s:%s pair %p with " - "USE-CANDIDATE attrib (regular nomination) for " - "stream %d component %d", agent, - priv_candidate_transport_to_string ( - this_component_pair->local->transport), - priv_candidate_transport_to_string ( - this_component_pair->remote->transport), - this_component_pair, stream->id, component->id); - this_component_pair->use_candidate_on_next_check = TRUE; - priv_add_pair_to_triggered_check_queue (agent, this_component_pair); - keep_timer_going = TRUE; - } - } - } else if (agent->controlling_mode) { - for (i = stream->components; i; i = i->next) { - NiceComponent *component = i->data; - - for (j = stream->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - /* note: highest priority item selected (list always sorted) */ - if (p->component_id == component->id && - (p->state == NICE_CHECK_SUCCEEDED || - p->state == NICE_CHECK_DISCOVERED)) { - nice_debug ("Agent %p : restarting check of pair %p as the " - "nominated pair.", agent, p); - p->nominated = TRUE; - conn_check_update_selected_pair (agent, component, p); - priv_add_pair_to_triggered_check_queue (agent, p); - keep_timer_going = TRUE; - break; /* move to the next component */ - } - } - } - } - } - if (stream->tick_counter++ % 50 == 0) - nice_debug ("Agent %p : stream %u: timer tick #%u: %u frozen, " - "%u in-progress, %u waiting, %u succeeded, %u discovered, " - "%u nominated, %u waiting-for-nom, %u valid", - agent, stream->id, stream->tick_counter, - s_frozen, s_inprogress, s_waiting, s_succeeded, s_discovered, - s_nominated, s_waiting_for_nomination, s_valid); - - return keep_timer_going; - -} - -static void -conn_check_stop (NiceAgent *agent) -{ - if (agent->conncheck_timer_source == NULL) - return; - - g_source_destroy (agent->conncheck_timer_source); - g_source_unref (agent->conncheck_timer_source); - agent->conncheck_timer_source = NULL; - agent->conncheck_ongoing_idle_delay = 0; -} - - -/* - * Timer callback that handles initiating and managing connectivity - * checks (paced by the Ta timer). - * - * This function is designed for the g_timeout_add() interface. - * - * @return will return FALSE when no more pending timers. - */ -static gboolean priv_conn_check_tick_agent_locked (NiceAgent *agent, - gpointer user_data) -{ - gboolean keep_timer_going = FALSE; - gboolean stun_sent = FALSE; - GSList *i, *j; - - /* step: process triggered checks - * these steps are ordered by priority, since a single stun request - * is sent per callback, we process the important steps first. - * - * perform a single stun request per timer callback, - * to respect stun pacing - */ - for (i = agent->streams; i && !stun_sent; i = i->next) { - NiceStream *stream = i->data; - - stun_sent = priv_conn_check_triggered_check (agent, stream); - } - - /* step: process ongoing STUN transactions */ - for (i = agent->streams; i && !stun_sent; i = i->next) { - NiceStream *stream = i->data; - - stun_sent = priv_conn_check_tick_stream (agent, stream); - } - - /* step: process ordinary checks */ - for (i = agent->streams; i && !stun_sent; i = i->next) { - NiceStream *stream = i->data; - - stun_sent = priv_conn_check_ordinary_check (agent, stream); - } - - if (stun_sent) - keep_timer_going = TRUE; - - /* step: try to nominate a pair - */ - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - - if (priv_conn_check_tick_stream_nominate (agent, stream)) - keep_timer_going = TRUE; - } - - /* note: we provide a grace period before declaring a component as - * failed. Components marked connected, and then ready follow another - * code path, and are not concerned by this grace period. - */ - if (!keep_timer_going && agent->conncheck_ongoing_idle_delay == 0) - nice_debug ("Agent %p : waiting %d msecs before checking " - "for failed components.", agent, agent->idle_timeout); - - if (keep_timer_going) - agent->conncheck_ongoing_idle_delay = 0; - else - agent->conncheck_ongoing_idle_delay += agent->timer_ta; - - /* step: stop timer if no work left */ - if (!keep_timer_going && - agent->conncheck_ongoing_idle_delay >= agent->idle_timeout) { - nice_debug ("Agent %p : checking for failed components now.", agent); - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - priv_update_check_list_failed_components (agent, stream); - for (j = stream->components; j; j = j->next) { - NiceComponent *component = j->data; - conn_check_update_check_list_state_for_ready (agent, stream, component); - } - } - - nice_debug ("Agent %p : %s: stopping conncheck timer", agent, G_STRFUNC); - priv_print_conn_check_lists (agent, G_STRFUNC, - ", conncheck timer stopped"); - - /* Stopping the timer so destroy the source.. this will allow - the timer to be reset if we get a set_remote_candidates after this - point */ - conn_check_stop (agent); - - /* XXX: what to signal, is all processing now really done? */ - nice_debug ("Agent %p : changing conncheck state to COMPLETED.", agent); - return FALSE; - } - - return TRUE; -} - -static gboolean priv_conn_keepalive_retransmissions_tick_agent_locked ( - NiceAgent *agent, gpointer pointer) -{ - CandidatePair *pair = (CandidatePair *) pointer; - - g_source_destroy (pair->keepalive.tick_source); - g_source_unref (pair->keepalive.tick_source); - pair->keepalive.tick_source = NULL; - - switch (stun_timer_refresh (&pair->keepalive.timer)) { - case STUN_USAGE_TIMER_RETURN_TIMEOUT: - { - /* Time out */ - StunTransactionId id; - NiceComponent *component; - - if (!agent_find_component (agent, - pair->keepalive.stream_id, pair->keepalive.component_id, - NULL, &component)) { - nice_debug ("Could not find stream or component in" - " priv_conn_keepalive_retransmissions_tick"); - return FALSE; - } - - stun_message_id (&pair->keepalive.stun_message, id); - stun_agent_forget_transaction (&component->stun_agent, id); - pair->keepalive.stun_message.buffer = NULL; - - if (agent->media_after_tick) { - nice_debug ("Agent %p : Keepalive conncheck timed out!! " - "but media was received. Suspecting keepalive lost because of " - "network bottleneck", agent); - } else { - nice_debug ("Agent %p : Keepalive conncheck timed out!! " - "peer probably lost connection", agent); - agent_signal_component_state_change (agent, - pair->keepalive.stream_id, pair->keepalive.component_id, - NICE_COMPONENT_STATE_FAILED); - } - break; - } - case STUN_USAGE_TIMER_RETURN_RETRANSMIT: - /* Retransmit */ - agent_socket_send (pair->local->sockptr, &pair->remote->addr, - stun_message_length (&pair->keepalive.stun_message), - (gchar *)pair->keepalive.stun_buffer); - - nice_debug ("Agent %p : Retransmitting keepalive conncheck", - agent); - - G_GNUC_FALLTHROUGH; - case STUN_USAGE_TIMER_RETURN_SUCCESS: - agent_timeout_add_with_context (agent, - &pair->keepalive.tick_source, - "Pair keepalive", stun_timer_remainder (&pair->keepalive.timer), - priv_conn_keepalive_retransmissions_tick_agent_locked, pair); - break; - default: - g_assert_not_reached(); - break; - } - - return FALSE; -} - -static guint32 peer_reflexive_candidate_priority (NiceAgent *agent, - NiceCandidate *local_candidate) -{ - NiceCandidate *candidate_priority = - nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE); - guint32 priority; - - candidate_priority->transport = local_candidate->transport; - candidate_priority->component_id = local_candidate->component_id; - candidate_priority->base_addr = local_candidate->addr; - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - priority = nice_candidate_jingle_priority (candidate_priority); - } else if (agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) { - priority = nice_candidate_msn_priority (candidate_priority); - } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - priority = nice_candidate_ms_ice_priority (candidate_priority, - agent->reliable, FALSE); - } else { - priority = nice_candidate_ice_priority (candidate_priority, - agent->reliable, FALSE); - } - nice_candidate_free (candidate_priority); - - return priority; -} - -/* Returns the priority of a local candidate of type peer-reflexive that - * would be learned as a consequence of a check from this local - * candidate. See RFC 5245, section 7.1.2.1. "PRIORITY and USE-CANDIDATE". - * RFC 5245 is more explanatory than RFC 8445 on this detail. - * - * Apply to local candidates of type host only, because candidates of type - * relay are supposed to have a public IP address, that wont generate - * a peer-reflexive address. Server-reflexive candidates are not - * concerned too, because no STUN request is sent with a local candidate - * of this type. - */ -static guint32 stun_request_priority (NiceAgent *agent, - NiceCandidate *local_candidate) -{ - if (local_candidate->type == NICE_CANDIDATE_TYPE_HOST) - return peer_reflexive_candidate_priority (agent, local_candidate); - else - return local_candidate->priority; -} - -static void ms_ice2_legacy_conncheck_send(StunMessage *msg, NiceSocket *sock, - const NiceAddress *remote_addr) -{ - uint32_t *fingerprint_attr; - uint32_t fingerprint_orig; - uint16_t fingerprint_len; - size_t buffer_len; - - if (msg->agent->ms_ice2_send_legacy_connchecks == FALSE) { - return; - } - - fingerprint_attr = (uint32_t *)stun_message_find (msg, - STUN_ATTRIBUTE_FINGERPRINT, &fingerprint_len); - - if (fingerprint_attr == NULL) { - nice_debug ("FINGERPRINT not found."); - return; - } - - if (fingerprint_len != sizeof (fingerprint_orig)) { - nice_debug ("Unexpected FINGERPRINT length %u.", fingerprint_len); - return; - } - - memcpy (&fingerprint_orig, fingerprint_attr, sizeof (fingerprint_orig)); - - buffer_len = stun_message_length (msg); - - *fingerprint_attr = stun_fingerprint (msg->buffer, buffer_len, TRUE); - - agent_socket_send (sock, remote_addr, buffer_len, (gchar *)msg->buffer); - - memcpy (fingerprint_attr, &fingerprint_orig, sizeof (fingerprint_orig)); -} - -/* - * Timer callback that handles initiating and managing connectivity - * checks (paced by the Ta timer). - * - * This function is designed for the g_timeout_add() interface. - * - * @return will return FALSE when no more pending timers. - */ -static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent) -{ - GSList *i, *j, *k; - int errors = 0; - size_t buf_len = 0; - guint64 now; - guint64 min_next_tick; - guint64 next_timer_tick; - - now = g_get_monotonic_time (); - min_next_tick = now + 1000 * NICE_AGENT_TIMER_TR_DEFAULT; - - /* case 1: session established and media flowing - * (ref ICE sect 11 "Keepalives" RFC-8445) - * TODO: keepalives should be send only when no packet has been sent - * on that pair in the last Tr seconds, and not unconditionally. - */ - for (i = agent->streams; i; i = i->next) { - - NiceStream *stream = i->data; - for (j = stream->components; j; j = j->next) { - NiceComponent *component = j->data; - if (component->selected_pair.local != NULL) { - CandidatePair *p = &component->selected_pair; - - /* Disable keepalive checks on TCP candidates unless explicitly enabled */ - if (p->local->transport != NICE_CANDIDATE_TRANSPORT_UDP && - !agent->keepalive_conncheck) - continue; - - if (p->keepalive.next_tick) { - if (p->keepalive.next_tick < min_next_tick) - min_next_tick = p->keepalive.next_tick; - if (now < p->keepalive.next_tick) - continue; - } - - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE || - agent->keepalive_conncheck) { - uint8_t uname[NICE_STREAM_MAX_UNAME]; - size_t uname_len = - priv_create_username (agent, agent_find_stream (agent, stream->id), - component->id, p->remote, p->local, uname, sizeof (uname), - FALSE); - uint8_t *password = NULL; - size_t password_len = priv_get_password (agent, - agent_find_stream (agent, stream->id), p->remote, &password); - - if (p->keepalive.stun_message.buffer != NULL) { - nice_debug ("Agent %p: Keepalive for s%u:c%u still" - " retransmitting, not restarting", agent, stream->id, - component->id); - continue; - } - - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (&p->remote->addr, tmpbuf); - nice_debug ("Agent %p : Keepalive STUN-CC REQ to '%s:%u', " - "(c-id:%u), username='%.*s' (%" G_GSIZE_FORMAT "), " - "password='%.*s' (%" G_GSIZE_FORMAT "), priority=%08x.", - agent, tmpbuf, nice_address_get_port (&p->remote->addr), - component->id, (int) uname_len, uname, uname_len, - (int) password_len, password, password_len, - p->stun_priority); - } - if (uname_len > 0) { - buf_len = stun_usage_ice_conncheck_create (&component->stun_agent, - &p->keepalive.stun_message, p->keepalive.stun_buffer, - sizeof(p->keepalive.stun_buffer), - uname, uname_len, password, password_len, - agent->controlling_mode, agent->controlling_mode, - p->stun_priority, - agent->tie_breaker, - NULL, - agent_to_ice_compatibility (agent)); - - nice_debug ("Agent %p: conncheck created %zd - %p", - agent, buf_len, p->keepalive.stun_message.buffer); - - if (buf_len > 0) { - stun_timer_start (&p->keepalive.timer, - agent->stun_initial_timeout, - agent->stun_max_retransmissions); - - agent->media_after_tick = FALSE; - - /* send the conncheck */ - agent_socket_send (p->local->sockptr, &p->remote->addr, - buf_len, (gchar *)p->keepalive.stun_buffer); - - p->keepalive.stream_id = stream->id; - p->keepalive.component_id = component->id; - p->keepalive.next_tick = now + 1000 * NICE_AGENT_TIMER_TR_DEFAULT; - - agent_timeout_add_with_context (agent, - &p->keepalive.tick_source, "Pair keepalive", - stun_timer_remainder (&p->keepalive.timer), - priv_conn_keepalive_retransmissions_tick_agent_locked, p); - - next_timer_tick = now + agent->timer_ta * 1000; - goto done; - } else { - ++errors; - } - } - } else { - buf_len = stun_usage_bind_keepalive (&component->stun_agent, - &p->keepalive.stun_message, p->keepalive.stun_buffer, - sizeof(p->keepalive.stun_buffer)); - - if (buf_len > 0) { - agent_socket_send (p->local->sockptr, &p->remote->addr, buf_len, - (gchar *)p->keepalive.stun_buffer); - - p->keepalive.next_tick = now + 1000 * NICE_AGENT_TIMER_TR_DEFAULT; - - if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - ms_ice2_legacy_conncheck_send (&p->keepalive.stun_message, - p->local->sockptr, &p->remote->addr); - } - - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (&p->local->base_addr, tmpbuf); - nice_debug ("Agent %p : resending STUN to keep the " - "selected base address %s:%u alive in s%d/c%d.", agent, - tmpbuf, nice_address_get_port (&p->local->base_addr), - stream->id, component->id); - } - - next_timer_tick = now + agent->timer_ta * 1000; - goto done; - } else { - ++errors; - } - } - } - } - } - - /* case 2: connectivity establishment ongoing - * (ref ICE sect 5.1.1.4 "Keeping Candidates Alive" RFC-8445) - */ - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - for (j = stream->components; j; j = j->next) { - NiceComponent *component = j->data; - if (component->state < NICE_COMPONENT_STATE_CONNECTED && - agent->stun_server_ip) { - NiceAddress stun_server; - if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) { - StunAgent stun_agent; - uint8_t stun_buffer[STUN_MAX_MESSAGE_SIZE_IPV6]; - StunMessage stun_message; - size_t buffer_len = 0; - - nice_address_set_port (&stun_server, agent->stun_server_port); - - nice_agent_init_stun_agent (agent, &stun_agent); - - buffer_len = stun_usage_bind_create (&stun_agent, - &stun_message, stun_buffer, sizeof(stun_buffer)); - - for (k = component->local_candidates; k; k = k->next) { - NiceCandidate *candidate = (NiceCandidate *) k->data; - if (candidate->type == NICE_CANDIDATE_TYPE_HOST && - candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP && - nice_address_ip_version (&candidate->addr) == - nice_address_ip_version (&stun_server)) { - - if (candidate->keepalive_next_tick) { - if (candidate->keepalive_next_tick < min_next_tick) - min_next_tick = candidate->keepalive_next_tick; - if (now < candidate->keepalive_next_tick) - continue; - } - - /* send the conncheck */ - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (&candidate->addr, tmpbuf); - nice_debug ("Agent %p : resending STUN to keep the local " - "candidate %s:%u alive in s%d/c%d.", agent, - tmpbuf, nice_address_get_port (&candidate->addr), - stream->id, component->id); - } - agent_socket_send (candidate->sockptr, &stun_server, - buffer_len, (gchar *)stun_buffer); - candidate->keepalive_next_tick = now + - 1000 * NICE_AGENT_TIMER_TR_DEFAULT; - next_timer_tick = now + agent->timer_ta * 1000; - goto done; - } - } - } - } - } - } - - next_timer_tick = min_next_tick; - - done: - if (errors) { - nice_debug ("Agent %p : %s: stopping keepalive timer", agent, G_STRFUNC); - return FALSE; - } - - if (agent->keepalive_timer_source) { - g_source_destroy (agent->keepalive_timer_source); - g_source_unref (agent->keepalive_timer_source); - agent->keepalive_timer_source = NULL; - } - agent_timeout_add_with_context (agent, &agent->keepalive_timer_source, - "Connectivity keepalive timeout", (next_timer_tick - now)/ 1000, - priv_conn_keepalive_tick_agent_locked, NULL); - return TRUE; -} - -static gboolean priv_conn_keepalive_tick_agent_locked (NiceAgent *agent, - gpointer pointer) -{ - gboolean ret; - - ret = priv_conn_keepalive_tick_unlocked (agent); - if (ret == FALSE) { - if (agent->keepalive_timer_source) { - g_source_destroy (agent->keepalive_timer_source); - g_source_unref (agent->keepalive_timer_source); - agent->keepalive_timer_source = NULL; - } - } - - return ret; -} - - -static gboolean priv_turn_allocate_refresh_retransmissions_tick_agent_locked ( - NiceAgent *agent, gpointer pointer) -{ - CandidateRefresh *cand = (CandidateRefresh *) pointer; - - g_source_destroy (cand->tick_source); - g_source_unref (cand->tick_source); - cand->tick_source = NULL; - - switch (stun_timer_refresh (&cand->timer)) { - case STUN_USAGE_TIMER_RETURN_TIMEOUT: - { - /* Time out */ - StunTransactionId id; - - stun_message_id (&cand->stun_message, id); - stun_agent_forget_transaction (&cand->stun_agent, id); - - refresh_free (agent, cand); - break; - } - case STUN_USAGE_TIMER_RETURN_RETRANSMIT: - /* Retransmit */ - agent_socket_send (cand->nicesock, &cand->server, - stun_message_length (&cand->stun_message), (gchar *)cand->stun_buffer); - - G_GNUC_FALLTHROUGH; - case STUN_USAGE_TIMER_RETURN_SUCCESS: - agent_timeout_add_with_context (agent, &cand->tick_source, - "Candidate TURN refresh", stun_timer_remainder (&cand->timer), - priv_turn_allocate_refresh_retransmissions_tick_agent_locked, cand); - break; - default: - /* Nothing to do. */ - break; - } - - return G_SOURCE_REMOVE; -} - -static void priv_turn_allocate_refresh_tick_unlocked (NiceAgent *agent, - CandidateRefresh *cand) -{ - uint8_t *username; - gsize username_len; - uint8_t *password; - gsize password_len; - size_t buffer_len = 0; - StunUsageTurnCompatibility turn_compat = - agent_to_turn_compatibility (agent); - - username = (uint8_t *)cand->candidate->turn->username; - username_len = (size_t) strlen (cand->candidate->turn->username); - password = (uint8_t *)cand->candidate->turn->password; - password_len = (size_t) strlen (cand->candidate->turn->password); - - if (turn_compat == STUN_USAGE_TURN_COMPATIBILITY_MSN || - turn_compat == STUN_USAGE_TURN_COMPATIBILITY_OC2007) { - username = cand->candidate->turn->decoded_username; - password = cand->candidate->turn->decoded_password; - username_len = cand->candidate->turn->decoded_username_len; - password_len = cand->candidate->turn->decoded_password_len; - } - - buffer_len = stun_usage_turn_create_refresh (&cand->stun_agent, - &cand->stun_message, cand->stun_buffer, sizeof(cand->stun_buffer), - cand->stun_resp_msg.buffer == NULL ? NULL : &cand->stun_resp_msg, -1, - username, username_len, - password, password_len, - turn_compat); - - nice_debug ("Agent %p : Sending allocate Refresh %zd", agent, - buffer_len); - - if (cand->tick_source != NULL) { - g_source_destroy (cand->tick_source); - g_source_unref (cand->tick_source); - cand->tick_source = NULL; - } - - if (buffer_len > 0) { - stun_timer_start (&cand->timer, - agent->stun_initial_timeout, - agent->stun_max_retransmissions); - - /* send the refresh */ - agent_socket_send (cand->nicesock, &cand->server, - buffer_len, (gchar *)cand->stun_buffer); - - agent_timeout_add_with_context (agent, &cand->tick_source, - "Candidate TURN refresh", stun_timer_remainder (&cand->timer), - priv_turn_allocate_refresh_retransmissions_tick_agent_locked, cand); - } - -} - - -/* - * Timer callback that handles refreshing TURN allocations - * - * This function is designed for the g_timeout_add() interface. - * - * @return will return FALSE when no more pending timers. - */ -static gboolean priv_turn_allocate_refresh_tick_agent_locked (NiceAgent *agent, - gpointer pointer) -{ - CandidateRefresh *cand = (CandidateRefresh *) pointer; - - priv_turn_allocate_refresh_tick_unlocked (agent, cand); - - return G_SOURCE_REMOVE; -} - - -/* - * Initiates the next pending connectivity check. - */ -void conn_check_schedule_next (NiceAgent *agent) -{ - if (agent->discovery_unsched_items > 0) - nice_debug ("Agent %p : WARN: starting conn checks before local candidate gathering is finished.", agent); - - /* step: schedule timer if not running yet */ - if (agent->conncheck_timer_source == NULL) { - agent_timeout_add_with_context (agent, &agent->conncheck_timer_source, - "Connectivity check schedule", agent->timer_ta, - priv_conn_check_tick_agent_locked, NULL); - } - - /* step: also start the keepalive timer */ - if (agent->keepalive_timer_source == NULL) { - agent_timeout_add_with_context (agent, &agent->keepalive_timer_source, - "Connectivity keepalive timeout", agent->timer_ta, - priv_conn_keepalive_tick_agent_locked, NULL); - } -} - -/* - * Compares two connectivity check items. Checkpairs are sorted - * in descending priority order, with highest priority item at - * the start of the list. - */ -gint conn_check_compare (const CandidateCheckPair *a, const CandidateCheckPair *b) -{ - if (a->priority > b->priority) - return -1; - else if (a->priority < b->priority) - return 1; - return 0; -} - -/* Find a transport compatible with a given socket. - * - * Returns TRUE when a matching transport can be guessed from - * the type of the socket in an unambiguous way. - */ -static gboolean -nice_socket_has_compatible_transport (NiceSocket *socket, - NiceCandidateTransport *transport) -{ - gboolean found = TRUE; - - g_assert (socket); - g_assert (transport); - - switch (socket->type) { - case NICE_SOCKET_TYPE_TCP_BSD: - if (nice_tcp_bsd_socket_get_passive_parent (socket)) - *transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE; - else - *transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; - break; - case NICE_SOCKET_TYPE_TCP_PASSIVE: - *transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE; - break; - case NICE_SOCKET_TYPE_TCP_ACTIVE: - *transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; - break; - case NICE_SOCKET_TYPE_UDP_BSD: - *transport = NICE_CANDIDATE_TRANSPORT_UDP; - break; - default: - found = FALSE; - } - - return found; -} - -/* Test if a local socket and a local candidate are compatible. This - * function does supplementary tests when the address and port are not - * sufficient to give a unique candidate. We try to avoid comparing - * directly the sockptr value, when possible, to rely on objective - * properties of the candidate and the socket instead, and we also - * choose to ignore the conncheck list for the same reason. - */ -static gboolean -local_candidate_and_socket_compatible (NiceAgent *agent, - NiceCandidate *lcand, NiceSocket *socket) -{ - gboolean ret = TRUE; - NiceCandidateTransport transport; - - g_assert (socket); - g_assert (lcand); - - if (nice_socket_has_compatible_transport (socket, &transport)) { - ret = (lcand->transport == transport); - /* tcp-active discovered peer-reflexive local candidate, where - * socket is the tcp connect related socket */ - if (ret && transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE && - nice_address_get_port (&lcand->addr) > 0) - ret = (lcand->sockptr == socket); - } else if (socket->type == NICE_SOCKET_TYPE_UDP_TURN) - /* Socket of type udp-turn will match a unique local candidate - * by its sockptr value. An an udp-turn socket doesn't carry enough - * information when base socket is udp-turn-over-tcp to disambiguate - * between a tcp-act and a tcp-pass local candidate. - */ - ret = (lcand->sockptr == socket); - - return ret; -} - -/* Test if a local socket and a remote candidate are compatible. - * This function is very close to its local candidate counterpart, - * the difference is that we also use information from the local - * candidate we may have identified previously. This is needed - * to disambiguate the transport of the candidate with a socket - * of type udp-turn. - * - */ -static gboolean -remote_candidate_and_socket_compatible (NiceAgent *agent, - NiceCandidate *lcand, NiceCandidate *rcand, NiceSocket *socket) -{ - gboolean ret = TRUE; - NiceCandidateTransport transport; - - g_assert (socket); - g_assert (rcand); - - if (nice_socket_has_compatible_transport (socket, &transport)) - ret = (conn_check_match_transport (rcand->transport) == transport); - - /* This supplementary test with the local candidate is needed with - * socket of type udp-turn, the type doesn't allow to disambiguate - * between a tcp-pass and a tcp-act remote candidate - */ - if (lcand && ret) - ret = (conn_check_match_transport (lcand->transport) == rcand->transport); - - return ret; -} - -void -conn_check_remote_candidates_set(NiceAgent *agent, NiceStream *stream, - NiceComponent *component) -{ - GList *i; - GSList *j; - NiceCandidate *lcand = NULL, *rcand = NULL; - - nice_debug ("Agent %p : conn_check_remote_candidates_set %u %u", - agent, stream->id, component->id); - - if (stream->remote_ufrag[0] == 0) - return; - - if (component->incoming_checks.head) - nice_debug ("Agent %p : credentials have been set, " - "we can process incoming checks", agent); - - for (i = component->incoming_checks.head; i;) { - IncomingCheck *icheck = i->data; - GList *i_next = i->next; - - nice_debug ("Agent %p : replaying icheck=%p (sock=%p)", - agent, icheck, icheck->local_socket); - - /* sect 7.2.1.3., "Learning Peer Reflexive Candidates", has to - * be handled separately */ - for (j = component->local_candidates; j; j = j->next) { - NiceCandidate *cand = j->data; - NiceAddress *addr; - - if (cand->type == NICE_CANDIDATE_TYPE_RELAYED) - addr = &cand->addr; - else - addr = &cand->base_addr; - - if (nice_address_equal (&icheck->local_socket->addr, addr) && - local_candidate_and_socket_compatible (agent, cand, - icheck->local_socket)) { - lcand = cand; - break; - } - } - - if (lcand == NULL) { - for (j = component->local_candidates; j; j = j->next) { - NiceCandidate *cand = j->data; - NiceAddress *addr = &cand->base_addr; - - /* tcp-active (not peer-reflexive discovered) local candidate, where - * socket is the tcp connect related socket */ - if (nice_address_equal_no_port (&icheck->local_socket->addr, addr) && - nice_address_get_port (&cand->addr) == 0 && - cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE && - local_candidate_and_socket_compatible (agent, cand, - icheck->local_socket)) { - lcand = cand; - break; - } - } - } - - g_assert (lcand != NULL); - - for (j = component->remote_candidates; j; j = j->next) { - NiceCandidate *cand = j->data; - if (nice_address_equal (&cand->addr, &icheck->from) && - remote_candidate_and_socket_compatible (agent, lcand, cand, - icheck->local_socket)) { - rcand = cand; - break; - } - } - - if (lcand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) { - CandidateCheckPair *pair = NULL; - - for (j = stream->conncheck_list; j; j = j->next) { - CandidateCheckPair *p = j->data; - if (lcand == p->local && rcand == p->remote) { - pair = p; - break; - } - } - if (pair == NULL) - priv_conn_check_add_for_candidate_pair_matched (agent, - stream->id, component, lcand, rcand, NICE_CHECK_WAITING); - } - - priv_schedule_triggered_check (agent, stream, component, - icheck->local_socket, rcand); - if (icheck->use_candidate) - priv_mark_pair_nominated (agent, stream, component, lcand, rcand); - - if (icheck->username) - g_free (icheck->username); - g_slice_free (IncomingCheck, icheck); - g_queue_delete_link (&component->incoming_checks, i); - i = i_next; - } -} - -/* - * Handle any processing steps for connectivity checks after - * remote credentials have been set. This function handles - * the special case where answerer has sent us connectivity - * checks before the answer (containing credentials information), - * reaches us. The special case is documented in RFC 5245 sect 7.2. - * ). - */ -void conn_check_remote_credentials_set(NiceAgent *agent, NiceStream *stream) -{ - GSList *j; - - for (j = stream->components; j ; j = j->next) { - NiceComponent *component = j->data; - - conn_check_remote_candidates_set(agent, stream, component); - } -} - -/* - * Enforces the upper limit for connectivity checks by dropping - * lower-priority pairs as described RFC 8445 section 6.1.2.5. See also - * conn_check_add_for_candidate(). - * Returns TRUE if the pair in argument is one of the deleted pairs. - */ -static gboolean priv_limit_conn_check_list_size (NiceAgent *agent, - NiceStream *stream, CandidateCheckPair *pair) -{ - guint valid = 0; - guint cancelled = 0; - gboolean deleted = FALSE; - GSList *item = stream->conncheck_list; - - while (item) { - CandidateCheckPair *p = item->data; - GSList *next = item->next; - - valid++; - /* We remove lower-priority pairs, but only the ones that can be - * safely discarded without breaking an ongoing conncheck process. - * This only includes pairs that are in the frozen state (those - * initially added when remote candidates are received) or in failed - * state. Pairs in any other state play a role in the conncheck, and - * there removal may lead to a failing conncheck that would succeed - * otherwise. - * - * We also remove failed pairs from the list unconditionally. - */ - if ((valid > agent->max_conn_checks && p->state == NICE_CHECK_FROZEN) || - p->state == NICE_CHECK_FAILED) { - if (p == pair) - deleted = TRUE; - nice_debug ("Agent %p : pair %p removed.", agent, p); - candidate_check_pair_free (agent, p); - stream->conncheck_list = g_slist_delete_link (stream->conncheck_list, - item); - cancelled++; - } - item = next; - } - - if (cancelled > 0) - nice_debug ("Agent %p : Pruned %d pairs. " - "Conncheck list has %d elements left. " - "Maximum connchecks allowed : %d", agent, cancelled, - valid - cancelled, agent->max_conn_checks); - - return deleted; -} - -/* - * Changes the selected pair for the component if 'pair' - * has higher priority than the currently selected pair. See - * RFC 8445 sect 8.1.1. "Nominating Pairs" - */ -void -conn_check_update_selected_pair (NiceAgent *agent, NiceComponent *component, - CandidateCheckPair *pair) -{ - CandidatePair cpair = { 0, }; - - g_assert (component); - g_assert (pair); - /* pair is expected to have the nominated flag */ - g_assert (pair->nominated); - if (pair->priority > component->selected_pair.priority) { - gchar priority[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE]; - nice_candidate_pair_priority_to_string (pair->priority, priority); - nice_debug ("Agent %p : changing SELECTED PAIR for component %u: %s:%s " - "(prio:%s).", agent, component->id, - pair->local->foundation, pair->remote->foundation, priority); - - cpair.local = pair->local; - cpair.remote = pair->remote; - cpair.priority = pair->priority; - cpair.stun_priority = pair->stun_priority; - - nice_component_update_selected_pair (agent, component, &cpair); - - priv_conn_keepalive_tick_unlocked (agent); - - agent_signal_new_selected_pair (agent, pair->stream_id, component->id, - pair->local, pair->remote); - } -} - -/* - * Updates the check list state. - * - * Implements parts of the algorithm described in - * ICE sect 8.1.2. "Updating States" (RFC 5245): if for any - * component, all checks have been completed and have - * failed to produce a nominated pair, mark that component's - * state to NICE_CHECK_FAILED. - * - * Sends a component state changesignal via 'agent'. - */ -static void priv_update_check_list_failed_components (NiceAgent *agent, NiceStream *stream) -{ - GSList *i; - gboolean completed; - guint nominated; - /* note: emitting a signal might cause the client - * to remove the stream, thus the component count - * must be fetched before entering the loop*/ - guint c, components = stream->n_components; - - if (stream->conncheck_list == NULL) - return; - - for (i = agent->discovery_list; i; i = i->next) { - CandidateDiscovery *d = i->data; - - /* There is still discovery ogoing for this stream, - * so don't fail any of it's candidates. - */ - if (d->stream_id == stream->id && !d->done) - return; - } - if (agent->discovery_list != NULL) - return; - - /* note: iterate the conncheck list for each component separately */ - for (c = 0; c < components; c++) { - NiceComponent *component = NULL; - if (!agent_find_component (agent, stream->id, c+1, NULL, &component)) - continue; - - nominated = 0; - completed = TRUE; - for (i = stream->conncheck_list; i; i = i->next) { - CandidateCheckPair *p = i->data; - - g_assert_cmpuint (p->stream_id, ==, stream->id); - - if (p->component_id == (c + 1)) { - if (p->nominated) - ++nominated; - if (p->state != NICE_CHECK_FAILED && - p->state != NICE_CHECK_SUCCEEDED && - p->state != NICE_CHECK_DISCOVERED) - completed = FALSE; - } - } - - /* note: all pairs are either failed or succeeded, and the component - * has not produced a nominated pair. - * Set the component to FAILED only if it actually had remote candidates - * that failed.. */ - if (completed && nominated == 0 && - component != NULL && component->remote_candidates != NULL) - agent_signal_component_state_change (agent, - stream->id, - (c + 1), /* component-id */ - NICE_COMPONENT_STATE_FAILED); - } -} - -/* - * Updates the check list state for a stream component. - * - * Implements the algorithm described in ICE sect 8.1.2 - * "Updating States" (ID-19) as it applies to checks of - * a certain component. If there are any nominated pairs, - * ICE processing may be concluded, and component state is - * changed to READY. - * - * Sends a component state changesignal via 'agent'. - */ -void conn_check_update_check_list_state_for_ready (NiceAgent *agent, - NiceStream *stream, NiceComponent *component) -{ - GSList *i; - guint valid = 0, nominated = 0; - - g_assert (component); - - /* step: search for at least one nominated pair */ - for (i = stream->conncheck_list; i; i = i->next) { - CandidateCheckPair *p = i->data; - if (p->component_id == component->id) { - if (p->valid) { - ++valid; - if (p->nominated == TRUE) { - ++nominated; - } - } - } - } - - if (nominated > 0) { - /* Only go to READY if no checks are left in progress. If there are - * any that are kept, then this function will be called again when the - * conncheck tick timer finishes them all */ - if (priv_prune_pending_checks (agent, stream, component) == 0) { - /* Continue through the states to give client code a nice - * logical progression. See http://phabricator.freedesktop.org/D218 for - * discussion. */ - if (component->state < NICE_COMPONENT_STATE_CONNECTING || - component->state == NICE_COMPONENT_STATE_FAILED) - agent_signal_component_state_change (agent, stream->id, component->id, - NICE_COMPONENT_STATE_CONNECTING); - if (component->state < NICE_COMPONENT_STATE_CONNECTED) - agent_signal_component_state_change (agent, stream->id, component->id, - NICE_COMPONENT_STATE_CONNECTED); - agent_signal_component_state_change (agent, stream->id, - component->id, NICE_COMPONENT_STATE_READY); - } - } - nice_debug ("Agent %p : conn.check list status: %u nominated, %u valid, c-id %u.", agent, nominated, valid, component->id); -} - -/* - * The remote party has signalled that the candidate pair - * described by 'component' and 'remotecand' is nominated - * for use. - */ -static void priv_mark_pair_nominated (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceCandidate *localcand, NiceCandidate *remotecand) -{ - GSList *i; - - g_assert (component); - - if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) && - agent->controlling_mode) - return; - - /* step: search for at least one nominated pair */ - for (i = stream->conncheck_list; i; i = i->next) { - CandidateCheckPair *pair = i->data; - if (pair->local == localcand && pair->remote == remotecand) { - /* ICE, 7.2.1.5. Updating the Nominated Flag */ - /* note: TCP candidates typically produce peer reflexive - * candidate, generating a "discovered" pair that can be - * nominated. - */ - if (pair->state == NICE_CHECK_SUCCEEDED && - pair->discovered_pair != NULL) { - pair = pair->discovered_pair; - g_assert_cmpint (pair->state, ==, NICE_CHECK_DISCOVERED); - } - - /* If the received Binding request triggered a new check to be - * enqueued in the triggered-check queue (Section 7.3.1.4), once - * the check is sent and if it generates a successful response, - * and generates a valid pair, the agent sets the nominated flag - * of the pair to true - */ - if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) { - if (g_slist_find (agent->triggered_check_queue, pair) || - pair->state == NICE_CHECK_IN_PROGRESS) { - - /* This pair is not always in the triggered check list, for - * example if it is in-progress with a lower priority than an - * already nominated pair. Is that case, it is not rescheduled - * for a connection check, see function - * priv_schedule_triggered_check(), case NICE_CHECK_IN_PROGRESS. - */ - pair->mark_nominated_on_response_arrival = TRUE; - nice_debug ("Agent %p : pair %p (%s) is %s, " - "will be nominated on response receipt.", - agent, pair, pair->foundation, - priv_state_to_string (pair->state)); - } - } - - if (pair->valid || - !NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) { - nice_debug ("Agent %p : marking pair %p (%s) as nominated", - agent, pair, pair->foundation); - pair->nominated = TRUE; - } - - if (pair->valid) { - /* Do not step down to CONNECTED if we're already at state READY*/ - if (component->state == NICE_COMPONENT_STATE_FAILED) - agent_signal_component_state_change (agent, - stream->id, component->id, NICE_COMPONENT_STATE_CONNECTING); - conn_check_update_selected_pair (agent, component, pair); - if (component->state == NICE_COMPONENT_STATE_CONNECTING) - /* step: notify the client of a new component state (must be done - * before the possible check list state update step */ - agent_signal_component_state_change (agent, - stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED); - } - - if (pair->nominated) - conn_check_update_check_list_state_for_ready (agent, stream, component); - } - } -} - -/* - * Creates a new connectivity check pair and adds it to - * the agent's list of checks. - */ -static CandidateCheckPair *priv_add_new_check_pair (NiceAgent *agent, - guint stream_id, NiceComponent *component, NiceCandidate *local, - NiceCandidate *remote, NiceCheckState initial_state) -{ - NiceStream *stream; - CandidateCheckPair *pair; - guint64 priority; - - g_assert (local != NULL); - g_assert (remote != NULL); - - priority = agent_candidate_pair_priority (agent, local, remote); - - if (component->selected_pair.priority && - priority < component->selected_pair.priority) { - gchar prio1[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE]; - gchar prio2[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE]; - - nice_candidate_pair_priority_to_string (priority, prio1); - nice_candidate_pair_priority_to_string (component->selected_pair.priority, - prio2); - nice_debug ("Agent %p : do not create a pair that would have a priority " - "%s lower than selected pair priority %s.", agent, prio1, prio2); - return NULL; - } - - stream = agent_find_stream (agent, stream_id); - pair = g_slice_new0 (CandidateCheckPair); - - pair->stream_id = stream_id; - pair->component_id = component->id;; - pair->local = local; - pair->remote = remote; - /* note: we use the remote sockptr only in the case - * of TCP transport - */ - if (local->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE && - remote->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) - pair->sockptr = (NiceSocket *) remote->sockptr; - else - pair->sockptr = (NiceSocket *) local->sockptr; - g_snprintf (pair->foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s", local->foundation, remote->foundation); - - pair->priority = agent_candidate_pair_priority (agent, local, remote); - nice_debug ("Agent %p : creating a new pair", agent); - SET_PAIR_STATE (agent, pair, initial_state); - { - gchar tmpbuf1[INET6_ADDRSTRLEN]; - gchar tmpbuf2[INET6_ADDRSTRLEN]; - nice_address_to_string (&pair->local->addr, tmpbuf1); - nice_address_to_string (&pair->remote->addr, tmpbuf2); - nice_debug ("Agent %p : new pair %p : [%s]:%u --> [%s]:%u", agent, pair, - tmpbuf1, nice_address_get_port (&pair->local->addr), - tmpbuf2, nice_address_get_port (&pair->remote->addr)); - } - pair->stun_priority = stun_request_priority (agent, local); - - stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair, - (GCompareFunc)conn_check_compare); - - nice_debug ("Agent %p : added a new pair %p with foundation '%s' and " - "transport %s:%s to stream %u component %u", - agent, pair, pair->foundation, - priv_candidate_transport_to_string (pair->local->transport), - priv_candidate_transport_to_string (pair->remote->transport), - stream_id, component->id); - - if (initial_state == NICE_CHECK_FROZEN) - priv_conn_check_unfreeze_maybe (agent, pair); - - /* implement the hard upper limit for number of - checks (see sect 5.7.3 ICE ID-19): */ - if (agent->compatibility == NICE_COMPATIBILITY_RFC5245) { - if (priv_limit_conn_check_list_size (agent, stream, pair)) - return NULL; - } - - return pair; -} - -NiceCandidateTransport -conn_check_match_transport (NiceCandidateTransport transport) -{ - switch (transport) { - case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE: - return NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE; - break; - case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE: - return NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; - break; - case NICE_CANDIDATE_TRANSPORT_TCP_SO: - case NICE_CANDIDATE_TRANSPORT_UDP: - default: - return transport; - break; - } -} - -static CandidateCheckPair *priv_conn_check_add_for_candidate_pair_matched ( - NiceAgent *agent, guint stream_id, NiceComponent *component, - NiceCandidate *local, NiceCandidate *remote, NiceCheckState initial_state) -{ - CandidateCheckPair *pair; - - pair = priv_add_new_check_pair (agent, stream_id, component, local, remote, - initial_state); - if (pair) { - if (component->state == NICE_COMPONENT_STATE_CONNECTED || - component->state == NICE_COMPONENT_STATE_READY) { - agent_signal_component_state_change (agent, - stream_id, - component->id, - NICE_COMPONENT_STATE_CONNECTED); - } else { - agent_signal_component_state_change (agent, - stream_id, - component->id, - NICE_COMPONENT_STATE_CONNECTING); - } - } - - return pair; -} - -gboolean conn_check_add_for_candidate_pair (NiceAgent *agent, - guint stream_id, NiceComponent *component, NiceCandidate *local, - NiceCandidate *remote) -{ - gboolean ret = FALSE; - - g_assert (local != NULL); - g_assert (remote != NULL); - - /* note: do not create pairs where the local candidate is a srv-reflexive - * or peer-reflexive (ICE 6.1.2.4. "Pruning the pairs" RFC 8445) - */ - if ((agent->compatibility == NICE_COMPATIBILITY_RFC5245 || - agent->compatibility == NICE_COMPATIBILITY_WLM2009 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2) && - (local->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE || - local->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE)) { - return FALSE; - } - - /* note: do not create pairs where local candidate has TCP passive transport - * (ice-tcp-13 6.2. "Forming the Check Lists") */ - if (local->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) { - return FALSE; - } - - /* note: match pairs only if transport and address family are the same */ - if (local->transport == conn_check_match_transport (remote->transport) && - local->addr.s.addr.sa_family == remote->addr.s.addr.sa_family) { - if (priv_conn_check_add_for_candidate_pair_matched (agent, stream_id, - component, local, remote, NICE_CHECK_FROZEN)) - ret = TRUE; - } - - return ret; -} - -/* - * Forms new candidate pairs by matching the new remote candidate - * 'remote_cand' with all existing local candidates of 'component'. - * Implements the logic described in ICE sect 5.7.1. "Forming Candidate - * Pairs" (ID-19). - * - * @param agent context - * @param component pointer to the component - * @param remote remote candidate to match with - * - * @return number of checks added, negative on fatal errors - */ -int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *remote) -{ - GSList *i; - int added = 0; - int ret = 0; - - g_assert (remote != NULL); - - /* note: according to 7.2.1.3, "Learning Peer Reflexive Candidates", - * the agent does not pair this candidate with any local candidates. - */ - if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) && - remote->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) - { - return added; - } - - for (i = component->local_candidates; i ; i = i->next) { - NiceCandidate *local = i->data; - - if (agent->force_relay && local->type != NICE_CANDIDATE_TYPE_RELAYED) - continue; - - ret = conn_check_add_for_candidate_pair (agent, stream_id, component, local, remote); - - if (ret) { - ++added; - } - } - - return added; -} - -/* - * Forms new candidate pairs by matching the new local candidate - * 'local_cand' with all existing remote candidates of 'component'. - * - * @param agent context - * @param component pointer to the component - * @param local local candidate to match with - * - * @return number of checks added, negative on fatal errors - */ -int conn_check_add_for_local_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local) -{ - GSList *i; - int added = 0; - int ret = 0; - - g_assert (local != NULL); - - /* - * note: according to 7.1.3.2.1 "Discovering Peer Reflexive - * Candidates", the peer reflexive candidate is not paired - * with other remote candidates - */ - - if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) && - local->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) - { - return added; - } - - for (i = component->remote_candidates; i ; i = i->next) { - - NiceCandidate *remote = i->data; - ret = conn_check_add_for_candidate_pair (agent, stream_id, component, local, remote); - - if (ret) { - ++added; - } - } - - return added; -} - -/* - * Frees the CandidateCheckPair structure pointer to - * by 'user data'. Compatible with GDestroyNotify. - */ -static void candidate_check_pair_free (NiceAgent *agent, - CandidateCheckPair *pair) -{ - priv_remove_pair_from_triggered_check_queue (agent, pair); - priv_free_all_stun_transactions (pair, NULL); - g_slice_free (CandidateCheckPair, pair); -} - -/* - * Frees all resources of all connectivity checks. - */ -void conn_check_free (NiceAgent *agent) -{ - GSList *i; - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - - if (stream->conncheck_list) { - GSList *item; - - nice_debug ("Agent %p, freeing conncheck_list of stream %p", agent, - stream); - for (item = stream->conncheck_list; item; item = item->next) - candidate_check_pair_free (agent, item->data); - g_slist_free (stream->conncheck_list); - stream->conncheck_list = NULL; - } - } - - conn_check_stop (agent); -} - -/* - * Prunes the list of connectivity checks for items related - * to stream 'stream_id'. - * - * @return TRUE on success, FALSE on a fatal error - */ -void conn_check_prune_stream (NiceAgent *agent, NiceStream *stream) -{ - GSList *i; - gboolean keep_going = FALSE; - - if (stream->conncheck_list) { - GSList *item; - - nice_debug ("Agent %p, freeing conncheck_list of stream %p", agent, stream); - - for (item = stream->conncheck_list; item; item = item->next) - candidate_check_pair_free (agent, item->data); - g_slist_free (stream->conncheck_list); - stream->conncheck_list = NULL; - } - - for (i = agent->streams; i; i = i->next) { - NiceStream *s = i->data; - if (s->conncheck_list) { - keep_going = TRUE; - break; - } - } - - if (!keep_going) - conn_check_stop (agent); -} - -/* - * Fills 'dest' with a username string for use in an outbound connectivity - * checks. No more than 'dest_len' characters (including terminating - * NULL) is ever written to the 'dest'. - */ -static -size_t priv_gen_username (NiceAgent *agent, guint component_id, - gchar *remote, gchar *local, uint8_t *dest, guint dest_len) -{ - guint len = 0; - gsize remote_len = strlen (remote); - gsize local_len = strlen (local); - - if (remote_len > 0 && local_len > 0) { - if (agent->compatibility == NICE_COMPATIBILITY_RFC5245 && - dest_len >= remote_len + local_len + 1) { - memcpy (dest, remote, remote_len); - len += remote_len; - memcpy (dest + len, ":", 1); - len++; - memcpy (dest + len, local, local_len); - len += local_len; - } else if ((agent->compatibility == NICE_COMPATIBILITY_WLM2009 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2) && - dest_len >= remote_len + local_len + 4 ) { - memcpy (dest, remote, remote_len); - len += remote_len; - memcpy (dest + len, ":", 1); - len++; - memcpy (dest + len, local, local_len); - len += local_len; - if (len % 4 != 0) { - memset (dest + len, 0, 4 - (len % 4)); - len += 4 - (len % 4); - } - } else if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE && - dest_len >= remote_len + local_len) { - memcpy (dest, remote, remote_len); - len += remote_len; - memcpy (dest + len, local, local_len); - len += local_len; - } else if (agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) { - gchar component_str[10]; - guchar *local_decoded = NULL; - guchar *remote_decoded = NULL; - gsize local_decoded_len; - gsize remote_decoded_len; - gsize total_len; - int padding; - - g_snprintf (component_str, sizeof(component_str), "%d", component_id); - local_decoded = g_base64_decode (local, &local_decoded_len); - remote_decoded = g_base64_decode (remote, &remote_decoded_len); - - total_len = remote_decoded_len + local_decoded_len + 3 + 2*strlen (component_str); - padding = 4 - (total_len % 4); - - if (dest_len >= total_len + padding) { - guchar pad_char[1] = {0}; - int i; - - memcpy (dest, remote_decoded, remote_decoded_len); - len += remote_decoded_len; - memcpy (dest + len, ":", 1); - len++; - memcpy (dest + len, component_str, strlen (component_str)); - len += strlen (component_str); - - memcpy (dest + len, ":", 1); - len++; - - memcpy (dest + len, local_decoded, local_decoded_len); - len += local_decoded_len; - memcpy (dest + len, ":", 1); - len++; - memcpy (dest + len, component_str, strlen (component_str));; - len += strlen (component_str); - - for (i = 0; i < padding; i++) { - memcpy (dest + len, pad_char, 1); - len++; - } - - } - - g_free (local_decoded); - g_free (remote_decoded); - } - } - - return len; -} - -/* - * Fills 'dest' with a username string for use in an outbound connectivity - * checks. No more than 'dest_len' characters (including terminating - * NULL) is ever written to the 'dest'. - */ -static -size_t priv_create_username (NiceAgent *agent, NiceStream *stream, - guint component_id, NiceCandidate *remote, NiceCandidate *local, - uint8_t *dest, guint dest_len, gboolean inbound) -{ - gchar *local_username = NULL; - gchar *remote_username = NULL; - - - if (remote && remote->username) { - remote_username = remote->username; - } - - if (local && local->username) { - local_username = local->username; - } - - if (stream) { - if (remote_username == NULL) { - remote_username = stream->remote_ufrag; - } - if (local_username == NULL) { - local_username = stream->local_ufrag; - } - } - - if (local_username && remote_username) { - if (inbound) { - return priv_gen_username (agent, component_id, - local_username, remote_username, dest, dest_len); - } else { - return priv_gen_username (agent, component_id, - remote_username, local_username, dest, dest_len); - } - } - - return 0; -} - -/* - * Returns a password string for use in an outbound connectivity - * check. - */ -static -size_t priv_get_password (NiceAgent *agent, NiceStream *stream, - NiceCandidate *remote, uint8_t **password) -{ - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) - return 0; - - if (remote && remote->password) { - *password = (uint8_t *)remote->password; - return strlen (remote->password); - } - - if (stream) { - *password = (uint8_t *)stream->remote_password; - return strlen (stream->remote_password); - } - - return 0; -} - -/* Implement the computation specific in RFC 8445 section 14 */ - -static unsigned int priv_compute_conncheck_timer (NiceAgent *agent, NiceStream *stream) -{ - GSList *i, *j; - guint waiting_and_in_progress = 0; - unsigned int rto = 0; - - /* we can compute precisely the number of pairs in-progress or - * waiting for all streams, instead of limiting the value to one - * stream, and multiplying it by the number of active streams. - * Since RFC8445, this number of waiting and in-progress pairs - * if maxed by the number of different foundations in the conncheck - * list. - */ - for (i = agent->streams; i ; i = i->next) { - NiceStream *s = i->data; - for (j = s->conncheck_list; j ; j = j->next) { - CandidateCheckPair *p = j->data; - if (p->state == NICE_CHECK_IN_PROGRESS || - p->state == NICE_CHECK_WAITING) - waiting_and_in_progress++; - } - } - - rto = agent->timer_ta * waiting_and_in_progress; - - nice_debug ("Agent %p : timer set to %dms, " - "waiting+in_progress=%d", agent, MAX (rto, STUN_TIMER_DEFAULT_TIMEOUT), - waiting_and_in_progress); - return MAX (rto, STUN_TIMER_DEFAULT_TIMEOUT); -} - -/* - * Sends a connectivity check over candidate pair 'pair'. - * - * @return zero on success, non-zero on error - */ -int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair) -{ - - /* note: following information is supplied: - * - username (for USERNAME attribute) - * - password (for MESSAGE-INTEGRITY) - * - priority (for PRIORITY) - * - ICE-CONTROLLED/ICE-CONTROLLING (for role conflicts) - * - USE-CANDIDATE (if sent by the controlling agent) - */ - - uint8_t uname[NICE_STREAM_MAX_UNAME]; - NiceStream *stream; - NiceComponent *component; - gsize uname_len; - uint8_t *password = NULL; - gsize password_len; - bool controlling = agent->controlling_mode; - /* XXX: add API to support different nomination modes: */ - bool cand_use = controlling; - size_t buffer_len; - unsigned int timeout; - StunTransaction *stun; - - if (!agent_find_component (agent, pair->stream_id, pair->component_id, - &stream, &component)) - return -1; - - uname_len = priv_create_username (agent, stream, pair->component_id, - pair->remote, pair->local, uname, sizeof (uname), FALSE); - password_len = priv_get_password (agent, stream, pair->remote, &password); - - if (password != NULL && - (agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007)) { - password = g_base64_decode ((gchar *) password, &password_len); - } - - if (nice_debug_is_enabled ()) { - gchar tmpbuf1[INET6_ADDRSTRLEN]; - gchar tmpbuf2[INET6_ADDRSTRLEN]; - nice_address_to_string (&pair->local->addr, tmpbuf1); - nice_address_to_string (&pair->remote->addr, tmpbuf2); - nice_debug ("Agent %p : STUN-CC REQ [%s]:%u --> [%s]:%u, socket=%u, " - "pair=%p (c-id:%u), tie=%llu, username='%.*s' (%" G_GSIZE_FORMAT "), " - "password='%.*s' (%" G_GSIZE_FORMAT "), prio=%08x, %s.", agent, - tmpbuf1, nice_address_get_port (&pair->local->addr), - tmpbuf2, nice_address_get_port (&pair->remote->addr), - pair->sockptr->fileno ? g_socket_get_fd(pair->sockptr->fileno) : -1, - pair, pair->component_id, - (unsigned long long)agent->tie_breaker, - (int) uname_len, uname, uname_len, - (int) password_len, password, password_len, - pair->stun_priority, - controlling ? "controlling" : "controlled"); - } - - if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) { - switch (agent->nomination_mode) { - case NICE_NOMINATION_MODE_REGULAR: - /* We are doing regular nomination, so we set the use-candidate - * attrib, when the controlling agent decided which valid pair to - * resend with this flag in priv_conn_check_tick_stream() - */ - cand_use = pair->use_candidate_on_next_check; - nice_debug ("Agent %p : %s: set cand_use=%d " - "(regular nomination).", agent, G_STRFUNC, cand_use); - break; - case NICE_NOMINATION_MODE_AGGRESSIVE: - /* We are doing aggressive nomination, we set the use-candidate - * attrib in every check we send, when we are the controlling - * agent, RFC 5245, 8.1.1.2 - */ - cand_use = controlling; - nice_debug ("Agent %p : %s: set cand_use=%d " - "(aggressive nomination).", agent, G_STRFUNC, cand_use); - break; - default: - /* Nothing to do. */ - break; - } - } else if (cand_use) - pair->nominated = controlling; - - if (uname_len == 0) { - nice_debug ("Agent %p: no credentials found, cancelling conncheck", agent); - return -1; - } - - stun = priv_add_stun_transaction (pair); - - buffer_len = stun_usage_ice_conncheck_create (&component->stun_agent, - &stun->message, stun->buffer, sizeof(stun->buffer), - uname, uname_len, password, password_len, - cand_use, controlling, pair->stun_priority, - agent->tie_breaker, - pair->local->foundation, - agent_to_ice_compatibility (agent)); - - nice_debug ("Agent %p: conncheck created %zd - %p", agent, buffer_len, - stun->message.buffer); - - if (agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) { - g_free (password); - } - - if (buffer_len == 0) { - nice_debug ("Agent %p: buffer is empty, cancelling conncheck", agent); - priv_remove_stun_transaction (pair, stun, component); - return -1; - } - - if (nice_socket_is_reliable(pair->sockptr)) { - timeout = agent->stun_reliable_timeout; - stun_timer_start_reliable(&stun->timer, timeout); - } else { - timeout = priv_compute_conncheck_timer (agent, stream); - stun_timer_start (&stun->timer, timeout, agent->stun_max_retransmissions); - } - - stun->next_tick = g_get_monotonic_time () + timeout * 1000; - - /* TCP-ACTIVE candidate must create a new socket before sending - * by connecting to the peer. The new socket is stored in the candidate - * check pair, until we discover a new local peer reflexive */ - if (pair->sockptr->fileno == NULL && - pair->sockptr->type != NICE_SOCKET_TYPE_UDP_TURN && - pair->local->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) { - NiceStream *stream2 = NULL; - NiceComponent *component2 = NULL; - NiceSocket *new_socket; - - if (agent_find_component (agent, pair->stream_id, pair->component_id, - &stream2, &component2)) { - new_socket = nice_tcp_active_socket_connect (pair->sockptr, - &pair->remote->addr); - if (new_socket) { - nice_debug ("Agent %p: add to tcp-act socket %p a new " - "tcp connect socket %p on pair %p in s/c %d/%d", - agent, pair->sockptr, new_socket, pair, stream->id, component->id); - pair->sockptr = new_socket; - _priv_set_socket_tos (agent, pair->sockptr, stream2->tos); - - nice_socket_set_writable_callback (pair->sockptr, _tcp_sock_is_writable, - component2); - - nice_component_attach_socket (component2, new_socket); - } - } - } - /* send the conncheck */ - agent_socket_send (pair->sockptr, &pair->remote->addr, - buffer_len, (gchar *)stun->buffer); - - if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) - ms_ice2_legacy_conncheck_send (&stun->message, pair->sockptr, - &pair->remote->addr); - - return 0; -} - -/* - * Implemented the pruning steps described in ICE sect 8.1.2 - * "Updating States" (ID-19) after a pair has been nominated. - * - * @see conn_check_update_check_list_state_failed_components() - */ -static guint priv_prune_pending_checks (NiceAgent *agent, NiceStream *stream, NiceComponent *component) -{ - GSList *i; - guint64 priority; - guint in_progress = 0; - guint triggered_check = 0; - gchar prio[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE]; - - nice_debug ("Agent %p: Pruning pending checks for s%d/c%d", - agent, stream->id, component->id); - - /* Called when we have at least one selected pair */ - priority = component->selected_pair.priority; - g_assert (priority > 0); - - nice_candidate_pair_priority_to_string (priority, prio); - nice_debug ("Agent %p : selected pair priority is %s", agent, prio); - - i = stream->conncheck_list; - while (i) { - CandidateCheckPair *p = i->data; - GSList *next = i->next; - - if (p->component_id != component->id) { - i = next; - continue; - } - - /* We do not remove a pair from the conncheck list if it is also in - * the triggered check queue. This is not what suggests the ICE - * spec, but it proved to be more robust in the aggressive - * nomination scenario, precisely because these pairs may have the - * use-candidate flag set, and the peer agent may already have - * selected such one. - */ - if (g_slist_find (agent->triggered_check_queue, p) && - p->state != NICE_CHECK_IN_PROGRESS) { - if (p->priority < priority) { - nice_debug ("Agent %p : pair %p removed.", agent, p); - candidate_check_pair_free (agent, p); - stream->conncheck_list = g_slist_delete_link(stream->conncheck_list, i); - } else - triggered_check++; - } - - /* step: cancel all FROZEN and WAITING pairs for the component */ - else if (p->state == NICE_CHECK_FROZEN || p->state == NICE_CHECK_WAITING) { - nice_debug ("Agent %p : pair %p removed.", agent, p); - candidate_check_pair_free (agent, p); - stream->conncheck_list = g_slist_delete_link(stream->conncheck_list, i); - } - - /* note: a SHOULD level req. in ICE 8.1.2. "Updating States" (ID-19) */ - else if (p->state == NICE_CHECK_IN_PROGRESS) { - if (p->priority < priority) { - priv_remove_pair_from_triggered_check_queue (agent, p); - if (p->retransmit) { - p->retransmit = FALSE; - nice_debug ("Agent %p : pair %p will not be retransmitted.", - agent, p); - } - } else { - /* We must keep the higher priority pairs running because if a udp - * packet was lost, we might end up using a bad candidate */ - nice_candidate_pair_priority_to_string (p->priority, prio); - nice_debug ("Agent %p : pair %p kept IN_PROGRESS because priority " - "%s is higher than priority of best nominated pair.", agent, p, prio); - /* We may also have to enable the retransmit flag of pairs with - * a higher priority than the first nominated pair - */ - if (!p->retransmit && p->stun_transactions) { - p->retransmit = TRUE; - nice_debug ("Agent %p : pair %p will be retransmitted.", agent, p); - } - in_progress++; - } - } - i = next; - } - - return in_progress + triggered_check; -} - -/* - * Schedules a triggered check after a successfully inbound - * connectivity check. Implements ICE sect 7.2.1.4 "Triggered Checks" (ID-19). - * - * @param agent self pointer - * @param component the check is related to - * @param local_socket socket from which the inbound check was received - * @param remote_cand remote candidate from which the inbound check was sent - */ -static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *local_socket, NiceCandidate *remote_cand) -{ - GSList *i; - NiceCandidate *local = NULL; - CandidateCheckPair *p; - - g_assert (remote_cand != NULL); - - nice_debug ("Agent %p : scheduling triggered check with socket=%p " - "and remote cand=%p.", agent, local_socket, remote_cand); - - for (i = stream->conncheck_list; i ; i = i->next) { - p = i->data; - if (p->component_id == component->id && - p->remote == remote_cand && - p->sockptr == local_socket) { - /* If we match with a peer-reflexive discovered pair, we - * use the parent succeeded pair instead */ - - if (p->succeeded_pair != NULL) { - g_assert_cmpint (p->state, ==, NICE_CHECK_DISCOVERED); - p = p->succeeded_pair; - } - - nice_debug ("Agent %p : Found a matching pair %p (%s) (%s) ...", - agent, p, p->foundation, priv_state_to_string (p->state)); - - switch (p->state) { - case NICE_CHECK_WAITING: - case NICE_CHECK_FROZEN: - nice_debug ("Agent %p : pair %p added for a triggered check.", - agent, p); - priv_add_pair_to_triggered_check_queue (agent, p); - break; - case NICE_CHECK_IN_PROGRESS: - /* note: according to ICE SPEC sect 7.2.1.4 "Triggered Checks" - * we cancel the in-progress transaction, and after the - * retransmission timeout, we create a new connectivity check - * for that pair. The controlling role of this new check may - * be different from the role of this cancelled check. - * - * When another pair, with a higher priority is already - * nominated, so there's no reason to recheck this pair, - * since it can in no way replace the nominated one. - */ - if (p->priority > component->selected_pair.priority) { - nice_debug ("Agent %p : pair %p added for a triggered check.", - agent, p); - priv_add_pair_to_triggered_check_queue (agent, p); - } - break; - case NICE_CHECK_FAILED: - if (p->priority > component->selected_pair.priority) { - nice_debug ("Agent %p : pair %p added for a triggered check.", - agent, p); - priv_add_pair_to_triggered_check_queue (agent, p); - /* If the component for this pair is in failed state, move it - * back to connecting, and reinitiate the timers - */ - if (component->state == NICE_COMPONENT_STATE_FAILED) { - agent_signal_component_state_change (agent, stream->id, - component->id, NICE_COMPONENT_STATE_CONNECTING); - conn_check_schedule_next (agent); - /* If the component if in ready state, move it back to - * connected as this failed pair with a higher priority - * than the nominated pair requires to pursue the - * conncheck - */ - } else if (component->state == NICE_COMPONENT_STATE_READY) { - agent_signal_component_state_change (agent, stream->id, - component->id, NICE_COMPONENT_STATE_CONNECTED); - conn_check_schedule_next (agent); - } - } - break; - case NICE_CHECK_SUCCEEDED: - nice_debug ("Agent %p : nothing to do for pair %p.", agent, p); - break; - default: - break; - } - - /* note: the spec says the we SHOULD retransmit in-progress - * checks immediately, but we won't do that now */ - - return TRUE; - } - } - - for (i = component->local_candidates; i ; i = i->next) { - local = i->data; - if (local->sockptr == local_socket) - break; - } - - if (i) { - nice_debug ("Agent %p : Adding a triggered check to conn.check list (local=%p).", agent, local); - p = priv_conn_check_add_for_candidate_pair_matched (agent, stream->id, - component, local, remote_cand, NICE_CHECK_WAITING); - if (p) - priv_add_pair_to_triggered_check_queue (agent, p); - return TRUE; - } - else { - nice_debug ("Agent %p : Didn't find a matching pair for triggered check (remote-cand=%p).", agent, remote_cand); - return FALSE; - } -} - - -/* - * Sends a reply to an successfully received STUN connectivity - * check request. Implements parts of the ICE spec section 7.2 (STUN - * Server Procedures). - * - * @param agent context pointer - * @param stream which stream (of the agent) - * @param component which component (of the stream) - * @param rcand remote candidate from which the request came, if NULL, - * the response is sent immediately but no other processing is done - * @param toaddr address to which reply is sent - * @param socket the socket over which the request came - * @param rbuf_len length of STUN message to send - * @param msg the STUN message to send - * @param use_candidate whether the request had USE_CANDIDATE attribute - * - * @pre (rcand == NULL || nice_address_equal(rcand->addr, toaddr) == TRUE) - */ -static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream, - NiceComponent *component, NiceCandidate *lcand, NiceCandidate *rcand, - const NiceAddress *toaddr, NiceSocket *sockptr, size_t rbuf_len, - StunMessage *msg, gboolean use_candidate) -{ - g_assert (rcand == NULL || nice_address_equal(&rcand->addr, toaddr) == TRUE); - - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (toaddr, tmpbuf); - nice_debug ("Agent %p : STUN-CC RESP to '%s:%u', socket=%u, len=%u, cand=%p (c-id:%u), use-cand=%d.", agent, - tmpbuf, - nice_address_get_port (toaddr), - sockptr->fileno ? g_socket_get_fd(sockptr->fileno) : -1, - (unsigned)rbuf_len, - rcand, component->id, - (int)use_candidate); - } - - agent_socket_send (sockptr, toaddr, rbuf_len, (const gchar*)msg->buffer); - if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - ms_ice2_legacy_conncheck_send(msg, sockptr, toaddr); - } - - /* We react to this stun request when we have the remote credentials. - * When credentials are not yet known, this request is stored - * in incoming_checks for later processing when returning from this - * function. - */ - if (rcand && stream->remote_ufrag[0]) { - priv_schedule_triggered_check (agent, stream, component, sockptr, rcand); - if (use_candidate) - priv_mark_pair_nominated (agent, stream, component, lcand, rcand); - } -} - -/* - * Stores information of an incoming STUN connectivity check - * for later use. This is only needed when a check is received - * before we get information about the remote candidates (via - * SDP or other signaling means). - * - * @return non-zero on error, zero on success - */ -static int priv_store_pending_check (NiceAgent *agent, NiceComponent *component, - const NiceAddress *from, NiceSocket *sockptr, uint8_t *username, - uint16_t username_len, uint32_t priority, gboolean use_candidate) -{ - IncomingCheck *icheck; - nice_debug ("Agent %p : Storing pending check.", agent); - - if (g_queue_get_length (&component->incoming_checks) >= - NICE_AGENT_MAX_REMOTE_CANDIDATES) { - nice_debug ("Agent %p : WARN: unable to store information for early incoming check.", agent); - return -1; - } - - icheck = g_slice_new0 (IncomingCheck); - g_queue_push_tail (&component->incoming_checks, icheck); - icheck->from = *from; - icheck->local_socket = sockptr; - icheck->priority = priority; - icheck->use_candidate = use_candidate; - icheck->username_len = username_len; - icheck->username = NULL; - if (username_len > 0) - icheck->username = g_memdup (username, username_len); - - return 0; -} - -/* - * Adds a new pair, discovered from an incoming STUN response, to - * the connectivity check list. - * - * @return created pair, or NULL on fatal (memory allocation) errors - */ -static CandidateCheckPair *priv_add_peer_reflexive_pair (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local_cand, CandidateCheckPair *parent_pair) -{ - CandidateCheckPair *pair = g_slice_new0 (CandidateCheckPair); - NiceStream *stream = agent_find_stream (agent, stream_id); - - pair->stream_id = stream_id; - pair->component_id = component->id;; - pair->local = local_cand; - pair->remote = parent_pair->remote; - pair->sockptr = local_cand->sockptr; - parent_pair->discovered_pair = pair; - pair->succeeded_pair = parent_pair; - nice_debug ("Agent %p : creating a new pair", agent); - SET_PAIR_STATE (agent, pair, NICE_CHECK_DISCOVERED); - { - gchar tmpbuf1[INET6_ADDRSTRLEN]; - gchar tmpbuf2[INET6_ADDRSTRLEN]; - nice_address_to_string (&pair->local->addr, tmpbuf1); - nice_address_to_string (&pair->remote->addr, tmpbuf2); - nice_debug ("Agent %p : new pair %p : [%s]:%u --> [%s]:%u", agent, pair, - tmpbuf1, nice_address_get_port (&pair->local->addr), - tmpbuf2, nice_address_get_port (&pair->remote->addr)); - } - g_snprintf (pair->foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s", - local_cand->foundation, parent_pair->remote->foundation); - - if (agent->controlling_mode == TRUE) - pair->priority = nice_candidate_pair_priority (pair->local->priority, - pair->remote->priority); - else - pair->priority = nice_candidate_pair_priority (pair->remote->priority, - pair->local->priority); - pair->nominated = parent_pair->nominated; - /* the peer-reflexive priority used in stun request is copied from - * the parent succeeded pair. This value is not required for discovered - * pair, that won't emit stun requests themselves, but may be used when - * such pair becomes the selected pair, and when keepalive stun are emitted, - * using the sockptr and stun_priority values from the succeeded pair. - */ - pair->stun_priority = parent_pair->stun_priority; - nice_debug ("Agent %p : added a new peer-discovered pair %p with " - "foundation '%s' and transport %s:%s to stream %u component %u", - agent, pair, pair->foundation, - priv_candidate_transport_to_string (pair->local->transport), - priv_candidate_transport_to_string (pair->remote->transport), - stream_id, component->id); - - stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair, - (GCompareFunc)conn_check_compare); - - return pair; -} - -/* - * Recalculates priorities of all candidate pairs. This - * is required after a conflict in ICE roles. - */ -void recalculate_pair_priorities (NiceAgent *agent) -{ - GSList *i, *j; - - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - for (j = stream->conncheck_list; j; j = j->next) { - CandidateCheckPair *p = j->data; - p->priority = agent_candidate_pair_priority (agent, p->local, p->remote); - } - stream->conncheck_list = g_slist_sort (stream->conncheck_list, - (GCompareFunc)conn_check_compare); - } -} - -/* - * Change the agent role if different from 'control'. Can be - * initiated both by handling of incoming connectivity checks, - * and by processing the responses to checks sent by us. - */ -static void priv_check_for_role_conflict (NiceAgent *agent, gboolean control) -{ - /* role conflict, change mode; wait for a new conn. check */ - if (control != agent->controlling_mode) { - nice_debug ("Agent %p : Role conflict, changing agent role to \"%s\".", - agent, control ? "controlling" : "controlled"); - agent->controlling_mode = control; - /* the pair priorities depend on the roles, so recalculation - * is needed */ - recalculate_pair_priorities (agent); - } - else - nice_debug ("Agent %p : Role conflict, staying with role \"%s\".", - agent, control ? "controlling" : "controlled"); -} - -/* - * Checks whether the mapped address in connectivity check response - * matches any of the known local candidates. If not, apply the - * mechanism for "Discovering Peer Reflexive Candidates" ICE ID-19) - * - * @param agent context pointer - * @param stream which stream (of the agent) - * @param component which component (of the stream) - * @param p the connectivity check pair for which we got a response - * @param socketptr socket used to send the reply - * @param mapped_sockaddr mapped address in the response - * - * @return pointer to a candidate pair, found in conncheck list or newly created - */ -static CandidateCheckPair *priv_process_response_check_for_reflexive(NiceAgent *agent, NiceStream *stream, NiceComponent *component, CandidateCheckPair *p, NiceSocket *sockptr, struct sockaddr *mapped_sockaddr, NiceCandidate *local_candidate, NiceCandidate *remote_candidate) -{ - CandidateCheckPair *new_pair = NULL; - NiceAddress mapped; - GSList *i; - NiceCandidate *local_cand = NULL; - - nice_address_set_from_sockaddr (&mapped, mapped_sockaddr); - - for (i = component->local_candidates; i; i = i->next) { - NiceCandidate *cand = i->data; - - if (nice_address_equal (&mapped, &cand->addr) && - local_candidate_and_socket_compatible (agent, cand, sockptr)) { - local_cand = cand; - break; - } - } - - /* The mapped address allows to look for a previously discovered - * peer reflexive local candidate, and its related pair. This - * new_pair will be marked 'Valid', while the pair 'p' of the - * initial stun request will be marked 'Succeeded' - * - * In the case of a tcp-act/tcp-pass pair 'p', where the local - * candidate is of type tcp-act, and its port number is zero, a - * conncheck on this pair *always* leads to the creation of a - * discovered peer-reflexive tcp-act local candidate. - */ - for (i = stream->conncheck_list; i; i = i->next) { - CandidateCheckPair *pair = i->data; - if (local_cand == pair->local && remote_candidate == pair->remote) { - new_pair = pair; - break; - } - } - - if (new_pair) { - /* note: when new_pair is distinct from p, it means new_pair is a - * previously discovered peer-reflexive candidate pair, so we don't - * set the valid flag on p in this case, because the valid flag is - * already set on the discovered pair. - */ - if (new_pair == p) - p->valid = TRUE; - SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED); - priv_remove_pair_from_triggered_check_queue (agent, p); - priv_free_all_stun_transactions (p, component); - nice_component_add_valid_candidate (agent, component, remote_candidate); - } - else { - if (local_cand == NULL && !agent->force_relay) { - /* step: find a new local candidate, see RFC 5245 7.1.3.2.1. - * "Discovering Peer Reflexive Candidates" - * - * The priority equal to the value of the PRIORITY attribute - * in the Binding request is taken from the "parent" pair p - */ - local_cand = discovery_add_peer_reflexive_candidate (agent, - stream->id, - component->id, - p->stun_priority, - &mapped, - sockptr, - local_candidate, - remote_candidate); - nice_debug ("Agent %p : added a new peer-reflexive local candidate %p " - "with transport %s", agent, local_cand, - priv_candidate_transport_to_string (local_cand->transport)); - } - - /* step: add a new discovered pair (see RFC 5245 7.1.3.2.2 - "Constructing a Valid Pair") */ - if (local_cand) - new_pair = priv_add_peer_reflexive_pair (agent, stream->id, component, - local_cand, p); - /* note: this is same as "adding to VALID LIST" in the spec - text */ - if (new_pair) - new_pair->valid = TRUE; - /* step: The agent sets the state of the pair that *generated* the check to - * Succeeded, RFC 5245, 7.1.3.2.3, "Updating Pair States" - */ - SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED); - priv_remove_pair_from_triggered_check_queue (agent, p); - priv_free_all_stun_transactions (p, component); - } - - if (new_pair && new_pair->valid) - nice_component_add_valid_candidate (agent, component, remote_candidate); - - - return new_pair; -} - -/* - * Tries to match STUN reply in 'buf' to an existing STUN connectivity - * check transaction. If found, the reply is processed. Implements - * section 7.1.2 "Processing the Response" of ICE spec (ID-19). - * - * @return TRUE if a matching transaction is found - */ -static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *sockptr, const NiceAddress *from, NiceCandidate *local_candidate, NiceCandidate *remote_candidate, StunMessage *resp) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sockaddr; - socklen_t socklen = sizeof (sockaddr); - GSList *i, *j; - guint k; - StunUsageIceReturn res; - StunTransactionId discovery_id; - StunTransactionId response_id; - stun_message_id (resp, response_id); - - for (i = stream->conncheck_list; i; i = i->next) { - CandidateCheckPair *p = i->data; - - for (j = p->stun_transactions, k = 0; j; j = j->next, k++) { - StunTransaction *stun = j->data; - - stun_message_id (&stun->message, discovery_id); - - if (memcmp (discovery_id, response_id, sizeof(StunTransactionId))) - continue; - - res = stun_usage_ice_conncheck_process (resp, - &sockaddr.storage, &socklen, - agent_to_ice_compatibility (agent)); - nice_debug ("Agent %p : stun_bind_process/conncheck for %p: " - "%s,res=%s,stun#=%d.", - agent, p, - agent->controlling_mode ? "controlling" : "controlled", - priv_ice_return_to_string (res), k); - - if (res == STUN_USAGE_ICE_RETURN_SUCCESS || - res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) { - /* case: found a matching connectivity check request */ - - CandidateCheckPair *ok_pair = NULL; - - nice_debug ("Agent %p : pair %p MATCHED.", agent, p); - priv_remove_stun_transaction (p, stun, component); - - /* step: verify that response came from the same IP address we - * sent the original request to (see 7.1.2.1. "Failure - * Cases") */ - if (nice_address_equal (from, &p->remote->addr) == FALSE) { - candidate_check_pair_fail (stream, agent, p); - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - gchar tmpbuf2[INET6_ADDRSTRLEN]; - nice_debug ("Agent %p : pair %p FAILED" - " (mismatch of source address).", agent, p); - nice_address_to_string (&p->remote->addr, tmpbuf); - nice_address_to_string (from, tmpbuf2); - nice_debug ("Agent %p : '%s:%u' != '%s:%u'", agent, - tmpbuf, nice_address_get_port (&p->remote->addr), - tmpbuf2, nice_address_get_port (from)); - } - return TRUE; - } - - if (remote_candidate == NULL) { - candidate_check_pair_fail (stream, agent, p); - if (nice_debug_is_enabled ()) { - nice_debug ("Agent %p : pair %p FAILED " - "(got a matching pair without a known remote candidate).", agent, p); - } - return TRUE; - } - - /* note: CONNECTED but not yet READY, see docs */ - - /* step: handle the possible case of a peer-reflexive - * candidate where the mapped-address in response does - * not match any local candidate, see 7.1.2.2.1 - * "Discovering Peer Reflexive Candidates" ICE ID-19) */ - - if (res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) { - nice_debug ("Agent %p : Mapped address not found", agent); - SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED); - p->valid = TRUE; - nice_component_add_valid_candidate (agent, component, p->remote); - } else - ok_pair = priv_process_response_check_for_reflexive (agent, - stream, component, p, sockptr, &sockaddr.addr, - local_candidate, remote_candidate); - - /* note: The success of this check might also - * cause the state of other checks to change as well - * See sect 7.2.5.3.3 (Updating Candidate Pair States) of - * ICE spec (RFC8445). - */ - conn_check_unfreeze_related (agent, p); - - /* Note: this assignment helps to reduce the numbers of cases - * to be tested. If ok_pair and p refer to distinct pairs, it - * means that ok_pair is a discovered peer reflexive one, - * caused by the check made on pair p. In that case, the - * flags to be tested are on p, but the nominated flag will be - * set on ok_pair. When there's no discovered pair, p and - * ok_pair refer to the same pair. - * To summarize : p is a SUCCEEDED pair, ok_pair is a - * DISCOVERED, VALID, and eventually NOMINATED pair. - */ - if (!ok_pair) - ok_pair = p; - - /* step: updating nominated flag (ICE 7.1.2.2.4 "Updating the - Nominated Flag" (ID-19) */ - if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) { - nice_debug ("Agent %p : Updating nominated flag (%s): " - "ok_pair=%p (%d/%d) p=%p (%d/%d) (ucnc/mnora)", - agent, p->local->transport == NICE_CANDIDATE_TRANSPORT_UDP ? - "UDP" : "TCP", - ok_pair, ok_pair->use_candidate_on_next_check, - ok_pair->mark_nominated_on_response_arrival, - p, p->use_candidate_on_next_check, - p->mark_nominated_on_response_arrival); - - if (agent->controlling_mode) { - switch (agent->nomination_mode) { - case NICE_NOMINATION_MODE_REGULAR: - if (p->use_candidate_on_next_check) { - nice_debug ("Agent %p : marking pair %p (%s) as nominated " - "(regular nomination, controlling, " - "use_cand_on_next_check=1).", - agent, ok_pair, ok_pair->foundation); - ok_pair->nominated = TRUE; - } - break; - case NICE_NOMINATION_MODE_AGGRESSIVE: - if (!p->nominated) { - nice_debug ("Agent %p : marking pair %p (%s) as nominated " - "(aggressive nomination, controlling).", - agent, ok_pair, ok_pair->foundation); - ok_pair->nominated = TRUE; - } - break; - default: - /* Nothing to do */ - break; - } - } else { - if (p->mark_nominated_on_response_arrival) { - nice_debug ("Agent %p : marking pair %p (%s) as nominated " - "(%s nomination, controlled, mark_on_response=1).", - agent, ok_pair, ok_pair->foundation, - agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE ? - "aggressive" : "regular"); - ok_pair->nominated = TRUE; - } - } - } - - if (ok_pair->nominated == TRUE) { - conn_check_update_selected_pair (agent, component, ok_pair); - priv_print_conn_check_lists (agent, G_STRFUNC, - ", got a nominated pair"); - - /* Do not step down to CONNECTED if we're already at state READY*/ - if (component->state != NICE_COMPONENT_STATE_READY) - /* step: notify the client of a new component state (must be done - * before the possible check list state update step */ - agent_signal_component_state_change (agent, - stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED); - } - - /* step: update pair states (ICE 7.1.2.2.3 "Updating pair - states" and 8.1.2 "Updating States", ID-19) */ - conn_check_update_check_list_state_for_ready (agent, stream, component); - } else if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) { - uint64_t tie; - gboolean controlled_mode; - - if (!p->retransmit) { - nice_debug ("Agent %p : Role conflict with pair %p, not restarting", - agent, p); - return TRUE; - } - - /* case: role conflict error, need to restart with new role */ - nice_debug ("Agent %p : Role conflict with pair %p, restarting", - agent, p); - - /* note: this res value indicates that the role of the peer - * agent has not changed after the tie-breaker comparison, so - * this is our role that must change. see ICE sect. 7.1.3.1 - * "Failure Cases". Our role might already have changed due to - * an earlier incoming request, but if not, change role now. - * - * Sect. 7.1.3.1 is not clear on this point, but we choose to - * put the candidate pair in the triggered check list even - * when the agent did not switch its role. The reason for this - * interpretation is that the reception of the stun reply, even - * an error reply, is a good sign that this pair will be - * valid, if we retry the check after the role of both peers - * has been fixed. - */ - controlled_mode = (stun_message_find64 (&stun->message, - STUN_ATTRIBUTE_ICE_CONTROLLED, &tie) == - STUN_MESSAGE_RETURN_SUCCESS); - - priv_check_for_role_conflict (agent, controlled_mode); - priv_remove_stun_transaction (p, stun, component); - priv_add_pair_to_triggered_check_queue (agent, p); - } else { - /* case: STUN error, the check STUN context was freed */ - candidate_check_pair_fail (stream, agent, p); - } - return TRUE; - } - } - - return FALSE; -} - -/* - * Tries to match STUN reply in 'buf' to an existing STUN discovery - * transaction. If found, a reply is sent. - * - * @return TRUE if a matching transaction is found - */ -static gboolean priv_map_reply_to_discovery_request (NiceAgent *agent, StunMessage *resp) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sockaddr; - socklen_t socklen = sizeof (sockaddr); - - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } alternate; - socklen_t alternatelen = sizeof (sockaddr); - - GSList *i; - StunUsageBindReturn res; - gboolean trans_found = FALSE; - StunTransactionId discovery_id; - StunTransactionId response_id; - stun_message_id (resp, response_id); - - for (i = agent->discovery_list; i && trans_found != TRUE; i = i->next) { - CandidateDiscovery *d = i->data; - - if (d->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE && - d->stun_message.buffer) { - stun_message_id (&d->stun_message, discovery_id); - - if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)) == 0) { - res = stun_usage_bind_process (resp, &sockaddr.addr, - &socklen, &alternate.addr, &alternatelen); - nice_debug ("Agent %p : stun_bind_process/disc for %p res %d.", - agent, d, (int)res); - - if (res == STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER) { - /* handle alternate server */ - NiceAddress niceaddr; - nice_address_set_from_sockaddr (&niceaddr, &alternate.addr); - d->server = niceaddr; - - d->pending = FALSE; - agent->discovery_unsched_items++; - } else if (res == STUN_USAGE_BIND_RETURN_SUCCESS) { - /* case: successful binding discovery, create a new local candidate */ - - if (!agent->force_relay) { - NiceAddress niceaddr; - - nice_address_set_from_sockaddr (&niceaddr, &sockaddr.addr); - discovery_add_server_reflexive_candidate ( - agent, - d->stream_id, - d->component_id, - &niceaddr, - NICE_CANDIDATE_TRANSPORT_UDP, - d->nicesock, - FALSE); - if (agent->use_ice_tcp) - discovery_discover_tcp_server_reflexive_candidates ( - agent, - d->stream_id, - d->component_id, - &niceaddr, - d->nicesock); - } - d->stun_message.buffer = NULL; - d->stun_message.buffer_len = 0; - d->done = TRUE; - trans_found = TRUE; - } else if (res == STUN_USAGE_BIND_RETURN_ERROR) { - /* case: STUN error, the check STUN context was freed */ - d->stun_message.buffer = NULL; - d->stun_message.buffer_len = 0; - d->done = TRUE; - trans_found = TRUE; - } - } - } - } - - return trans_found; -} - -static guint -priv_calc_turn_timeout (guint lifetime) -{ - if (lifetime > 120) - return lifetime - 60; - else - return lifetime / 2; -} - -static void -priv_add_new_turn_refresh (NiceAgent *agent, CandidateDiscovery *cdisco, - NiceCandidate *relay_cand, guint lifetime) -{ - CandidateRefresh *cand; - - if (cdisco->turn->type == NICE_RELAY_TYPE_TURN_TLS && - (agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2)) - return; - - cand = g_slice_new0 (CandidateRefresh); - agent->refresh_list = g_slist_append (agent->refresh_list, cand); - - cand->candidate = relay_cand; - cand->nicesock = cdisco->nicesock; - cand->server = cdisco->server; - cand->stream_id = cdisco->stream_id; - cand->component_id = cdisco->component_id; - memcpy (&cand->stun_agent, &cdisco->stun_agent, sizeof(StunAgent)); - - /* Use previous stun response for authentication credentials */ - if (cdisco->stun_resp_msg.buffer != NULL) { - memcpy(cand->stun_resp_buffer, cdisco->stun_resp_buffer, - sizeof(cand->stun_resp_buffer)); - memcpy(&cand->stun_resp_msg, &cdisco->stun_resp_msg, sizeof(StunMessage)); - cand->stun_resp_msg.buffer = cand->stun_resp_buffer; - cand->stun_resp_msg.agent = &cand->stun_agent; - cand->stun_resp_msg.key = NULL; - } - - nice_debug ("Agent %p : Adding new refresh candidate %p with timeout %d", - agent, cand, priv_calc_turn_timeout (lifetime)); - /* step: also start the refresh timer */ - /* refresh should be sent 1 minute before it expires */ - agent_timeout_add_seconds_with_context (agent, &cand->timer_source, - "Candidate TURN refresh", - priv_calc_turn_timeout (lifetime), - priv_turn_allocate_refresh_tick_agent_locked, cand); - - nice_debug ("timer source is : %p", cand->timer_source); - - return; -} - -static void priv_handle_turn_alternate_server (NiceAgent *agent, - CandidateDiscovery *disco, NiceAddress server, NiceAddress alternate) -{ - /* We need to cancel and reset all candidate discovery turn for the same - stream and type if there is an alternate server. Otherwise, we might end up - with two relay components on different servers, creating candidates with - unique foundations that only contain one component. - */ - GSList *i; - - for (i = agent->discovery_list; i; i = i->next) { - CandidateDiscovery *d = i->data; - - if (!d->done && - d->type == disco->type && - d->stream_id == disco->stream_id && - d->turn->type == disco->turn->type && - nice_address_equal (&d->server, &server)) { - gchar ip[INET6_ADDRSTRLEN]; - // Cancel the pending request to avoid a race condition with another - // component responding with another altenrate-server - d->stun_message.buffer = NULL; - d->stun_message.buffer_len = 0; - - nice_address_to_string (&server, ip); - nice_debug ("Agent %p : Cancelling and setting alternate server %s for " - "CandidateDiscovery %p on s%d/c%d", agent, ip, d, - d->stream_id, d->component_id); - d->server = alternate; - d->turn->server = alternate; - d->pending = FALSE; - agent->discovery_unsched_items++; - - if (d->turn->type == NICE_RELAY_TYPE_TURN_TCP || - d->turn->type == NICE_RELAY_TYPE_TURN_TLS) { - NiceStream *stream; - NiceComponent *component; - - if (!agent_find_component (agent, d->stream_id, d->component_id, - &stream, &component)) { - nice_debug ("Could not find stream or component in " - "priv_handle_turn_alternate_server"); - continue; - } - d->nicesock = agent_create_tcp_turn_socket (agent, stream, component, - d->nicesock, &d->server, d->turn->type, - nice_socket_is_reliable (d->nicesock)); - - nice_component_attach_socket (component, d->nicesock); - } - } - } -} - -/* - * Tries to match STUN reply in 'buf' to an existing STUN discovery - * transaction. If found, a reply is sent. - * - * @return TRUE if a matching transaction is found - */ -static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *resp) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sockaddr; - socklen_t socklen = sizeof (sockaddr); - - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } alternate; - socklen_t alternatelen = sizeof (alternate); - - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } relayaddr; - socklen_t relayaddrlen = sizeof (relayaddr); - - uint32_t lifetime; - uint32_t bandwidth; - GSList *i; - StunUsageTurnReturn res; - gboolean trans_found = FALSE; - StunTransactionId discovery_id; - StunTransactionId response_id; - stun_message_id (resp, response_id); - - for (i = agent->discovery_list; i && trans_found != TRUE; i = i->next) { - CandidateDiscovery *d = i->data; - - if (d->type == NICE_CANDIDATE_TYPE_RELAYED && - d->stun_message.buffer) { - stun_message_id (&d->stun_message, discovery_id); - - if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)) == 0) { - res = stun_usage_turn_process (resp, - &relayaddr.storage, &relayaddrlen, - &sockaddr.storage, &socklen, - &alternate.storage, &alternatelen, - &bandwidth, &lifetime, agent_to_turn_compatibility (agent)); - nice_debug ("Agent %p : stun_turn_process/disc for %p res %d.", - agent, d, (int)res); - - if (res == STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER) { - NiceAddress addr; - - /* handle alternate server */ - nice_address_set_from_sockaddr (&addr, &alternate.addr); - priv_handle_turn_alternate_server (agent, d, d->server, addr); - trans_found = TRUE; - } else if (res == STUN_USAGE_TURN_RETURN_RELAY_SUCCESS || - res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) { - /* case: successful allocate, create a new local candidate */ - NiceAddress niceaddr; - NiceCandidate *relay_cand; - - nice_address_set_from_sockaddr (&niceaddr, &relayaddr.addr); - - if (res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) { - NiceAddress mappedniceaddr; - - /* We also received our mapped address */ - nice_address_set_from_sockaddr (&mappedniceaddr, &sockaddr.addr); - - /* TCP or TLS TURNS means the server-reflexive address was - * on a TCP connection, which cannot be used for server-reflexive - * discovery of candidates. - */ - if (d->turn->type == NICE_RELAY_TYPE_TURN_UDP && - !agent->force_relay) { - discovery_add_server_reflexive_candidate ( - agent, - d->stream_id, - d->component_id, - &mappedniceaddr, - NICE_CANDIDATE_TRANSPORT_UDP, - d->nicesock, - FALSE); - } - if (agent->use_ice_tcp) { - if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2) && - !nice_address_equal_no_port (&niceaddr, &d->turn->server)) { - nice_debug("TURN port got allocated on an alternate server, " - "ignoring bogus srflx address"); - } else { - discovery_discover_tcp_server_reflexive_candidates ( - agent, - d->stream_id, - d->component_id, - &mappedniceaddr, - d->nicesock); - } - } - } - - if (nice_socket_is_reliable (d->nicesock)) { - relay_cand = discovery_add_relay_candidate ( - agent, - d->stream_id, - d->component_id, - &niceaddr, - NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE, - d->nicesock, - d->turn); - - if (relay_cand) { - if (agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - nice_udp_turn_socket_set_ms_realm(relay_cand->sockptr, - &d->stun_message); - nice_udp_turn_socket_set_ms_connection_id(relay_cand->sockptr, - resp); - } - priv_add_new_turn_refresh (agent, d, relay_cand, lifetime); - } - - relay_cand = discovery_add_relay_candidate ( - agent, - d->stream_id, - d->component_id, - &niceaddr, - NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE, - d->nicesock, - d->turn); - } else { - relay_cand = discovery_add_relay_candidate ( - agent, - d->stream_id, - d->component_id, - &niceaddr, - NICE_CANDIDATE_TRANSPORT_UDP, - d->nicesock, - d->turn); - } - - if (relay_cand) { - if (d->stun_resp_msg.buffer) - nice_udp_turn_socket_cache_realm_nonce (relay_cand->sockptr, - &d->stun_resp_msg); - if (agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - /* These data are needed on TURN socket when sending requests, - * but never reach nice_turn_socket_parse_recv() where it could - * be read directly, as the socket does not exist when allocate - * response arrives to _nice_agent_recv(). We must set them right - * after socket gets created in discovery_add_relay_candidate(), - * so we are doing it here. */ - nice_udp_turn_socket_set_ms_realm(relay_cand->sockptr, - &d->stun_message); - nice_udp_turn_socket_set_ms_connection_id(relay_cand->sockptr, - resp); - } - priv_add_new_turn_refresh (agent, d, relay_cand, lifetime); - - /* In case a new candidate has been added */ - conn_check_schedule_next (agent); - } - - d->stun_message.buffer = NULL; - d->stun_message.buffer_len = 0; - d->done = TRUE; - trans_found = TRUE; - } else if (res == STUN_USAGE_TURN_RETURN_ERROR) { - int code = -1; - uint8_t *sent_realm = NULL; - uint8_t *recv_realm = NULL; - uint16_t sent_realm_len = 0; - uint16_t recv_realm_len = 0; - - sent_realm = (uint8_t *) stun_message_find (&d->stun_message, - STUN_ATTRIBUTE_REALM, &sent_realm_len); - recv_realm = (uint8_t *) stun_message_find (resp, - STUN_ATTRIBUTE_REALM, &recv_realm_len); - - if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2) && - alternatelen != sizeof(alternate)) { - NiceAddress addr; - - nice_address_set_from_sockaddr (&addr, &alternate.addr); - - if (!nice_address_equal (&addr, &d->server)) { - priv_handle_turn_alternate_server (agent, d, d->server, addr); - } - } - /* check for unauthorized error response */ - if ((agent->compatibility == NICE_COMPATIBILITY_RFC5245 || - agent->compatibility == NICE_COMPATIBILITY_OC2007 || - agent->compatibility == NICE_COMPATIBILITY_OC2007R2) && - stun_message_get_class (resp) == STUN_ERROR && - stun_message_find_error (resp, &code) == - STUN_MESSAGE_RETURN_SUCCESS && - recv_realm != NULL && recv_realm_len > 0) { - - if (code == STUN_ERROR_STALE_NONCE || - (code == STUN_ERROR_UNAUTHORIZED && - !(recv_realm_len == sent_realm_len && - sent_realm != NULL && - memcmp (sent_realm, recv_realm, sent_realm_len) == 0))) { - d->stun_resp_msg = *resp; - memcpy (d->stun_resp_buffer, resp->buffer, - stun_message_length (resp)); - d->stun_resp_msg.buffer = d->stun_resp_buffer; - d->stun_resp_msg.buffer_len = sizeof(d->stun_resp_buffer); - d->pending = FALSE; - agent->discovery_unsched_items++; - } else { - /* case: a real unauthorized error */ - d->stun_message.buffer = NULL; - d->stun_message.buffer_len = 0; - d->done = TRUE; - } - } else if (d->pending) { - /* case: STUN error, the check STUN context was freed */ - d->stun_message.buffer = NULL; - d->stun_message.buffer_len = 0; - d->done = TRUE; - } - trans_found = TRUE; - } - } - } - } - - return trans_found; -} - - -/* - * Tries to match STUN reply in 'buf' to an existing STUN discovery - * transaction. If found, a reply is sent. - * - * @return TRUE if a matching transaction is found - */ -static gboolean priv_map_reply_to_relay_refresh (NiceAgent *agent, StunMessage *resp) -{ - uint32_t lifetime; - GSList *i; - StunUsageTurnReturn res; - gboolean trans_found = FALSE; - StunTransactionId refresh_id; - StunTransactionId response_id; - stun_message_id (resp, response_id); - - for (i = agent->refresh_list; i && trans_found != TRUE;) { - CandidateRefresh *cand = i->data; - GSList *next = i->next; - - if (!cand->disposing && cand->stun_message.buffer) { - stun_message_id (&cand->stun_message, refresh_id); - - if (memcmp (refresh_id, response_id, sizeof(StunTransactionId)) == 0) { - res = stun_usage_turn_refresh_process (resp, - &lifetime, agent_to_turn_compatibility (agent)); - nice_debug ("Agent %p : stun_turn_refresh_process for %p res %d with lifetime %u.", - agent, cand, (int)res, lifetime); - if (res == STUN_USAGE_TURN_RETURN_RELAY_SUCCESS) { - /* refresh should be sent 1 minute before it expires */ - agent_timeout_add_seconds_with_context (agent, - &cand->timer_source, - "Candidate TURN refresh", priv_calc_turn_timeout (lifetime), - priv_turn_allocate_refresh_tick_agent_locked, cand); - - g_source_destroy (cand->tick_source); - g_source_unref (cand->tick_source); - cand->tick_source = NULL; - trans_found = TRUE; - } else if (res == STUN_USAGE_TURN_RETURN_ERROR) { - int code = -1; - uint8_t *sent_realm = NULL; - uint8_t *recv_realm = NULL; - uint16_t sent_realm_len = 0; - uint16_t recv_realm_len = 0; - - sent_realm = (uint8_t *) stun_message_find (&cand->stun_message, - STUN_ATTRIBUTE_REALM, &sent_realm_len); - recv_realm = (uint8_t *) stun_message_find (resp, - STUN_ATTRIBUTE_REALM, &recv_realm_len); - - /* check for unauthorized error response */ - if (agent->compatibility == NICE_COMPATIBILITY_RFC5245 && - stun_message_get_class (resp) == STUN_ERROR && - stun_message_find_error (resp, &code) == - STUN_MESSAGE_RETURN_SUCCESS && - recv_realm != NULL && recv_realm_len > 0) { - - if (code == STUN_ERROR_STALE_NONCE || - (code == STUN_ERROR_UNAUTHORIZED && - !(recv_realm_len == sent_realm_len && - sent_realm != NULL && - memcmp (sent_realm, recv_realm, sent_realm_len) == 0))) { - cand->stun_resp_msg = *resp; - memcpy (cand->stun_resp_buffer, resp->buffer, - stun_message_length (resp)); - cand->stun_resp_msg.buffer = cand->stun_resp_buffer; - cand->stun_resp_msg.buffer_len = sizeof(cand->stun_resp_buffer); - priv_turn_allocate_refresh_tick_unlocked (agent, cand); - } else { - /* case: a real unauthorized error */ - refresh_free (agent, cand); - } - } else { - /* case: STUN error, the check STUN context was freed */ - refresh_free (agent, cand); - } - trans_found = TRUE; - } - } - } - i = next; - } - - return trans_found; -} - -static gboolean priv_map_reply_to_relay_remove (NiceAgent *agent, - StunMessage *resp) -{ - StunTransactionId response_id; - GSList *i; - - stun_message_id (resp, response_id); - - for (i = agent->refresh_list; i; i = i->next) { - CandidateRefresh *cand = i->data; - StunTransactionId request_id; - StunUsageTurnReturn res; - uint32_t lifetime; - - if (!cand->disposing || !cand->stun_message.buffer) { - continue; - } - - stun_message_id (&cand->stun_message, request_id); - - if (memcmp (request_id, response_id, sizeof(StunTransactionId)) == 0) { - res = stun_usage_turn_refresh_process (resp, &lifetime, - agent_to_turn_compatibility (agent)); - - nice_debug ("Agent %p : priv_map_reply_to_relay_remove for %p res %d " - "with lifetime %u.", agent, cand, res, lifetime); - - if (res != STUN_USAGE_TURN_RETURN_INVALID) { - refresh_free (agent, cand); - return TRUE; - } - } - } - - return FALSE; -} - -static gboolean priv_map_reply_to_keepalive_conncheck (NiceAgent *agent, - NiceComponent *component, StunMessage *resp) -{ - StunTransactionId conncheck_id; - StunTransactionId response_id; - stun_message_id (resp, response_id); - - if (component->selected_pair.keepalive.stun_message.buffer) { - stun_message_id (&component->selected_pair.keepalive.stun_message, - conncheck_id); - if (memcmp (conncheck_id, response_id, sizeof(StunTransactionId)) == 0) { - nice_debug ("Agent %p : Keepalive for selected pair received.", - agent); - if (component->selected_pair.keepalive.tick_source) { - g_source_destroy (component->selected_pair.keepalive.tick_source); - g_source_unref (component->selected_pair.keepalive.tick_source); - component->selected_pair.keepalive.tick_source = NULL; - } - component->selected_pair.keepalive.stun_message.buffer = NULL; - return TRUE; - } - } - - return FALSE; -} - - -typedef struct { - NiceAgent *agent; - NiceStream *stream; - NiceComponent *component; - uint8_t *password; -} conncheck_validater_data; - -static bool conncheck_stun_validater (StunAgent *agent, - StunMessage *message, uint8_t *username, uint16_t username_len, - uint8_t **password, size_t *password_len, void *user_data) -{ - conncheck_validater_data *data = (conncheck_validater_data*) user_data; - GSList *i; - gchar *ufrag = NULL; - gsize ufrag_len; - - gboolean msn_msoc_nice_compatibility = - data->agent->compatibility == NICE_COMPATIBILITY_MSN || - data->agent->compatibility == NICE_COMPATIBILITY_OC2007; - - if (data->agent->compatibility == NICE_COMPATIBILITY_OC2007 && - stun_message_get_class (message) == STUN_RESPONSE) - i = data->component->remote_candidates; - else - i = data->component->local_candidates; - - for (; i; i = i->next) { - NiceCandidate *cand = i->data; - - ufrag = NULL; - if (cand->username) - ufrag = cand->username; - else - ufrag = data->stream->local_ufrag; - ufrag_len = ufrag? strlen (ufrag) : 0; - - if (ufrag && msn_msoc_nice_compatibility) - ufrag = (gchar *)g_base64_decode (ufrag, &ufrag_len); - - if (ufrag == NULL) - continue; - - stun_debug ("Comparing username/ufrag of len %d and %" G_GSIZE_FORMAT ", equal=%d", - username_len, ufrag_len, username_len >= ufrag_len ? - memcmp (username, ufrag, ufrag_len) : 0); - stun_debug_bytes (" username: ", username, username_len); - stun_debug_bytes (" ufrag: ", ufrag, ufrag_len); - if (ufrag_len > 0 && username_len >= ufrag_len && - memcmp (username, ufrag, ufrag_len) == 0) { - gchar *pass = NULL; - - if (cand->password) - pass = cand->password; - else if (data->stream && data->stream->local_password[0]) - pass = data->stream->local_password; - - if (pass) { - *password = (uint8_t *) pass; - *password_len = strlen (pass); - - if (msn_msoc_nice_compatibility) { - gsize pass_len; - - data->password = g_base64_decode (pass, &pass_len); - *password = data->password; - *password_len = pass_len; - } - } - - if (msn_msoc_nice_compatibility) - g_free (ufrag); - - stun_debug ("Found valid username, returning password: '%s'", *password); - return TRUE; - } - - if (msn_msoc_nice_compatibility) - g_free (ufrag); - } - - return FALSE; -} - -/* - * handle RENOMINATION stun attribute - * @return TRUE if nomination changed. FALSE otherwise - */ -static gboolean conn_check_handle_renomination (NiceAgent *agent, NiceStream *stream, - NiceComponent *component, StunMessage *req, - NiceCandidate *remote_candidate, NiceCandidate *local_candidate) -{ - GSList *lst; - if (!agent->controlling_mode && NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) && - agent->support_renomination && remote_candidate && local_candidate) - { - uint32_t nom_value = 0; - uint16_t nom_len = 0; - const void *value = stun_message_find (req, STUN_ATTRIBUTE_NOMINATION, &nom_len); - if (nom_len == 0) { - return FALSE; - } - if (nom_len == 4) { - memcpy (&nom_value, value, 4); - nom_value = ntohl (nom_value); - } else { - nice_debug ("Agent %p : received NOMINATION attr with incorrect octet length %u, expected 4 bytes", - agent, nom_len); - return FALSE; - } - - if (nice_debug_is_enabled ()) { - gchar remote_str[INET6_ADDRSTRLEN]; - nice_address_to_string(&remote_candidate->addr, remote_str); - nice_debug ("Agent %p : received NOMINATION attr for remote candidate [%s]:%u, value is %u", - agent, remote_str, nice_address_get_port (&remote_candidate->addr), nom_value); - } - - /* - * If another pair is SELECTED, change this pair's priority to be greater than - * selected pair's priority so this pair gets SELECTED! - */ - if (component->selected_pair.priority && - component->selected_pair.remote && component->selected_pair.remote != remote_candidate && - component->selected_pair.local && component->selected_pair.local != local_candidate) { - for (lst = stream->conncheck_list; lst; lst = lst->next) { - CandidateCheckPair *pair = lst->data; - if (pair->local == local_candidate && pair->remote == remote_candidate) { - if (pair->valid) { - pair->priority = component->selected_pair.priority + 1; - } - break; - } - } - } - priv_mark_pair_nominated (agent, stream, component, local_candidate, remote_candidate); - return TRUE; - } - return FALSE; -} - -/* - * Processing an incoming STUN message. - * - * @param agent self pointer - * @param stream stream the packet is related to - * @param component component the packet is related to - * @param nicesock socket from which the packet was received - * @param from address of the sender - * @param buf message contents - * @param buf message length - * - * @pre contents of 'buf' is a STUN message - * - * @return XXX (what FALSE means exactly?) - */ -gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream, - NiceComponent *component, NiceSocket *nicesock, const NiceAddress *from, - gchar *buf, guint len) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sockaddr; - uint8_t rbuf[MAX_STUN_DATAGRAM_PAYLOAD]; - ssize_t res; - size_t rbuf_len = sizeof (rbuf); - bool control = agent->controlling_mode; - uint8_t uname[NICE_STREAM_MAX_UNAME]; - guint uname_len; - uint8_t *username; - uint16_t username_len; - StunMessage req; - StunMessage msg; - StunValidationStatus valid; - conncheck_validater_data validater_data = {agent, stream, component, NULL}; - GSList *i, *j; - NiceCandidate *remote_candidate = NULL; - NiceCandidate *remote_candidate2 = NULL; - NiceCandidate *local_candidate = NULL; - gboolean discovery_msg = FALSE; - - nice_address_copy_to_sockaddr (from, &sockaddr.addr); - - /* note: contents of 'buf' already validated, so it is - * a valid and fully received STUN message */ - - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (from, tmpbuf); - nice_debug ("Agent %p: inbound STUN packet for %u/%u (stream/component) from [%s]:%u (%u octets) :", - agent, stream->id, component->id, tmpbuf, nice_address_get_port (from), len); - } - - /* note: ICE 7.2. "STUN Server Procedures" (ID-19) */ - - valid = stun_agent_validate (&component->stun_agent, &req, - (uint8_t *) buf, len, conncheck_stun_validater, &validater_data); - - /* Check for discovery candidates stun agents */ - if (valid == STUN_VALIDATION_BAD_REQUEST || - valid == STUN_VALIDATION_UNMATCHED_RESPONSE) { - for (i = agent->discovery_list; i; i = i->next) { - CandidateDiscovery *d = i->data; - if (d->stream_id == stream->id && d->component_id == component->id && - d->nicesock == nicesock) { - valid = stun_agent_validate (&d->stun_agent, &req, - (uint8_t *) buf, len, conncheck_stun_validater, &validater_data); - - if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE) - continue; - - discovery_msg = TRUE; - break; - } - } - } - /* Check for relay refresh stun agents */ - if (valid == STUN_VALIDATION_BAD_REQUEST || - valid == STUN_VALIDATION_UNMATCHED_RESPONSE) { - for (i = agent->refresh_list; i; i = i->next) { - CandidateRefresh *r = i->data; - - nice_debug_verbose ("Comparing r.sid=%u to sid=%u, r.cid=%u to cid=%u and %p and %p to %p", - r->stream_id, stream->id, r->component_id, component->id, r->nicesock, - r->candidate->sockptr, nicesock); - - if (r->stream_id == stream->id && r->component_id == component->id && - (r->nicesock == nicesock || r->candidate->sockptr == nicesock)) { - valid = stun_agent_validate (&r->stun_agent, &req, - (uint8_t *) buf, len, conncheck_stun_validater, &validater_data); - nice_debug ("Validating gave %d", valid); - if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE) - continue; - discovery_msg = TRUE; - break; - } - } - } - - g_free (validater_data.password); - - if (valid == STUN_VALIDATION_NOT_STUN || - valid == STUN_VALIDATION_INCOMPLETE_STUN || - valid == STUN_VALIDATION_BAD_REQUEST) - { - nice_debug ("Agent %p : Incorrectly multiplexed STUN message ignored.", - agent); - return FALSE; - } - - if (valid == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE) { - nice_debug ("Agent %p : Unknown mandatory attributes in message.", agent); - - if (agent->compatibility != NICE_COMPATIBILITY_MSN && - agent->compatibility != NICE_COMPATIBILITY_OC2007) { - rbuf_len = stun_agent_build_unknown_attributes_error (&component->stun_agent, - &msg, rbuf, rbuf_len, &req); - if (rbuf_len != 0) - agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf); - } - return TRUE; - } - - if (valid == STUN_VALIDATION_UNAUTHORIZED) { - nice_debug ("Agent %p : Integrity check failed.", agent); - - if (stun_agent_init_error (&component->stun_agent, &msg, rbuf, rbuf_len, - &req, STUN_ERROR_UNAUTHORIZED)) { - rbuf_len = stun_agent_finish_message (&component->stun_agent, &msg, NULL, 0); - if (rbuf_len > 0 && agent->compatibility != NICE_COMPATIBILITY_MSN && - agent->compatibility != NICE_COMPATIBILITY_OC2007) - agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf); - } - return TRUE; - } - if (valid == STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST) { - nice_debug ("Agent %p : Integrity check failed - bad request.", agent); - if (stun_agent_init_error (&component->stun_agent, &msg, rbuf, rbuf_len, - &req, STUN_ERROR_BAD_REQUEST)) { - rbuf_len = stun_agent_finish_message (&component->stun_agent, &msg, NULL, 0); - if (rbuf_len > 0 && agent->compatibility != NICE_COMPATIBILITY_MSN && - agent->compatibility != NICE_COMPATIBILITY_OC2007) - agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf); - } - return TRUE; - } - - username = (uint8_t *) stun_message_find (&req, STUN_ATTRIBUTE_USERNAME, - &username_len); - - for (i = component->local_candidates; i; i = i->next) { - NiceCandidate *cand = i->data; - NiceAddress *addr; - - if (cand->type == NICE_CANDIDATE_TYPE_RELAYED) - addr = &cand->addr; - else - addr = &cand->base_addr; - - if (nice_address_equal (&nicesock->addr, addr) && - local_candidate_and_socket_compatible (agent, cand, nicesock)) { - local_candidate = cand; - break; - } - } - - for (i = component->remote_candidates; i; i = i->next) { - NiceCandidate *cand = i->data; - if (nice_address_equal (from, &cand->addr) && - remote_candidate_and_socket_compatible (agent, local_candidate, - cand, nicesock)) { - remote_candidate = cand; - break; - } - } - - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE || - agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) { - /* We need to find which local candidate was used */ - for (i = component->remote_candidates; - i != NULL && remote_candidate2 == NULL; i = i->next) { - for (j = component->local_candidates; j; j = j->next) { - gboolean inbound = TRUE; - NiceCandidate *rcand = i->data; - NiceCandidate *lcand = j->data; - - /* If we receive a response, then the username is local:remote */ - if (agent->compatibility != NICE_COMPATIBILITY_MSN) { - if (stun_message_get_class (&req) == STUN_REQUEST || - stun_message_get_class (&req) == STUN_INDICATION) { - inbound = TRUE; - } else { - inbound = FALSE; - } - } - - uname_len = priv_create_username (agent, stream, - component->id, rcand, lcand, - uname, sizeof (uname), inbound); - - - - stun_debug ("Comparing usernames of size %d and %d: %d", - username_len, uname_len, username && uname_len == username_len && - memcmp (username, uname, uname_len) == 0); - stun_debug_bytes (" First username: ", username, - username ? username_len : 0); - stun_debug_bytes (" Second uname: ", uname, uname_len); - - if (username && - uname_len == username_len && - memcmp (uname, username, username_len) == 0) { - local_candidate = lcand; - remote_candidate2 = rcand; - break; - } - } - } - } - - if (component->remote_candidates && - agent->compatibility == NICE_COMPATIBILITY_GOOGLE && - local_candidate == NULL && - discovery_msg == FALSE) { - /* if we couldn't match the username and the stun agent has - IGNORE_CREDENTIALS then we have an integrity check failing. - This could happen with the race condition of receiving connchecks - before the remote candidates are added. Just drop the message, and let - the retransmissions make it work. */ - nice_debug ("Agent %p : Username check failed.", agent); - return TRUE; - } - - /* This is most likely caused by a second response to a request which - * already has received a valid reply. - */ - if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE) { - nice_debug ("Agent %p : Valid STUN response for which we don't have a request, ignoring", agent); - return TRUE; - } - - if (valid != STUN_VALIDATION_SUCCESS) { - nice_debug ("Agent %p : STUN message is unsuccessful %d, ignoring", agent, valid); - return FALSE; - } - - - if (stun_message_get_class (&req) == STUN_REQUEST) { - if ( agent->compatibility == NICE_COMPATIBILITY_MSN - || agent->compatibility == NICE_COMPATIBILITY_OC2007) { - if (local_candidate && remote_candidate2) { - gsize key_len; - - if (agent->compatibility == NICE_COMPATIBILITY_MSN) { - username = (uint8_t *) stun_message_find (&req, - STUN_ATTRIBUTE_USERNAME, &username_len); - uname_len = priv_create_username (agent, stream, - component->id, remote_candidate2, local_candidate, - uname, sizeof (uname), FALSE); - memcpy (username, uname, MIN (uname_len, username_len)); - - req.key = g_base64_decode ((gchar *) remote_candidate2->password, - &key_len); - req.key_len = key_len; - } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007) { - req.key = g_base64_decode ((gchar *) local_candidate->password, - &key_len); - req.key_len = key_len; - } - } else { - nice_debug ("Agent %p : received MSN incoming check from unknown remote candidate. " - "Ignoring request", agent); - return TRUE; - } - } - - rbuf_len = sizeof (rbuf); - res = stun_usage_ice_conncheck_create_reply (&component->stun_agent, &req, - &msg, rbuf, &rbuf_len, &sockaddr.storage, sizeof (sockaddr), - &control, agent->tie_breaker, - agent_to_ice_compatibility (agent)); - - if ( agent->compatibility == NICE_COMPATIBILITY_MSN - || agent->compatibility == NICE_COMPATIBILITY_OC2007) { - g_free (req.key); - } - - if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) - priv_check_for_role_conflict (agent, control); - - if (res == STUN_USAGE_ICE_RETURN_SUCCESS || - res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) { - /* case 1: valid incoming request, send a reply/error */ - bool use_candidate = - stun_usage_ice_conncheck_use_candidate (&req); - uint32_t priority = stun_usage_ice_conncheck_priority (&req); - - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE || - agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) - use_candidate = TRUE; - - if (stream->initial_binding_request_received != TRUE) - agent_signal_initial_binding_request_received (agent, stream); - - if (remote_candidate == NULL) { - nice_debug ("Agent %p : No matching remote candidate for incoming " - "check -> peer-reflexive candidate.", agent); - remote_candidate = discovery_learn_remote_peer_reflexive_candidate ( - agent, stream, component, priority, from, nicesock, - local_candidate, - remote_candidate2 ? remote_candidate2 : remote_candidate); - if(remote_candidate && stream->remote_ufrag[0]) { - if (local_candidate && - local_candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) - priv_conn_check_add_for_candidate_pair_matched (agent, - stream->id, component, local_candidate, remote_candidate, - NICE_CHECK_WAITING); - else - conn_check_add_for_candidate (agent, stream->id, component, remote_candidate); - } - } - - nice_component_add_valid_candidate (agent, component, remote_candidate); - - priv_reply_to_conn_check (agent, stream, component, local_candidate, - remote_candidate, from, nicesock, rbuf_len, &msg, use_candidate); - - if (stream->remote_ufrag[0] == 0) { - /* case: We've got a valid binding request to a local candidate - * but we do not yet know remote credentials. - * As per sect 7.2 of ICE (ID-19), we send a reply - * immediately but postpone all other processing until - * we get information about the remote candidates */ - - /* step: send a reply immediately but postpone other processing */ - priv_store_pending_check (agent, component, from, nicesock, - username, username_len, priority, use_candidate); - priv_print_conn_check_lists (agent, G_STRFUNC, ", icheck stored"); - } - } else { - nice_debug ("Agent %p : Invalid STUN packet, ignoring... %s", - agent, strerror(errno)); - return FALSE; - } - } else { - /* case 2: not a new request, might be a reply... */ - gboolean trans_found = FALSE; - - /* note: ICE sect 7.1.2. "Processing the Response" (ID-19) */ - - /* step: let's try to match the response to an existing check context */ - if (trans_found != TRUE) - trans_found = priv_map_reply_to_conn_check_request (agent, stream, - component, nicesock, from, local_candidate, remote_candidate, &req); - - /* step: let's try to match the response to an existing discovery */ - if (trans_found != TRUE) - trans_found = priv_map_reply_to_discovery_request (agent, &req); - - /* step: let's try to match the response to an existing turn allocate */ - if (trans_found != TRUE) - trans_found = priv_map_reply_to_relay_request (agent, &req); - - /* step: let's try to match the response to an existing turn refresh */ - if (trans_found != TRUE) - trans_found = priv_map_reply_to_relay_refresh (agent, &req); - - if (trans_found != TRUE) - trans_found = priv_map_reply_to_relay_remove (agent, &req); - - /* step: let's try to match the response to an existing keepalive conncheck */ - if (trans_found != TRUE) - trans_found = priv_map_reply_to_keepalive_conncheck (agent, component, - &req); - - if (trans_found != TRUE) - nice_debug ("Agent %p : Unable to match to an existing transaction, " - "probably a keepalive.", agent); - } - - /* RENOMINATION attribute support */ - conn_check_handle_renomination(agent, stream, component, &req, remote_candidate, local_candidate); - - return TRUE; -} - -/* Remove all pointers to the given @sock from the connection checking process. - * These are entirely NiceCandidates pointed to from various places. */ -void -conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *component, - NiceSocket *sock) -{ - GSList *l; - - if (component->selected_pair.local && - component->selected_pair.local->sockptr == sock && - component->state == NICE_COMPONENT_STATE_READY) { - nice_debug ("Agent %p: Selected pair socket %p has been destroyed, " - "declaring failed", agent, sock); - agent_signal_component_state_change (agent, - stream->id, component->id, NICE_COMPONENT_STATE_FAILED); - } - - /* Prune from the candidate check pairs. */ - for (l = stream->conncheck_list; l != NULL;) { - CandidateCheckPair *p = l->data; - GSList *next = l->next; - - if ((p->local != NULL && p->local->sockptr == sock) || - (p->remote != NULL && p->remote->sockptr == sock) || - (p->sockptr == sock)) { - nice_debug ("Agent %p : Retransmissions failed, giving up on pair %p", - agent, p); - candidate_check_pair_fail (stream, agent, p); - candidate_check_pair_free (agent, p); - stream->conncheck_list = g_slist_delete_link (stream->conncheck_list, l); - } - - l = next; - } -} diff --git a/agent/conncheck.h b/agent/conncheck.h deleted file mode 100644 index 50fa0b1..0000000 --- a/agent/conncheck.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _NICE_CONNCHECK_H -#define _NICE_CONNCHECK_H - -/* note: this is a private header to libnice */ - -#include "agent.h" -#include "stream.h" -#include "stun/stunagent.h" -#include "stun/usages/timer.h" - -#define NICE_CANDIDATE_PAIR_MAX_FOUNDATION NICE_CANDIDATE_MAX_FOUNDATION*2 - -/** - * NiceCheckState: - * @NICE_CHECK_WAITING: Waiting to be scheduled. - * @NICE_CHECK_IN_PROGRESS: Connection checks started. - * @NICE_CHECK_SUCCEEDED: Connection successfully checked. - * @NICE_CHECK_FAILED: No connectivity; retransmissions ceased. - * @NICE_CHECK_FROZEN: Waiting to be scheduled to %NICE_CHECK_WAITING. - * @NICE_CHECK_DISCOVERED: A valid candidate pair not on the check list. - * - * States for checking a candidate pair. - */ -typedef enum -{ - NICE_CHECK_WAITING = 1, - NICE_CHECK_IN_PROGRESS, - NICE_CHECK_SUCCEEDED, - NICE_CHECK_FAILED, - NICE_CHECK_FROZEN, - NICE_CHECK_DISCOVERED, -} NiceCheckState; - -typedef struct _CandidateCheckPair CandidateCheckPair; -typedef struct _StunTransaction StunTransaction; - -struct _StunTransaction -{ - gint64 next_tick; /* next tick timestamp */ - StunTimer timer; - uint8_t buffer[STUN_MAX_MESSAGE_SIZE_IPV6]; - StunMessage message; -}; - -struct _CandidateCheckPair -{ - guint stream_id; - guint component_id; - NiceCandidate *local; - NiceCandidate *remote; - NiceSocket *sockptr; - gchar foundation[NICE_CANDIDATE_PAIR_MAX_FOUNDATION]; - NiceCheckState state; - gboolean nominated; - gboolean valid; - gboolean use_candidate_on_next_check; - gboolean mark_nominated_on_response_arrival; - gboolean retransmit; /* if the first stun request must be retransmitted */ - CandidateCheckPair *discovered_pair; - CandidateCheckPair *succeeded_pair; - guint64 priority; - guint32 stun_priority; - GSList *stun_transactions; /* a list of ongoing stun requests */ -}; - -int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *remote); -int conn_check_add_for_local_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local); -gboolean conn_check_add_for_candidate_pair (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local, NiceCandidate *remote); -void conn_check_free (NiceAgent *agent); -void conn_check_schedule_next (NiceAgent *agent); -int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair); -void conn_check_prune_stream (NiceAgent *agent, NiceStream *stream); -gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *udp_socket, const NiceAddress *from, gchar *buf, guint len); -gint conn_check_compare (const CandidateCheckPair *a, const CandidateCheckPair *b); -void conn_check_remote_candidates_set(NiceAgent *agent, NiceStream *stream, NiceComponent *component); -void conn_check_remote_credentials_set(NiceAgent *agent, NiceStream *stream); -NiceCandidateTransport conn_check_match_transport (NiceCandidateTransport transport); -void -conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *component, - NiceSocket *sock); - -void recalculate_pair_priorities (NiceAgent *agent); -void conn_check_update_selected_pair (NiceAgent *agent, - NiceComponent *component, CandidateCheckPair *pair); -void conn_check_update_check_list_state_for_ready (NiceAgent *agent, - NiceStream *stream, NiceComponent *component); -void conn_check_unfreeze_related (NiceAgent *agent, CandidateCheckPair *pair); -guint conn_check_stun_transactions_count (NiceAgent *agent); - - -#endif /*_NICE_CONNCHECK_H */ diff --git a/agent/debug.c b/agent/debug.c deleted file mode 100644 index 08ffb07..0000000 --- a/agent/debug.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "debug.h" - -#include "stunagent.h" -#include "pseudotcp.h" - -#include "agent-priv.h" - -static int debug_enabled = 0; -static int debug_verbose_enabled = 0; - -#define NICE_DEBUG_STUN 1 -#define NICE_DEBUG_NICE 2 -#define NICE_DEBUG_PSEUDOTCP 4 -#define NICE_DEBUG_PSEUDOTCP_VERBOSE 8 -#define NICE_DEBUG_NICE_VERBOSE 16 - -static const GDebugKey keys[] = { - { (gchar *)"stun", NICE_DEBUG_STUN }, - { (gchar *)"nice", NICE_DEBUG_NICE }, - { (gchar *)"pseudotcp", NICE_DEBUG_PSEUDOTCP }, - { (gchar *)"pseudotcp-verbose", NICE_DEBUG_PSEUDOTCP_VERBOSE }, - { (gchar *)"nice-verbose", NICE_DEBUG_NICE_VERBOSE } -}; - -static const GDebugKey gkeys[] = { - { (gchar *)"libnice-stun", NICE_DEBUG_STUN }, - { (gchar *)"libnice", NICE_DEBUG_NICE }, - { (gchar *)"libnice-pseudotcp", NICE_DEBUG_PSEUDOTCP }, - { (gchar *)"libnice-pseudotcp-verbose", NICE_DEBUG_PSEUDOTCP_VERBOSE }, - { (gchar *)"libnice-verbose", NICE_DEBUG_NICE_VERBOSE } -}; - -static void -stun_handler (const char *format, va_list ap) G_GNUC_PRINTF (1, 0); - -static void -stun_handler (const char *format, va_list ap) -{ - g_logv ("libnice-stun", G_LOG_LEVEL_DEBUG, format, ap); -} - -void nice_debug_init (void) -{ - static gboolean debug_initialized = FALSE; - const gchar *flags_string; - const gchar *gflags_string; - guint flags = 0; - - if (!debug_initialized) { - debug_initialized = TRUE; - - flags_string = g_getenv ("NICE_DEBUG"); - gflags_string = g_getenv ("G_MESSAGES_DEBUG"); - - if (flags_string) - flags = g_parse_debug_string (flags_string, keys, G_N_ELEMENTS (keys)); - if (gflags_string) - flags |= g_parse_debug_string (gflags_string, gkeys, G_N_ELEMENTS (gkeys)); - if (gflags_string && strstr (gflags_string, "libnice-pseudotcp-verbose")) - flags |= NICE_DEBUG_PSEUDOTCP_VERBOSE; - if (gflags_string && strstr (gflags_string, "libnice-verbose")) { - flags |= NICE_DEBUG_NICE_VERBOSE; - } - - stun_set_debug_handler (stun_handler); - debug_enabled = !!(flags & NICE_DEBUG_NICE); - if (flags & NICE_DEBUG_STUN) - stun_debug_enable (); - else - stun_debug_disable (); - - if (flags & NICE_DEBUG_NICE_VERBOSE) - debug_verbose_enabled = TRUE; - - /* Set verbose before normal so that if we use 'all', then only - normal debug is enabled, we'd need to set pseudotcp-verbose without the - pseudotcp flag in order to actually enable verbose pseudotcp */ - if (flags & NICE_DEBUG_PSEUDOTCP_VERBOSE) - pseudo_tcp_set_debug_level (PSEUDO_TCP_DEBUG_VERBOSE); - else if (flags & NICE_DEBUG_PSEUDOTCP) - pseudo_tcp_set_debug_level (PSEUDO_TCP_DEBUG_NORMAL); - } -} - -#ifndef NDEBUG -gboolean nice_debug_is_enabled (void) -{ - return debug_enabled; -} -gboolean nice_debug_is_verbose (void) -{ - return debug_verbose_enabled; -} -#else -/* Defined in agent-priv.h. */ -#endif - -void nice_debug_enable (gboolean with_stun) -{ - nice_debug_init (); - debug_enabled = 1; - if (with_stun) - stun_debug_enable (); -} -void nice_debug_disable (gboolean with_stun) -{ - nice_debug_init (); - debug_enabled = 0; - if (with_stun) - stun_debug_disable (); -} - -#ifndef NDEBUG -void nice_debug (const char *fmt, ...) -{ - va_list ap; - if (debug_enabled) { - va_start (ap, fmt); - g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, fmt, ap); - va_end (ap); - } -} -void nice_debug_verbose (const char *fmt, ...) -{ - va_list ap; - if (debug_enabled && debug_verbose_enabled) { - va_start (ap, fmt); - g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, fmt, ap); - va_end (ap); - } -} -#else -/* Defined in agent-priv.h. */ -#endif diff --git a/agent/debug.h b/agent/debug.h deleted file mode 100644 index c1a6473..0000000 --- a/agent/debug.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef __LIBNICE_DEBUG_H__ -#define __LIBNICE_DEBUG_H__ - - -/** - * SECTION:debug - * @short_description: Debug messages utility functions - * @stability: Unstable - * - * Libnice can output a lot of information when debug messages are enabled. - * This can significantly help track down problems and/or understand what - * it's doing. - * - * You can enable/disable the debug messages by calling nice_debug_enable() - * or nice_debug_disable() and choosing whether you want only ICE debug messages - * or also stun debug messages. - * - * By default, the debug messages are disabled, unless the environment - * variable NICE_DEBUG is set, in which case, it must contain a comma separated - * list of flags specifying which debug to enable. - * The currently available flags are "nice", "stun", "pseudotcp", - * "pseudotcp-verbose" or "all" to enable all debug messages. - * If the 'pseudotcp' flag is enabled, then 'pseudotcp-verbose' gets - * automatically disabled. This is to allow the use of the 'all' flag without - * having verbose messages from pseudotcp. You can enable verbose debug messages - * from the pseudotcp layer by specifying 'pseudotcp-verbose' without the - * 'pseudotcp' flag. - * - * - * This API is unstable and is subject to change at any time... - * More flags are to come and a better API to enable/disable each flag - * should be added. - */ - - -#include - -G_BEGIN_DECLS - -/** - * nice_debug_enable: - * @with_stun: Also enable STUN debugging messages - * - * Enables libnice debug output to the terminal. Note that the - * `G_MESSAGES_DEBUG` and `NICE_DEBUG` environment variables must be set to the - * set of logging domains to print, in order for any output to be printed. Set - * them to `all` to print all debugging messages, or any of the following - * domains: - * - `libnice-stun` - * - `libnice-tests` - * - `libnice-socket` - * - `libnice` - * - `libnice-pseudotcp` - * - `libnice-pseudotcp-verbose` - */ -void nice_debug_enable (gboolean with_stun); - -/** - * nice_debug_disable: - * @with_stun: Also disable stun debugging messages - * - * Disables libnice debug output to the terminal - */ -void nice_debug_disable (gboolean with_stun); - -G_END_DECLS - -#endif /* __LIBNICE_DEBUG_H__ */ - diff --git a/agent/discovery.c b/agent/discovery.c deleted file mode 100644 index 0abc7ec..0000000 --- a/agent/discovery.c +++ /dev/null @@ -1,1353 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * @file discovery.c - * @brief ICE candidate discovery functions - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include -#include -#include - -#include "debug.h" - -#include "agent.h" -#include "agent-priv.h" -#include "component.h" -#include "discovery.h" -#include "stun/usages/bind.h" -#include "stun/usages/turn.h" -#include "socket.h" - -/* - * Frees the CandidateDiscovery structure pointed to - * by 'user data'. Compatible with g_slist_free_full(). - */ -static void discovery_free_item (CandidateDiscovery *cand) -{ - if (cand->turn) - turn_server_unref (cand->turn); - - g_slice_free (CandidateDiscovery, cand); -} - -/* - * Frees all discovery related resources for the agent. - */ -void discovery_free (NiceAgent *agent) -{ - g_slist_free_full (agent->discovery_list, - (GDestroyNotify) discovery_free_item); - agent->discovery_list = NULL; - agent->discovery_unsched_items = 0; - - if (agent->discovery_timer_source != NULL) { - g_source_destroy (agent->discovery_timer_source); - g_source_unref (agent->discovery_timer_source); - agent->discovery_timer_source = NULL; - } -} - -/* - * Prunes the list of discovery processes for items related - * to stream 'stream_id'. - * - * @return TRUE on success, FALSE on a fatal error - */ -void discovery_prune_stream (NiceAgent *agent, guint stream_id) -{ - GSList *i; - - for (i = agent->discovery_list; i ; ) { - CandidateDiscovery *cand = i->data; - GSList *next = i->next; - - if (cand->stream_id == stream_id) { - agent->discovery_list = g_slist_remove (agent->discovery_list, cand); - discovery_free_item (cand); - } - i = next; - } - - if (agent->discovery_list == NULL) { - /* noone using the timer anymore, clean it up */ - discovery_free (agent); - } -} - -/* - * Prunes the list of discovery processes for items related - * to socket @sock. - * - * @return TRUE on success, FALSE on a fatal error - */ -void discovery_prune_socket (NiceAgent *agent, NiceSocket *sock) -{ - GSList *i; - - for (i = agent->discovery_list; i ; ) { - CandidateDiscovery *discovery = i->data; - GSList *next = i->next; - - if (discovery->nicesock == sock) { - agent->discovery_list = g_slist_remove (agent->discovery_list, discovery); - discovery_free_item (discovery); - } - i = next; - } - - if (agent->discovery_list == NULL) { - /* noone using the timer anymore, clean it up */ - discovery_free (agent); - } -} - -/* - * Frees a CandidateRefresh and calls destroy callback if it has been set. - */ -void refresh_free (NiceAgent *agent, CandidateRefresh *cand) -{ - nice_debug ("Agent %p : Freeing candidate refresh %p", agent, cand); - - agent->refresh_list = g_slist_remove (agent->refresh_list, cand); - - if (cand->timer_source != NULL) { - g_source_destroy (cand->timer_source); - g_clear_pointer (&cand->timer_source, g_source_unref); - } - - if (cand->tick_source) { - g_source_destroy (cand->tick_source); - g_clear_pointer (&cand->tick_source, g_source_unref); - } - - if (cand->destroy_source) { - g_source_destroy (cand->destroy_source); - g_source_unref (cand->destroy_source); - } - - if (cand->destroy_cb) { - cand->destroy_cb (cand->destroy_cb_data); - } - - g_slice_free (CandidateRefresh, cand); -} - -static gboolean on_refresh_remove_timeout (NiceAgent *agent, - CandidateRefresh *cand) -{ - switch (stun_timer_refresh (&cand->timer)) { - case STUN_USAGE_TIMER_RETURN_TIMEOUT: - { - StunTransactionId id; - - nice_debug ("Agent %p : TURN deallocate for refresh %p timed out", - agent, cand); - - stun_message_id (&cand->stun_message, id); - stun_agent_forget_transaction (&cand->stun_agent, id); - - refresh_free (agent, cand); - break; - } - case STUN_USAGE_TIMER_RETURN_RETRANSMIT: - nice_debug ("Agent %p : Retransmitting TURN deallocate for refresh %p", - agent, cand); - - agent_socket_send (cand->nicesock, &cand->server, - stun_message_length (&cand->stun_message), (gchar *)cand->stun_buffer); - - G_GNUC_FALLTHROUGH; - case STUN_USAGE_TIMER_RETURN_SUCCESS: - agent_timeout_add_with_context (agent, &cand->tick_source, - "TURN deallocate retransmission", stun_timer_remainder (&cand->timer), - (NiceTimeoutLockedCallback) on_refresh_remove_timeout, cand); - break; - default: - break; - } - - return G_SOURCE_REMOVE; -} - -/* - * Closes the port associated with the candidate refresh on the TURN server by - * sending a refresh request that has zero lifetime. After a response is - * received or the request times out, 'cand' gets freed and 'cb' is called. - */ -static gboolean refresh_remove_async (NiceAgent *agent, gpointer pointer) -{ - uint8_t *username; - gsize username_len; - uint8_t *password; - gsize password_len; - size_t buffer_len = 0; - CandidateRefresh *cand = (CandidateRefresh *) pointer; - StunUsageTurnCompatibility turn_compat = agent_to_turn_compatibility (agent); - - nice_debug ("Agent %p : Sending request to remove TURN allocation " - "for refresh %p", agent, cand); - - if (cand->timer_source != NULL) { - g_source_destroy (cand->timer_source); - g_source_unref (cand->timer_source); - cand->timer_source = NULL; - } - - g_source_destroy (cand->destroy_source); - g_source_unref (cand->destroy_source); - cand->destroy_source = NULL; - - username = (uint8_t *)cand->candidate->turn->username; - username_len = (size_t) strlen (cand->candidate->turn->username); - password = (uint8_t *)cand->candidate->turn->password; - password_len = (size_t) strlen (cand->candidate->turn->password); - - if (turn_compat == STUN_USAGE_TURN_COMPATIBILITY_MSN || - turn_compat == STUN_USAGE_TURN_COMPATIBILITY_OC2007) { - username = cand->candidate->turn->decoded_username; - password = cand->candidate->turn->decoded_password; - username_len = cand->candidate->turn->decoded_username_len; - password_len = cand->candidate->turn->decoded_password_len; - } - - buffer_len = stun_usage_turn_create_refresh (&cand->stun_agent, - &cand->stun_message, cand->stun_buffer, sizeof(cand->stun_buffer), - cand->stun_resp_msg.buffer == NULL ? NULL : &cand->stun_resp_msg, 0, - username, username_len, - password, password_len, - agent_to_turn_compatibility (agent)); - - if (buffer_len > 0) { - agent_socket_send (cand->nicesock, &cand->server, buffer_len, - (gchar *)cand->stun_buffer); - - stun_timer_start (&cand->timer, agent->stun_initial_timeout, - agent->stun_max_retransmissions); - - agent_timeout_add_with_context (agent, &cand->tick_source, - "TURN deallocate retransmission", stun_timer_remainder (&cand->timer), - (NiceTimeoutLockedCallback) on_refresh_remove_timeout, cand); - } - return G_SOURCE_REMOVE; -} - -typedef struct { - NiceAgent *agent; - gpointer user_data; - guint items_to_free; - NiceTimeoutLockedCallback cb; -} RefreshPruneAsyncData; - -static void on_refresh_removed (RefreshPruneAsyncData *data) -{ - if (data->items_to_free == 0 || --(data->items_to_free) == 0) { - GSource *timeout_source = NULL; - agent_timeout_add_with_context (data->agent, &timeout_source, - "Async refresh prune", 0, data->cb, data->user_data); - - g_source_unref (timeout_source); - g_free (data); - } -} - -static void refresh_prune_async (NiceAgent *agent, GSList *refreshes, - NiceTimeoutLockedCallback function, gpointer user_data) -{ - RefreshPruneAsyncData *data = g_new0 (RefreshPruneAsyncData, 1); - GSList *it; - guint timeout = 0; - - data->agent = agent; - data->user_data = user_data; - data->cb = function; - - for (it = refreshes; it; it = it->next) { - CandidateRefresh *cand = it->data; - - if (cand->disposing) - continue; - - timeout += agent->timer_ta; - cand->disposing = TRUE; - cand->destroy_cb = (GDestroyNotify) on_refresh_removed; - cand->destroy_cb_data = data; - - agent_timeout_add_with_context(agent, &cand->destroy_source, - "TURN refresh remove async", timeout, refresh_remove_async, cand); - - ++data->items_to_free; - } - - if (data->items_to_free == 0) { - /* Stream doesn't have any refreshes to remove. Invoke our callback once to - * schedule client's callback function. */ - on_refresh_removed (data); - } -} - -void refresh_prune_agent_async (NiceAgent *agent, - NiceTimeoutLockedCallback function, gpointer user_data) -{ - refresh_prune_async (agent, agent->refresh_list, function, user_data); -} - -/* - * Removes the candidate refreshes related to 'stream' and asynchronously - * closes the associated port allocations on TURN server. Invokes 'function' - * when the process finishes. - */ -void refresh_prune_stream_async (NiceAgent *agent, NiceStream *stream, - NiceTimeoutLockedCallback function) -{ - GSList *refreshes = NULL; - GSList *i; - - for (i = agent->refresh_list; i ; i = i->next) { - CandidateRefresh *cand = i->data; - - /* Don't free the candidate refresh to the currently selected local candidate - * unless the whole pair is being destroyed. - */ - if (cand->stream_id == stream->id) { - refreshes = g_slist_append (refreshes, cand); - } - } - - refresh_prune_async (agent, refreshes, function, stream); - g_slist_free (refreshes); -} - -/* - * Removes the candidate refreshes related to 'candidate'. The function does not - * close any associated port allocations on TURN server. Its purpose is in - * situations when an error is detected in socket communication that prevents - * sending more requests to the server. - */ -void refresh_prune_candidate (NiceAgent *agent, NiceCandidate *candidate) -{ - GSList *i; - - for (i = agent->refresh_list; i;) { - GSList *next = i->next; - CandidateRefresh *refresh = i->data; - - if (refresh->candidate == candidate) { - refresh_free(agent, refresh); - } - - i = next; - } -} - -/* - * Removes the candidate refreshes related to 'candidate' and asynchronously - * closes the associated port allocations on TURN server. Invokes 'function' - * when the process finishes. - */ -void refresh_prune_candidate_async (NiceAgent *agent, NiceCandidate *candidate, - NiceTimeoutLockedCallback function) -{ - GSList *refreshes = NULL; - GSList *i; - - for (i = agent->refresh_list; i; i = i->next) { - CandidateRefresh *refresh = i->data; - - if (refresh->candidate == candidate) { - refreshes = g_slist_append (refreshes, refresh); - } - } - - refresh_prune_async (agent, refreshes, function, candidate); - g_slist_free (refreshes); -} - -/* - * Adds a new local candidate. Implements the candidate pruning - * defined in ICE spec section 4.1.3 "Eliminating Redundant - * Candidates" (ID-19). - */ -static gboolean priv_add_local_candidate_pruned (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *candidate) -{ - GSList *i; - - g_assert (candidate != NULL); - - for (i = component->local_candidates; i ; i = i->next) { - NiceCandidate *c = i->data; - - if (nice_address_equal (&c->base_addr, &candidate->base_addr) && - nice_address_equal (&c->addr, &candidate->addr) && - c->transport == candidate->transport) { - nice_debug ("Candidate %p (component-id %u) redundant, ignoring.", candidate, component->id); - return FALSE; - } - } - - component->local_candidates = g_slist_append (component->local_candidates, - candidate); - conn_check_add_for_local_candidate(agent, stream_id, component, candidate); - - return TRUE; -} - -static guint priv_highest_remote_foundation (NiceComponent *component) -{ - GSList *i; - guint highest = 1; - gchar foundation[NICE_CANDIDATE_MAX_FOUNDATION]; - - for (highest = 1;; highest++) { - gboolean taken = FALSE; - - g_snprintf (foundation, NICE_CANDIDATE_MAX_FOUNDATION, "remote%u", - highest); - for (i = component->remote_candidates; i; i = i->next) { - NiceCandidate *cand = i->data; - if (strncmp (foundation, cand->foundation, - NICE_CANDIDATE_MAX_FOUNDATION) == 0) { - taken = TRUE; - break; - } - } - if (!taken) - return highest; - } - - g_return_val_if_reached (highest); -} - -/* From RFC 5245 section 4.1.3: - * - * for reflexive and relayed candidates, the STUN or TURN servers - * used to obtain them have the same IP address. - */ -static gboolean -priv_compare_turn_servers (TurnServer *turn1, TurnServer *turn2) -{ - if (turn1 == turn2) - return TRUE; - if (turn1 == NULL || turn2 == NULL) - return FALSE; - - return nice_address_equal_no_port (&turn1->server, &turn2->server); -} - -/* - * Assings a foundation to the candidate. - * - * Implements the mechanism described in ICE sect - * 4.1.1.3 "Computing Foundations" (ID-19). - */ -static void priv_assign_foundation (NiceAgent *agent, NiceCandidate *candidate) -{ - GSList *i, *j, *k; - - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - for (j = stream->components; j; j = j->next) { - NiceComponent *component = j->data; - for (k = component->local_candidates; k; k = k->next) { - NiceCandidate *n = k->data; - - /* note: candidate must not on the local candidate list */ - g_assert (candidate != n); - - if (candidate->type == n->type && - candidate->transport == n->transport && - nice_address_equal_no_port (&candidate->base_addr, &n->base_addr) && - (candidate->type != NICE_CANDIDATE_TYPE_RELAYED || - priv_compare_turn_servers (candidate->turn, n->turn)) && - !(agent->compatibility == NICE_COMPATIBILITY_GOOGLE && - n->type == NICE_CANDIDATE_TYPE_RELAYED)) { - /* note: currently only one STUN server per stream at a - * time is supported, so there is no need to check - * for candidates that would otherwise share the - * foundation, but have different STUN servers */ - g_strlcpy (candidate->foundation, n->foundation, - NICE_CANDIDATE_MAX_FOUNDATION); - if (n->username) { - g_free (candidate->username); - candidate->username = g_strdup (n->username); - } - if (n->password) { - g_free (candidate->password); - candidate->password = g_strdup (n->password); - } - return; - } - } - } - } - - g_snprintf (candidate->foundation, NICE_CANDIDATE_MAX_FOUNDATION, - "%u", agent->next_candidate_id++); -} - -static void priv_assign_remote_foundation (NiceAgent *agent, NiceCandidate *candidate) -{ - GSList *i, *j, *k; - guint next_remote_id; - NiceComponent *component = NULL; - - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - for (j = stream->components; j; j = j->next) { - NiceComponent *c = j->data; - - if (c->id == candidate->component_id) - component = c; - - for (k = c->remote_candidates; k; k = k->next) { - NiceCandidate *n = k->data; - - /* note: candidate must not on the remote candidate list */ - g_assert (candidate != n); - - if (candidate->type == n->type && - candidate->transport == n->transport && - candidate->stream_id == n->stream_id && - nice_address_equal_no_port (&candidate->addr, &n->addr)) { - /* note: No need to check for STUN/TURN servers, as these candidate - * will always be peer reflexive, never relayed or serve reflexive. - */ - g_strlcpy (candidate->foundation, n->foundation, - NICE_CANDIDATE_MAX_FOUNDATION); - if (n->username) { - g_free (candidate->username); - candidate->username = g_strdup (n->username); - } - if (n->password) { - g_free (candidate->password); - candidate->password = g_strdup (n->password); - } - return; - } - } - } - } - - if (component) { - next_remote_id = priv_highest_remote_foundation (component); - g_snprintf (candidate->foundation, NICE_CANDIDATE_MAX_FOUNDATION, - "remote%u", next_remote_id); - } -} - - -static -void priv_generate_candidate_credentials (NiceAgent *agent, - NiceCandidate *candidate) -{ - - if (agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) { - guchar username[32]; - guchar password[16]; - - g_free (candidate->username); - g_free (candidate->password); - - nice_rng_generate_bytes (agent->rng, 32, (gchar *)username); - nice_rng_generate_bytes (agent->rng, 16, (gchar *)password); - - candidate->username = g_base64_encode (username, 32); - candidate->password = g_base64_encode (password, 16); - - } else if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - gchar username[16]; - - g_free (candidate->username); - g_free (candidate->password); - candidate->password = NULL; - - nice_rng_generate_bytes_print (agent->rng, 16, (gchar *)username); - - candidate->username = g_strndup (username, 16); - } - - -} - -static gboolean -priv_local_host_candidate_duplicate_port (NiceAgent *agent, - NiceCandidate *candidate) -{ - GSList *i, *j, *k; - - if (candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) - return FALSE; - - for (i = agent->streams; i; i = i->next) { - NiceStream *stream = i->data; - - for (j = stream->components; j; j = j->next) { - NiceComponent *component = j->data; - - for (k = component->local_candidates; k; k = k->next) { - NiceCandidate *c = k->data; - - if (candidate->transport == c->transport && - nice_address_ip_version (&candidate->addr) == - nice_address_ip_version (&c->addr) && - nice_address_get_port (&candidate->addr) == - nice_address_get_port (&c->addr)) - return TRUE; - } - } - } - return FALSE; -} - -/* - * Creates a local host candidate for 'component_id' of stream - * 'stream_id'. - * - * @return pointer to the created candidate, or NULL on error - */ -HostCandidateResult discovery_add_local_host_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceAddress *address, - NiceCandidateTransport transport, - NiceCandidate **outcandidate) -{ - NiceCandidate *candidate; - NiceComponent *component; - NiceStream *stream; - NiceSocket *nicesock = NULL; - HostCandidateResult res = HOST_CANDIDATE_FAILED; - - if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) - return res; - - candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_HOST); - candidate->transport = transport; - candidate->stream_id = stream_id; - candidate->component_id = component_id; - candidate->addr = *address; - candidate->base_addr = *address; - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - candidate->priority = nice_candidate_jingle_priority (candidate); - } else if (agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) { - candidate->priority = nice_candidate_msn_priority (candidate); - } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - candidate->priority = nice_candidate_ms_ice_priority (candidate, - agent->reliable, FALSE); - } else { - candidate->priority = nice_candidate_ice_priority (candidate, - agent->reliable, FALSE); - } - - priv_generate_candidate_credentials (agent, candidate); - priv_assign_foundation (agent, candidate); - - /* note: candidate username and password are left NULL as stream - level ufrag/password are used */ - if (transport == NICE_CANDIDATE_TRANSPORT_UDP) { - nicesock = nice_udp_bsd_socket_new (address); - } else if (transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) { - nicesock = nice_tcp_active_socket_new (agent->main_context, address); - } else if (transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) { - nicesock = nice_tcp_passive_socket_new (agent->main_context, address); - } else { - /* TODO: Add TCP-SO */ - } - if (!nicesock) { - res = HOST_CANDIDATE_CANT_CREATE_SOCKET; - goto errors; - } - - candidate->sockptr = nicesock; - candidate->addr = nicesock->addr; - candidate->base_addr = nicesock->addr; - - if (priv_local_host_candidate_duplicate_port (agent, candidate)) { - res = HOST_CANDIDATE_DUPLICATE_PORT; - goto errors; - } - - if (!priv_add_local_candidate_pruned (agent, stream_id, component, - candidate)) { - res = HOST_CANDIDATE_REDUNDANT; - goto errors; - } - - _priv_set_socket_tos (agent, nicesock, stream->tos); - nice_component_attach_socket (component, nicesock); - - *outcandidate = candidate; - - return HOST_CANDIDATE_SUCCESS; - -errors: - nice_candidate_free (candidate); - if (nicesock) - nice_socket_free (nicesock); - return res; -} - -/* - * Creates a server reflexive candidate for 'component_id' of stream - * 'stream_id'. - * - * @return pointer to the created candidate, or NULL on error - */ -NiceCandidate* -discovery_add_server_reflexive_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceAddress *address, - NiceCandidateTransport transport, - NiceSocket *base_socket, - gboolean nat_assisted) -{ - NiceCandidate *candidate; - NiceComponent *component; - NiceStream *stream; - gboolean result = FALSE; - - if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) - return NULL; - - candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE); - candidate->transport = transport; - candidate->stream_id = stream_id; - candidate->component_id = component_id; - candidate->addr = *address; - - /* step: link to the base candidate+socket */ - candidate->sockptr = base_socket; - candidate->base_addr = base_socket->addr; - - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - candidate->priority = nice_candidate_jingle_priority (candidate); - } else if (agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) { - candidate->priority = nice_candidate_msn_priority (candidate); - } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - candidate->priority = nice_candidate_ms_ice_priority (candidate, - agent->reliable, nat_assisted); - } else { - candidate->priority = nice_candidate_ice_priority (candidate, - agent->reliable, nat_assisted); - } - - priv_generate_candidate_credentials (agent, candidate); - priv_assign_foundation (agent, candidate); - - result = priv_add_local_candidate_pruned (agent, stream_id, component, candidate); - if (result) { - agent_signal_new_candidate (agent, candidate); - } - else { - /* error: duplicate candidate */ - nice_candidate_free (candidate), candidate = NULL; - } - - return candidate; -} - -/* - * Creates a server reflexive candidate for 'component_id' of stream - * 'stream_id' for each TCP_PASSIVE and TCP_ACTIVE candidates for each - * base address. - * - * @return pointer to the created candidate, or NULL on error - */ -void -discovery_discover_tcp_server_reflexive_candidates ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceAddress *address, - NiceSocket *base_socket) -{ - NiceComponent *component; - NiceStream *stream; - NiceAddress base_addr = base_socket->addr; - GSList *i; - - if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) - return; - - nice_address_set_port (&base_addr, 0); - for (i = component->local_candidates; i; i = i ->next) { - NiceCandidate *c = i->data; - NiceAddress caddr; - - caddr = c->addr; - nice_address_set_port (&caddr, 0); - if (agent->force_relay == FALSE && - c->transport != NICE_CANDIDATE_TRANSPORT_UDP && - c->type == NICE_CANDIDATE_TYPE_HOST && - nice_address_equal (&base_addr, &caddr)) { - nice_address_set_port (address, nice_address_get_port (&c->addr)); - discovery_add_server_reflexive_candidate ( - agent, - stream_id, - component_id, - address, - c->transport, - c->sockptr, - FALSE); - } - } -} - -/* - * Creates a server reflexive candidate for 'component_id' of stream - * 'stream_id'. - * - * @return pointer to the created candidate, or NULL on error - */ -NiceCandidate* -discovery_add_relay_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceAddress *address, - NiceCandidateTransport transport, - NiceSocket *base_socket, - TurnServer *turn) -{ - NiceCandidate *candidate; - NiceComponent *component; - NiceStream *stream; - NiceSocket *relay_socket = NULL; - - if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) - return NULL; - - candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_RELAYED); - candidate->transport = transport; - candidate->stream_id = stream_id; - candidate->component_id = component_id; - candidate->addr = *address; - candidate->turn = turn_server_ref (turn); - - /* step: link to the base candidate+socket */ - relay_socket = nice_udp_turn_socket_new (agent->main_context, address, - base_socket, &turn->server, - turn->username, turn->password, - agent_to_turn_socket_compatibility (agent)); - if (!relay_socket) - goto errors; - - candidate->sockptr = relay_socket; - candidate->base_addr = base_socket->addr; - - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - candidate->priority = nice_candidate_jingle_priority (candidate); - } else if (agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) { - candidate->priority = nice_candidate_msn_priority (candidate); - } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - candidate->priority = nice_candidate_ms_ice_priority (candidate, - agent->reliable, FALSE); - } else { - candidate->priority = nice_candidate_ice_priority (candidate, - agent->reliable, FALSE); - } - - priv_generate_candidate_credentials (agent, candidate); - - /* Google uses the turn username as the candidate username */ - if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - g_free (candidate->username); - candidate->username = g_strdup (turn->username); - } - - priv_assign_foundation (agent, candidate); - - if (!priv_add_local_candidate_pruned (agent, stream_id, component, candidate)) - goto errors; - - nice_component_attach_socket (component, relay_socket); - agent_signal_new_candidate (agent, candidate); - - return candidate; - -errors: - nice_candidate_free (candidate); - if (relay_socket) - nice_socket_free (relay_socket); - return NULL; -} - -/* - * Creates a peer reflexive candidate for 'component_id' of stream - * 'stream_id'. - * - * @return pointer to the created candidate, or NULL on error - */ -NiceCandidate* -discovery_add_peer_reflexive_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - guint32 priority, - NiceAddress *address, - NiceSocket *base_socket, - NiceCandidate *local, - NiceCandidate *remote) -{ - NiceCandidate *candidate; - NiceComponent *component; - NiceStream *stream; - gboolean result; - - if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) - return NULL; - - candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE); - if (local) - candidate->transport = local->transport; - else if (remote) - candidate->transport = conn_check_match_transport (remote->transport); - else { - if (base_socket->type == NICE_SOCKET_TYPE_UDP_BSD || - base_socket->type == NICE_SOCKET_TYPE_UDP_TURN) - candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP; - else - candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE; - } - candidate->stream_id = stream_id; - candidate->component_id = component_id; - candidate->addr = *address; - candidate->sockptr = base_socket; - candidate->base_addr = base_socket->addr; - /* We don't ensure priority uniqueness in this case, since the - * discovered candidate receives the same priority than its - * parent pair, by design, RFC 5245, sect 7.1.3.2.1. - * Discovering Peer Reflexive Candidates (the priority from the - * STUN Request) - */ - candidate->priority = priority; - priv_assign_foundation (agent, candidate); - - if ((agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) && - remote && local) { - guchar *new_username = NULL; - guchar *decoded_local = NULL; - guchar *decoded_remote = NULL; - gsize local_size; - gsize remote_size; - g_free(candidate->username); - g_free(candidate->password); - - decoded_local = g_base64_decode (local->username, &local_size); - decoded_remote = g_base64_decode (remote->username, &remote_size); - - new_username = g_new0(guchar, local_size + remote_size); - memcpy(new_username, decoded_local, local_size); - memcpy(new_username + local_size, decoded_remote, remote_size); - - candidate->username = g_base64_encode (new_username, local_size + remote_size); - g_free(new_username); - g_free(decoded_local); - g_free(decoded_remote); - - candidate->password = g_strdup(local->password); - } else if (local) { - g_free(candidate->username); - g_free(candidate->password); - - candidate->username = g_strdup(local->username); - candidate->password = g_strdup(local->password); - } - - result = priv_add_local_candidate_pruned (agent, stream_id, component, candidate); - if (result != TRUE) { - /* error: memory allocation, or duplicate candidate */ - nice_candidate_free (candidate), candidate = NULL; - } - - return candidate; -} - - -/* - * Adds a new peer reflexive candidate to the list of known - * remote candidates. The candidate is however not paired with - * existing local candidates. - * - * See ICE sect 7.2.1.3 "Learning Peer Reflexive Candidates" (ID-19). - * - * @return pointer to the created candidate, or NULL on error - */ -NiceCandidate *discovery_learn_remote_peer_reflexive_candidate ( - NiceAgent *agent, - NiceStream *stream, - NiceComponent *component, - guint32 priority, - const NiceAddress *remote_address, - NiceSocket *nicesock, - NiceCandidate *local, - NiceCandidate *remote) -{ - NiceCandidate *candidate; - - candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE); - - candidate->addr = *remote_address; - candidate->base_addr = *remote_address; - if (remote) - candidate->transport = remote->transport; - else if (local) - candidate->transport = conn_check_match_transport (local->transport); - else { - if (nicesock->type == NICE_SOCKET_TYPE_UDP_BSD || - nicesock->type == NICE_SOCKET_TYPE_UDP_TURN) - candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP; - else - candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; - } - candidate->sockptr = nicesock; - candidate->stream_id = stream->id; - candidate->component_id = component->id; - - /* if the check didn't contain the PRIORITY attribute, then the priority will - * be 0, which is invalid... */ - if (priority != 0) { - candidate->priority = priority; - } else if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { - candidate->priority = nice_candidate_jingle_priority (candidate); - } else if (agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) { - candidate->priority = nice_candidate_msn_priority (candidate); - } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { - candidate->priority = nice_candidate_ms_ice_priority (candidate, - agent->reliable, FALSE); - } else { - candidate->priority = nice_candidate_ice_priority (candidate, - agent->reliable, FALSE); - } - - priv_assign_remote_foundation (agent, candidate); - - if ((agent->compatibility == NICE_COMPATIBILITY_MSN || - agent->compatibility == NICE_COMPATIBILITY_OC2007) && - remote && local) { - guchar *new_username = NULL; - guchar *decoded_local = NULL; - guchar *decoded_remote = NULL; - gsize local_size; - gsize remote_size; - g_free(candidate->username); - g_free (candidate->password); - - decoded_local = g_base64_decode (local->username, &local_size); - decoded_remote = g_base64_decode (remote->username, &remote_size); - - new_username = g_new0(guchar, local_size + remote_size); - memcpy(new_username, decoded_remote, remote_size); - memcpy(new_username + remote_size, decoded_local, local_size); - - candidate->username = g_base64_encode (new_username, local_size + remote_size); - g_free(new_username); - g_free(decoded_local); - g_free(decoded_remote); - - candidate->password = g_strdup(remote->password); - } else if (remote) { - g_free (candidate->username); - g_free (candidate->password); - candidate->username = g_strdup(remote->username); - candidate->password = g_strdup(remote->password); - } - - /* note: candidate username and password are left NULL as stream - level ufrag/password are used */ - - component->remote_candidates = g_slist_append (component->remote_candidates, - candidate); - - agent_signal_new_remote_candidate (agent, candidate); - - return candidate; -} - -/* - * Timer callback that handles scheduling new candidate discovery - * processes (paced by the Ta timer), and handles running of the - * existing discovery processes. - * - * This function is designed for the g_timeout_add() interface. - * - * @return will return FALSE when no more pending timers. - */ -static gboolean priv_discovery_tick_unlocked (NiceAgent *agent) -{ - CandidateDiscovery *cand; - GSList *i; - int not_done = 0; /* note: track whether to continue timer */ - int need_pacing = 0; - size_t buffer_len = 0; - - { - static int tick_counter = 0; - if (tick_counter++ % 50 == 0) - nice_debug ("Agent %p : discovery tick #%d with list %p (1)", agent, tick_counter, agent->discovery_list); - } - - for (i = agent->discovery_list; i ; i = i->next) { - cand = i->data; - - if (cand->pending != TRUE) { - cand->pending = TRUE; - - if (agent->discovery_unsched_items) - --agent->discovery_unsched_items; - - if (nice_debug_is_enabled ()) { - gchar tmpbuf[INET6_ADDRSTRLEN]; - nice_address_to_string (&cand->server, tmpbuf); - nice_debug ("Agent %p : discovery - scheduling cand type %u addr %s.", - agent, cand->type, tmpbuf); - } - if (nice_address_is_valid (&cand->server) && - (cand->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE || - cand->type == NICE_CANDIDATE_TYPE_RELAYED)) { - NiceComponent *component; - - if (agent_find_component (agent, cand->stream_id, - cand->component_id, NULL, &component) && - (component->state == NICE_COMPONENT_STATE_DISCONNECTED || - component->state == NICE_COMPONENT_STATE_FAILED)) - agent_signal_component_state_change (agent, - cand->stream_id, - cand->component_id, - NICE_COMPONENT_STATE_GATHERING); - - if (cand->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE) { - buffer_len = stun_usage_bind_create (&cand->stun_agent, - &cand->stun_message, cand->stun_buffer, sizeof(cand->stun_buffer)); - } else if (cand->type == NICE_CANDIDATE_TYPE_RELAYED) { - uint8_t *username = (uint8_t *)cand->turn->username; - gsize username_len = strlen (cand->turn->username); - uint8_t *password = (uint8_t *)cand->turn->password; - gsize password_len = strlen (cand->turn->password); - StunUsageTurnCompatibility turn_compat = - agent_to_turn_compatibility (agent); - - if (turn_compat == STUN_USAGE_TURN_COMPATIBILITY_MSN || - turn_compat == STUN_USAGE_TURN_COMPATIBILITY_OC2007) { - username = cand->turn->decoded_username; - password = cand->turn->decoded_password; - username_len = cand->turn->decoded_username_len; - password_len = cand->turn->decoded_password_len; - } - - buffer_len = stun_usage_turn_create (&cand->stun_agent, - &cand->stun_message, cand->stun_buffer, sizeof(cand->stun_buffer), - cand->stun_resp_msg.buffer == NULL ? NULL : &cand->stun_resp_msg, - STUN_USAGE_TURN_REQUEST_PORT_NORMAL, - -1, -1, - username, username_len, - password, password_len, - turn_compat); - } - - if (buffer_len > 0 && - agent_socket_send (cand->nicesock, &cand->server, buffer_len, - (gchar *)cand->stun_buffer) >= 0) { - /* case: success, start waiting for the result */ - if (nice_socket_is_reliable (cand->nicesock)) { - stun_timer_start_reliable (&cand->timer, agent->stun_reliable_timeout); - } else { - stun_timer_start (&cand->timer, - agent->stun_initial_timeout, - agent->stun_max_retransmissions); - } - - cand->next_tick = g_get_monotonic_time (); - ++need_pacing; - } else { - /* case: error in starting discovery, start the next discovery */ - nice_debug ("Agent %p : Error starting discovery, skipping the item.", - agent); - cand->done = TRUE; - cand->stun_message.buffer = NULL; - cand->stun_message.buffer_len = 0; - continue; - } - } - else - /* allocate relayed candidates */ - g_assert_not_reached (); - - ++not_done; /* note: new discovery scheduled */ - } - - if (need_pacing) - break; - - if (cand->done != TRUE) { - gint64 now = g_get_monotonic_time (); - - if (cand->stun_message.buffer == NULL) { - nice_debug ("Agent %p : STUN discovery was cancelled, marking discovery done.", agent); - cand->done = TRUE; - } - else if (now >= cand->next_tick) { - switch (stun_timer_refresh (&cand->timer)) { - case STUN_USAGE_TIMER_RETURN_TIMEOUT: - { - /* Time out */ - /* case: error, abort processing */ - StunTransactionId id; - - stun_message_id (&cand->stun_message, id); - stun_agent_forget_transaction (&cand->stun_agent, id); - - cand->done = TRUE; - cand->stun_message.buffer = NULL; - cand->stun_message.buffer_len = 0; - nice_debug ("Agent %p : bind discovery timed out, aborting discovery item.", agent); - break; - } - case STUN_USAGE_TIMER_RETURN_RETRANSMIT: - { - /* case: not ready complete, so schedule next timeout */ - unsigned int timeout = stun_timer_remainder (&cand->timer); - - stun_debug ("STUN transaction retransmitted (timeout %dms).", - timeout); - - /* retransmit */ - agent_socket_send (cand->nicesock, &cand->server, - stun_message_length (&cand->stun_message), - (gchar *)cand->stun_buffer); - - /* note: convert from milli to microseconds for g_time_val_add() */ - cand->next_tick = now + (timeout * 1000); - - ++not_done; /* note: retry later */ - ++need_pacing; - break; - } - case STUN_USAGE_TIMER_RETURN_SUCCESS: - { - unsigned int timeout = stun_timer_remainder (&cand->timer); - - cand->next_tick = now + (timeout * 1000); - - ++not_done; /* note: retry later */ - break; - } - default: - /* Nothing to do. */ - break; - } - - } else { - ++not_done; /* note: discovery not expired yet */ - } - } - - if (need_pacing) - break; - } - - if (not_done == 0) { - nice_debug ("Agent %p : Candidate gathering FINISHED, stopping discovery timer.", agent); - - discovery_free (agent); - - agent_gathering_done (agent); - - /* note: no pending timers, return FALSE to stop timer */ - return FALSE; - } - - return TRUE; -} - -static gboolean priv_discovery_tick_agent_locked (NiceAgent *agent, - gpointer pointer) -{ - gboolean ret; - - ret = priv_discovery_tick_unlocked (agent); - if (ret == FALSE) { - if (agent->discovery_timer_source != NULL) { - g_source_destroy (agent->discovery_timer_source); - g_source_unref (agent->discovery_timer_source); - agent->discovery_timer_source = NULL; - } - } - - return ret; -} - -/* - * Initiates the candidate discovery process by starting - * the necessary timers. - * - * @pre agent->discovery_list != NULL // unsched discovery items available - */ -void discovery_schedule (NiceAgent *agent) -{ - g_assert (agent->discovery_list != NULL); - - if (agent->discovery_unsched_items > 0) { - - if (agent->discovery_timer_source == NULL) { - /* step: run first iteration immediately */ - gboolean res = priv_discovery_tick_unlocked (agent); - if (res == TRUE) { - agent_timeout_add_with_context (agent, &agent->discovery_timer_source, - "Candidate discovery tick", agent->timer_ta, - priv_discovery_tick_agent_locked, NULL); - } - } - } -} diff --git a/agent/discovery.h b/agent/discovery.h deleted file mode 100644 index fd1dfe4..0000000 --- a/agent/discovery.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _NICE_DISCOVERY_H -#define _NICE_DISCOVERY_H - -/* note: this is a private header to libnice */ - -#include "stream.h" -#include "agent.h" - -typedef struct -{ - NiceCandidateType type; /* candidate type STUN or TURN */ - NiceSocket *nicesock; /* XXX: should be taken from local cand: existing socket to use */ - NiceAddress server; /* STUN/TURN server address */ - gint64 next_tick; /* next tick timestamp */ - gboolean pending; /* is discovery in progress? */ - gboolean done; /* is discovery complete? */ - guint stream_id; - guint component_id; - TurnServer *turn; - StunAgent stun_agent; - StunTimer timer; - uint8_t stun_buffer[STUN_MAX_MESSAGE_SIZE_IPV6]; - StunMessage stun_message; - uint8_t stun_resp_buffer[STUN_MAX_MESSAGE_SIZE]; - StunMessage stun_resp_msg; -} CandidateDiscovery; - -typedef struct -{ - NiceSocket *nicesock; /* existing socket to use */ - NiceAddress server; /* STUN/TURN server address */ - NiceCandidate *candidate; /* candidate to refresh */ - guint stream_id; - guint component_id; - StunAgent stun_agent; - GSource *timer_source; - GSource *tick_source; - StunTimer timer; - uint8_t stun_buffer[STUN_MAX_MESSAGE_SIZE_IPV6]; - StunMessage stun_message; - uint8_t stun_resp_buffer[STUN_MAX_MESSAGE_SIZE]; - StunMessage stun_resp_msg; - - gboolean disposing; - GDestroyNotify destroy_cb; - gpointer destroy_cb_data; - GSource *destroy_source; -} CandidateRefresh; - -void refresh_free (NiceAgent *agent, CandidateRefresh *refresh); -void refresh_prune_agent_async (NiceAgent *agent, - NiceTimeoutLockedCallback function, gpointer user_data); -void refresh_prune_stream_async (NiceAgent *agent, NiceStream *stream, - NiceTimeoutLockedCallback function); -void refresh_prune_candidate (NiceAgent *agent, NiceCandidate *candidate); -void refresh_prune_candidate_async (NiceAgent *agent, NiceCandidate *candidate, - NiceTimeoutLockedCallback function); - - -void discovery_free (NiceAgent *agent); -void discovery_prune_stream (NiceAgent *agent, guint stream_id); -void discovery_prune_socket (NiceAgent *agent, NiceSocket *sock); -void discovery_schedule (NiceAgent *agent); - -typedef enum { - HOST_CANDIDATE_SUCCESS, - HOST_CANDIDATE_FAILED, - HOST_CANDIDATE_CANT_CREATE_SOCKET, - HOST_CANDIDATE_REDUNDANT, - HOST_CANDIDATE_DUPLICATE_PORT -} HostCandidateResult; - -HostCandidateResult -discovery_add_local_host_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceAddress *address, - NiceCandidateTransport transport, - NiceCandidate **candidate); - -NiceCandidate* -discovery_add_relay_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceAddress *address, - NiceCandidateTransport transport, - NiceSocket *base_socket, - TurnServer *turn); - -NiceCandidate* -discovery_add_server_reflexive_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceAddress *address, - NiceCandidateTransport transport, - NiceSocket *base_socket, - gboolean nat_assisted); - -void -discovery_discover_tcp_server_reflexive_candidates ( - NiceAgent *agent, - guint stream_id, - guint component_id, - NiceAddress *address, - NiceSocket *base_socket); - -NiceCandidate* -discovery_add_peer_reflexive_candidate ( - NiceAgent *agent, - guint stream_id, - guint component_id, - guint32 priority, - NiceAddress *address, - NiceSocket *base_socket, - NiceCandidate *local, - NiceCandidate *remote); - -NiceCandidate * -discovery_learn_remote_peer_reflexive_candidate ( - NiceAgent *agent, - NiceStream *stream, - NiceComponent *component, - guint32 priority, - const NiceAddress *remote_address, - NiceSocket *udp_socket, - NiceCandidate *local, - NiceCandidate *remote); - -#endif /*_NICE_CONNCHECK_H */ diff --git a/agent/inputstream.c b/agent/inputstream.c deleted file mode 100644 index eafac1b..0000000 --- a/agent/inputstream.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2010, 2013 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/*** - * SECTION:nice_input_stream - * @short_description: #GInputStream implementation for libnice - * @see_also: #NiceAgent - * @include: inputstream.h - * @stability: Stable - * - * #NiceInputStream is a #GInputStream wrapper for a single reliable stream and - * component of a #NiceAgent. Given an existing reliable #NiceAgent, plus the - * IDs of an existing stream and component in the agent, it will provide a - * streaming input interface for reading from the given component. - * - * A single #NiceInputStream can only be used with a single agent, stream and - * component triple, and will be closed as soon as that stream is removed from - * the agent (e.g. if nice_agent_remove_stream() is called from another thread). - * If g_input_stream_close() is called on a #NiceInputStream, the input stream - * and underlying #NiceAgent stream will be closed, but the underlying stream - * will not be removed. Use nice_agent_remove_stream() to do that. - * - * Since: 0.1.5 - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "inputstream.h" -#include "agent-priv.h" - -static void streams_removed_cb (NiceAgent *agent, guint *stream_ids, - gpointer user_data); -static void nice_input_stream_init_pollable ( - GPollableInputStreamInterface *iface); - -G_DEFINE_TYPE_WITH_CODE (NiceInputStream, - nice_input_stream, G_TYPE_INPUT_STREAM, - G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, - nice_input_stream_init_pollable)); - -enum -{ - PROP_AGENT = 1, - PROP_STREAM_ID, - PROP_COMPONENT_ID, -}; - -struct _NiceInputStreamPrivate -{ - GWeakRef/**/ agent_ref; - guint stream_id; - guint component_id; -}; - -static void nice_input_stream_dispose (GObject *object); -static void nice_input_stream_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec); -static void nice_input_stream_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec); -static gssize nice_input_stream_read (GInputStream *stream, void *buffer, - gsize count, GCancellable *cancellable, GError **error); -static gboolean nice_input_stream_close (GInputStream *stream, - GCancellable *cancellable, GError **error); -static gboolean nice_input_stream_is_readable (GPollableInputStream *stream); -static gssize nice_input_stream_read_nonblocking (GPollableInputStream *stream, - void *buffer, gsize count, GError **error); -static GSource *nice_input_stream_create_source (GPollableInputStream *stream, - GCancellable *cancellable); - -static void -nice_input_stream_class_init (NiceInputStreamClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NiceInputStreamPrivate)); - - gobject_class->set_property = nice_input_stream_set_property; - gobject_class->get_property = nice_input_stream_get_property; - gobject_class->dispose = nice_input_stream_dispose; - - stream_class->read_fn = nice_input_stream_read; - stream_class->close_fn = nice_input_stream_close; - - /*** - * NiceInputStream:agent: - * - * The #NiceAgent to wrap with an input stream. This must be an existing - * reliable agent. - * - * A reference is not held on the #NiceAgent. If the agent is destroyed before - * the #NiceInputStream, %G_IO_ERROR_CLOSED will be returned for all - * subsequent operations on the stream. - * - * Since: 0.1.5 - */ - g_object_class_install_property (gobject_class, PROP_AGENT, - g_param_spec_object ("agent", - "NiceAgent", - "The underlying NiceAgent", - NICE_TYPE_AGENT, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /*** - * NiceInputStream:stream-id: - * - * ID of the stream to use in the #NiceInputStream:agent. - * - * Since: 0.1.5 - */ - g_object_class_install_property (gobject_class, PROP_STREAM_ID, - g_param_spec_uint ( - "stream-id", - "Agent’s stream ID", - "The ID of the agent’s stream to wrap.", - 0, G_MAXUINT, - 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /*** - * NiceInputStream:component-id: - * - * ID of the component to use in the #NiceInputStream:agent. - * - * Since: 0.1.5 - */ - g_object_class_install_property (gobject_class, PROP_COMPONENT_ID, - g_param_spec_uint ( - "component-id", - "Agent’s component ID", - "The ID of the agent’s component to wrap.", - 0, G_MAXUINT, - 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -} - -static void -nice_input_stream_dispose (GObject *object) -{ - NiceInputStream *self = NICE_INPUT_STREAM (object); - NiceAgent *agent; - - /* Ensure the stream is closed first, otherwise the agent can’t be found in - * the close handler called by the parent implementation. */ - if (!g_input_stream_is_closed (G_INPUT_STREAM (object))) - g_input_stream_close (G_INPUT_STREAM (object), NULL, NULL); - - agent = g_weak_ref_get (&self->priv->agent_ref); - if (agent != NULL) { - g_signal_handlers_disconnect_by_func (agent, streams_removed_cb, self); - g_object_unref (agent); - } - - g_weak_ref_clear (&self->priv->agent_ref); - - G_OBJECT_CLASS (nice_input_stream_parent_class)->dispose (object); -} - -static void -nice_input_stream_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NiceInputStream *self = NICE_INPUT_STREAM (object); - - switch (prop_id) { - case PROP_AGENT: - g_value_take_object (value, g_weak_ref_get (&self->priv->agent_ref)); - break; - case PROP_STREAM_ID: - g_value_set_uint (value, self->priv->stream_id); - break; - case PROP_COMPONENT_ID: - g_value_set_uint (value, self->priv->component_id); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -nice_input_stream_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NiceInputStream *self = NICE_INPUT_STREAM (object); - - switch (prop_id) { - case PROP_AGENT: { - /* Construct only. */ - NiceAgent *agent = g_value_dup_object (value); - g_weak_ref_set (&self->priv->agent_ref, agent); - - /* agent may be NULL if the stream is being constructed by - * nice_io_stream_get_input_stream() after the NiceIOStream’s agent has - * already been finalised. */ - if (agent != NULL) { - g_signal_connect (agent, "streams-removed", - (GCallback) streams_removed_cb, self); - g_object_unref (agent); - } - - break; - } - case PROP_STREAM_ID: - /* Construct only. */ - self->priv->stream_id = g_value_get_uint (value); - break; - case PROP_COMPONENT_ID: - /* Construct only. */ - self->priv->component_id = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -nice_input_stream_init (NiceInputStream *stream) -{ - stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, NICE_TYPE_INPUT_STREAM, - NiceInputStreamPrivate); - - g_weak_ref_init (&stream->priv->agent_ref, NULL); -} - -static void -nice_input_stream_init_pollable (GPollableInputStreamInterface *iface) -{ - iface->is_readable = nice_input_stream_is_readable; - iface->read_nonblocking = nice_input_stream_read_nonblocking; - iface->create_source = nice_input_stream_create_source; -} - -/*** - * nice_input_stream_new: - * @agent: A #NiceAgent - * @stream_id: The ID of the agent’s stream to wrap - * @component_id: The ID of the agent’s component to wrap - * - * Create a new #NiceInputStream wrapping the given stream/component from - * @agent, which must be a reliable #NiceAgent. - * - * The constructed #NiceInputStream will not hold a reference to @agent. If - * @agent is destroyed before the input stream, %G_IO_ERROR_CLOSED will be - * returned for all subsequent operations on the stream. - * - * Returns: The new #NiceInputStream object - * - * Since: 0.1.5 - */ -NiceInputStream * -nice_input_stream_new (NiceAgent *agent, guint stream_id, guint component_id) -{ - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - g_return_val_if_fail (component_id >= 1, NULL); - - return g_object_new (NICE_TYPE_INPUT_STREAM, - "agent", agent, - "stream-id", stream_id, - "component-id", component_id, - NULL); -} - -static gssize -nice_input_stream_read (GInputStream *stream, void *buffer, gsize count, - GCancellable *cancellable, GError **error) -{ - NiceInputStreamPrivate *priv = NICE_INPUT_STREAM (stream)->priv; - NiceAgent *agent; /* owned */ - gssize len; - - /* Closed streams are not readable. */ - if (g_input_stream_is_closed (stream)) { - return 0; - } - - /* Has the agent disappeared? */ - agent = g_weak_ref_get (&priv->agent_ref); - if (agent == NULL) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, - "Stream is closed due to the NiceAgent being finalised."); - return -1; - } - - len = nice_agent_recv (agent, priv->stream_id, priv->component_id, - buffer, count, cancellable, error); - - g_object_unref (agent); - - return len; -} - -static gboolean -nice_input_stream_close (GInputStream *stream, GCancellable *cancellable, - GError **error) -{ - NiceInputStreamPrivate *priv = NICE_INPUT_STREAM (stream)->priv; - NiceComponent *component = NULL; - NiceStream *_stream = NULL; - NiceAgent *agent; /* owned */ - - /* Has the agent disappeared? */ - agent = g_weak_ref_get (&priv->agent_ref); - if (agent == NULL) - return TRUE; - - agent_lock (agent); - - /* Shut down the read side of the pseudo-TCP stream, if it still exists. */ - if (agent_find_component (agent, priv->stream_id, priv->component_id, - &_stream, &component) && agent->reliable && - !pseudo_tcp_socket_is_closed (component->tcp)) { - pseudo_tcp_socket_shutdown (component->tcp, PSEUDO_TCP_SHUTDOWN_RD); - } - - agent_unlock (agent); - - g_object_unref (agent); - - return TRUE; -} - -static gboolean -nice_input_stream_is_readable (GPollableInputStream *stream) -{ - NiceInputStreamPrivate *priv = NICE_INPUT_STREAM (stream)->priv; - NiceComponent *component = NULL; - NiceStream *_stream = NULL; - gboolean retval = FALSE; - GSList *i; - NiceAgent *agent; /* owned */ - - /* Closed streams are not readable. */ - if (g_input_stream_is_closed (G_INPUT_STREAM (stream))) - return FALSE; - - /* Has the agent disappeared? */ - agent = g_weak_ref_get (&priv->agent_ref); - if (agent == NULL) - return FALSE; - - agent_lock (agent); - - if (!agent_find_component (agent, priv->stream_id, priv->component_id, - &_stream, &component)) { - g_warning ("Could not find component %u in stream %u", priv->component_id, - priv->stream_id); - goto done; - } - - /* If it’s a reliable agent, see if there’s any pending data in the pseudo-TCP - * buffer. */ - if (agent->reliable && - pseudo_tcp_socket_get_available_bytes (component->tcp) > 0) { - retval = TRUE; - goto done; - } - - /* Check whether any of the component’s FDs are pollable. */ - for (i = component->socket_sources; i != NULL; i = i->next) { - SocketSource *socket_source = i->data; - NiceSocket *nicesock = socket_source->socket; - - if (g_socket_condition_check (nicesock->fileno, G_IO_IN) != 0) { - retval = TRUE; - break; - } - } - -done: - agent_unlock (agent); - - g_object_unref (agent); - - return retval; -} - -static gssize -nice_input_stream_read_nonblocking (GPollableInputStream *stream, void *buffer, - gsize count, GError **error) -{ - NiceInputStreamPrivate *priv = NICE_INPUT_STREAM (stream)->priv; - NiceAgent *agent; /* owned */ - gssize len; - - /* Closed streams are not readable. */ - if (g_input_stream_is_closed (G_INPUT_STREAM (stream))) { - return 0; - } - - /* Has the agent disappeared? */ - agent = g_weak_ref_get (&priv->agent_ref); - if (agent == NULL) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, - "Stream is closed due to the NiceAgent being finalised."); - return -1; - } - - len = nice_agent_recv_nonblocking (agent, priv->stream_id, - priv->component_id, (guint8 *) buffer, count, NULL, error); - - g_object_unref (agent); - - return len; -} - -static GSource * -nice_input_stream_create_source (GPollableInputStream *stream, - GCancellable *cancellable) -{ - NiceInputStreamPrivate *priv = NICE_INPUT_STREAM (stream)->priv; - GSource *component_source = NULL; - NiceAgent *agent; /* owned */ - - /* Closed streams cannot have sources. */ - if (g_input_stream_is_closed (G_INPUT_STREAM (stream))) - goto dummy_source; - - /* Has the agent disappeared? */ - agent = g_weak_ref_get (&priv->agent_ref); - if (agent == NULL) - goto dummy_source; - - component_source = nice_component_input_source_new (agent, priv->stream_id, - priv->component_id, stream, cancellable); - - g_object_unref (agent); - - return component_source; - - dummy_source: - - component_source = g_pollable_source_new (G_OBJECT (stream)); - - if (cancellable) { - GSource *cancellable_source = g_cancellable_source_new (cancellable); - - g_source_set_dummy_callback (cancellable_source); - g_source_add_child_source (component_source, cancellable_source); - g_source_unref (cancellable_source); - } - - return component_source; -} - -static void -streams_removed_cb (NiceAgent *agent, guint *stream_ids, gpointer user_data) -{ - NiceInputStream *self = NICE_INPUT_STREAM (user_data); - guint i; - - for (i = 0; stream_ids[i] != 0; i++) { - if (stream_ids[i] == self->priv->stream_id) { - /* The socket has been closed. */ - g_input_stream_close (G_INPUT_STREAM (self), NULL, NULL); - break; - } - } -} diff --git a/agent/inputstream.h b/agent/inputstream.h deleted file mode 100644 index e59dddf..0000000 --- a/agent/inputstream.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2010, 2013 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef __NICE_INPUT_STREAM_H__ -#define __NICE_INPUT_STREAM_H__ - -#include -#include -#include "agent.h" - -G_BEGIN_DECLS - -/* TYPE MACROS */ -#define NICE_TYPE_INPUT_STREAM \ - (nice_input_stream_get_type ()) -#define NICE_INPUT_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NICE_TYPE_INPUT_STREAM, \ - NiceInputStream)) -#define NICE_INPUT_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NICE_TYPE_INPUT_STREAM, \ - NiceInputStreamClass)) -#define NICE_IS_INPUT_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), NICE_TYPE_INPUT_STREAM)) -#define NICE_IS_INPUT_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NICE_TYPE_INPUT_STREAM)) -#define NICE_INPUT_STREAM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), NICE_TYPE_INPUT_STREAM, \ - NiceInputStreamClass)) - - -typedef struct _NiceInputStreamPrivate NiceInputStreamPrivate; -typedef struct _NiceInputStreamClass NiceInputStreamClass; -typedef struct _NiceInputStream NiceInputStream; - -GType nice_input_stream_get_type (void); - -struct _NiceInputStreamClass -{ - GInputStreamClass parent_class; -}; - -struct _NiceInputStream -{ - GInputStream parent_instance; - NiceInputStreamPrivate *priv; -}; - - -NiceInputStream *nice_input_stream_new (NiceAgent *agent, - guint stream_id, guint component_id); - - -G_END_DECLS - -#endif /* __NICE_INPUT_STREAM_H__ */ diff --git a/agent/interfaces.c b/agent/interfaces.c deleted file mode 100644 index 95e64a8..0000000 --- a/agent/interfaces.c +++ /dev/null @@ -1,723 +0,0 @@ -/* - * interfaces.c - Source for interface discovery code - * - * Copyright (C) 2006 Youness Alaoui - * Copyright (C) 2007 Collabora, Nokia - * Contact: Youness Alaoui - * Copyright (C) 2008 Haakon Sporsheim - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * Philip Withnall, Collabora Ltd. - * Haakon Sporsheim - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "interfaces.h" -#include "agent-priv.h" - -#ifdef G_OS_UNIX - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef __sun -#include -#endif - -#ifdef HAVE_GETIFADDRS - #include -#endif - -#include -#include - -#endif /* G_OS_UNIX */ - -#ifdef IGNORED_IFACE_PREFIX -static const gchar *ignored_iface_prefix_list[] = { - IGNORED_IFACE_PREFIX, - NULL -}; -#endif - -#if (defined(G_OS_UNIX) && defined(HAVE_GETIFADDRS)) || defined(G_OS_WIN32) -/* Works on both UNIX and Windows. Magic! */ -static gchar * -sockaddr_to_string (const struct sockaddr *addr) -{ - char addr_as_string[INET6_ADDRSTRLEN+1]; - size_t addr_len; - - switch (addr->sa_family) { - case AF_INET: addr_len = sizeof (struct sockaddr_in); break; - case AF_INET6: addr_len = sizeof (struct sockaddr_in6); break; - default: return NULL; - } - - if (getnameinfo (addr, addr_len, - addr_as_string, sizeof (addr_as_string), NULL, 0, - NI_NUMERICHOST) != 0) { - return NULL; - } - - return g_strdup (addr_as_string); -} -#endif - -#ifdef G_OS_UNIX - -static GList * -get_local_interfaces_ioctl (void) -{ - GList *interfaces = NULL; - gint sockfd; - gint size = 0; - struct ifreq *ifr; - struct ifconf ifc; - - if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) { - nice_debug ("error : Cannot open socket to retrieve interface list"); - return NULL; - } - - ifc.ifc_len = 0; - ifc.ifc_req = NULL; - - /* Loop and get each interface the system has, one by one... */ - do { - size += sizeof (struct ifreq); - /* realloc buffer size until no overflow occurs */ - if (NULL == (ifc.ifc_req = realloc (ifc.ifc_req, size))) { - nice_debug ("Error : Out of memory while allocation interface" - "configuration structure"); - close (sockfd); - return NULL; - } - ifc.ifc_len = size; - - if (ioctl (sockfd, SIOCGIFCONF, &ifc)) { - perror ("ioctl SIOCFIFCONF"); - close (sockfd); - free (ifc.ifc_req); - return NULL; - } - } while (size <= ifc.ifc_len); - - - /* Loop throught the interface list and get the IP address of each IF */ - for (ifr = ifc.ifc_req; - (gchar *) ifr < (gchar *) ifc.ifc_req + ifc.ifc_len; - ++ifr) { - nice_debug ("Found interface : %s", ifr->ifr_name); - interfaces = g_list_prepend (interfaces, g_strdup (ifr->ifr_name)); - } - - free (ifc.ifc_req); - close (sockfd); - - return interfaces; -} - -#ifdef HAVE_GETIFADDRS - -GList * -nice_interfaces_get_local_interfaces (void) -{ - GList *interfaces = NULL; - struct ifaddrs *ifa, *results; - - if (getifaddrs (&results) < 0) { - nice_debug ("Failed to retrieve list of network interfaces with \"getifaddrs\": %s." - "Trying to use fallback ...", strerror (errno)); - return get_local_interfaces_ioctl (); - } - - /* Loop and get each interface the system has, one by one... */ - for (ifa = results; ifa; ifa = ifa->ifa_next) { - /* no ip address from interface that is down */ - if ((ifa->ifa_flags & IFF_UP) == 0) - continue; - - if (ifa->ifa_addr == NULL) - continue; - - if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) { - nice_debug ("Found interface : %s", ifa->ifa_name); - interfaces = g_list_prepend (interfaces, g_strdup (ifa->ifa_name)); - } - } - - freeifaddrs (results); - - return interfaces; -} - -#else /* ! HAVE_GETIFADDRS */ - -GList * -nice_interfaces_get_local_interfaces (void) -{ - return get_local_interfaces_ioctl (); -} - -#endif /* HAVE_GETIFADDRS */ - - -static gboolean -nice_interfaces_is_private_ip (const struct sockaddr *sa) -{ - NiceAddress niceaddr; - - nice_address_init (&niceaddr); - nice_address_set_from_sockaddr (&niceaddr, sa); - return nice_address_is_private (&niceaddr); -} - -static GList * -add_ip_to_list (GList *list, gchar *ip, gboolean append) -{ - GList *i; - - for (i = list; i; i = i->next) { - gchar *addr = (gchar *) i->data; - - if (g_strcmp0 (addr, ip) == 0) - return list; - } - if (append) - return g_list_append (list, ip); - else - return g_list_prepend (list, ip); -} - -static GList * -get_local_ips_ioctl (gboolean include_loopback) -{ - GList *ips = NULL; - gint sockfd; - gint size = 0; - struct ifreq *ifr; - struct ifconf ifc; - union { - struct sockaddr_in *sin; - struct sockaddr *sa; - } sa; - - GList *loopbacks = NULL; -#ifdef IGNORED_IFACE_PREFIX - const gchar **prefix; - gboolean ignored; -#endif - - if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) { - nice_debug ("Error : Cannot open socket to retrieve interface list"); - return NULL; - } - - ifc.ifc_len = 0; - ifc.ifc_req = NULL; - - /* Loop and get each interface the system has, one by one... */ - do { - size += sizeof (struct ifreq); - /* realloc buffer size until no overflow occurs */ - if (NULL == (ifc.ifc_req = realloc (ifc.ifc_req, size))) { - nice_debug ("Error : Out of memory while allocation interface" - " configuration structure"); - close (sockfd); - return NULL; - } - ifc.ifc_len = size; - - if (ioctl (sockfd, SIOCGIFCONF, &ifc)) { - perror ("ioctl SIOCFIFCONF"); - close (sockfd); - free (ifc.ifc_req); - return NULL; - } - } while (size <= ifc.ifc_len); - - - /* Loop throught the interface list and get the IP address of each IF */ - for (ifr = ifc.ifc_req; - (gchar *) ifr < (gchar *) ifc.ifc_req + ifc.ifc_len; - ++ifr) { - - if (ioctl (sockfd, SIOCGIFFLAGS, ifr)) { - nice_debug ("Error : Unable to get IP information for interface %s." - " Skipping...", ifr->ifr_name); - continue; /* failed to get flags, skip it */ - } - - /* no ip address from interface that is down */ - if ((ifr->ifr_flags & IFF_UP) == 0) - continue; - - /* no ip address from interface that isn't running */ - if ((ifr->ifr_flags & IFF_RUNNING) == 0) - continue; - - sa.sa = &ifr->ifr_addr; - nice_debug ("Interface: %s", ifr->ifr_name); - nice_debug ("IP Address: %s", inet_ntoa (sa.sin->sin_addr)); - if ((ifr->ifr_flags & IFF_LOOPBACK) == IFF_LOOPBACK){ - if (include_loopback) - loopbacks = add_ip_to_list (loopbacks, g_strdup (inet_ntoa (sa.sin->sin_addr)), TRUE); - else - nice_debug ("Ignoring loopback interface"); - continue; - } - -#ifdef IGNORED_IFACE_PREFIX - ignored = FALSE; - for (prefix = ignored_iface_prefix_list; *prefix; prefix++) { - if (g_str_has_prefix (ifr->ifr_name, *prefix)) { - nice_debug ("Ignoring interface %s as it matches prefix %s", - ifr->ifr_name, *prefix); - ignored = TRUE; - break; - } - } - - if (ignored) - continue; -#endif - - if (nice_interfaces_is_private_ip (sa.sa)) { - ips = add_ip_to_list (ips, g_strdup (inet_ntoa (sa.sin->sin_addr)), TRUE); - } else { - ips = add_ip_to_list (ips, g_strdup (inet_ntoa (sa.sin->sin_addr)), FALSE); - } - } - - close (sockfd); - free (ifc.ifc_req); - - if (loopbacks) - ips = g_list_concat (ips, loopbacks); - - return ips; -} - -#ifdef HAVE_GETIFADDRS - -GList * -nice_interfaces_get_local_ips (gboolean include_loopback) -{ - GList *ips = NULL; - struct ifaddrs *ifa, *results; - GList *loopbacks = NULL; -#ifdef IGNORED_IFACE_PREFIX - const gchar **prefix; - gboolean ignored; -#endif - - if (getifaddrs (&results) < 0) { - nice_debug ("Failed to retrieve list of network interfaces with \"getifaddrs\": %s." - "Trying to use fallback ...", strerror (errno)); - return get_local_ips_ioctl (include_loopback); - } - - /* Loop through the interface list and get the IP address of each IF */ - for (ifa = results; ifa; ifa = ifa->ifa_next) { - gchar *addr_string; - - /* no ip address from interface that is down */ - if ((ifa->ifa_flags & IFF_UP) == 0) - continue; - - /* no ip address from interface that isn't running */ - if ((ifa->ifa_flags & IFF_RUNNING) == 0) - continue; - - if (ifa->ifa_addr == NULL) - continue; - - /* Convert to a string. */ - addr_string = sockaddr_to_string (ifa->ifa_addr); - if (addr_string == NULL) { - nice_debug ("Failed to convert address to string for interface ‘%s’.", - ifa->ifa_name); - continue; - } - - nice_debug ("Interface: %s", ifa->ifa_name); - nice_debug ("IP Address: %s", addr_string); - if ((ifa->ifa_flags & IFF_LOOPBACK) == IFF_LOOPBACK) { - if (include_loopback) { - loopbacks = add_ip_to_list (loopbacks, addr_string, TRUE); - } else { - nice_debug ("Ignoring loopback interface"); - g_free (addr_string); - } - continue; - } - -#ifdef IGNORED_IFACE_PREFIX - ignored = FALSE; - for (prefix = ignored_iface_prefix_list; *prefix; prefix++) { - if (g_str_has_prefix (ifa->ifa_name, *prefix)) { - nice_debug ("Ignoring interface %s as it matches prefix %s", - ifa->ifa_name, *prefix); - g_free (addr_string); - ignored = TRUE; - break; - } - } - - if (ignored) - continue; -#endif - - if (nice_interfaces_is_private_ip (ifa->ifa_addr)) - ips = add_ip_to_list (ips, addr_string, TRUE); - else - ips = add_ip_to_list (ips, addr_string, FALSE); - } - - freeifaddrs (results); - - if (loopbacks) - ips = g_list_concat (ips, loopbacks); - - return ips; -} - -#else /* ! HAVE_GETIFADDRS */ - -GList * -nice_interfaces_get_local_ips (gboolean include_loopback) -{ - return get_local_ips_ioctl (include_loopback); -} - -#endif /* HAVE_GETIFADDRS */ - -gchar * -nice_interfaces_get_ip_for_interface (gchar *interface_name) -{ - struct ifreq ifr; - union { - struct sockaddr *addr; - struct sockaddr_in *in; - } sa; - gint sockfd; - - g_return_val_if_fail (interface_name != NULL, NULL); - - ifr.ifr_addr.sa_family = AF_INET; - memset (ifr.ifr_name, 0, sizeof (ifr.ifr_name)); - g_strlcpy (ifr.ifr_name, interface_name, sizeof (ifr.ifr_name)); - - if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) { - nice_debug ("Error : Cannot open socket to retrieve interface list"); - return NULL; - } - - if (ioctl (sockfd, SIOCGIFADDR, &ifr) < 0) { - nice_debug ("Error : Unable to get IP information for interface %s", - interface_name); - close (sockfd); - return NULL; - } - - close (sockfd); - sa.addr = &ifr.ifr_addr; - nice_debug ("Address for %s: %s", interface_name, inet_ntoa (sa.in->sin_addr)); - return g_strdup (inet_ntoa (sa.in->sin_addr)); -} - -#else /* G_OS_UNIX */ -#ifdef G_OS_WIN32 - -#include -#include - -// Should be in Iphlpapi.h, but mingw doesn't seem to have these -// Values copied directly from: -// http://msdn.microsoft.com/en-us/library/aa366845(v=vs.85).aspx -// (Title: MIB_IPADDRROW structure) - -#ifndef MIB_IPADDR_DISCONNECTED -#define MIB_IPADDR_DISCONNECTED 0x0008 -#endif - -#ifndef MIB_IPADDR_DELETED -#define MIB_IPADDR_DELETED 0x0040 -#endif - -#if 0 -static gboolean started_wsa_engine = FALSE; - -/* - * private function that initializes the WinSock engine and - * returns a prebuilt socket - */ -SOCKET nice_interfaces_get_WSA_socket () -{ - WORD wVersionRequested; - WSADATA wsaData; - int err; - SOCKET sock; - - if (started_wsa_engine == FALSE) { - wVersionRequested = MAKEWORD ( 2, 0 ); - - err = WSAStartup ( wVersionRequested, &wsaData ); - if ( err != 0 ) { - nice_debug ("Error : Could not start the winsocket engine"); - return INVALID_SOCKET; - } - started_wsa_engine = TRUE; - } - - - if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { - nice_debug ("Error : Could not open socket to retrieve interface list," - " error no : %d", WSAGetLastError ()); - return INVALID_SOCKET; - } - - return sock; -} -#endif - -GList * nice_interfaces_get_local_interfaces (void) -{ - ULONG size = 0; - PMIB_IFTABLE if_table; - GList * ret = NULL; - - GetIfTable(NULL, &size, TRUE); - - if (!size) - return NULL; - - if_table = (PMIB_IFTABLE)g_malloc0(size); - - if (GetIfTable(if_table, &size, TRUE) == ERROR_SUCCESS) { - DWORD i; - for (i = 0; i < if_table->dwNumEntries; i++) { - ret = g_list_prepend (ret, g_strdup ((gchar*)if_table->table[i].bDescr)); - } - } - - g_free(if_table); - - return ret; -} - -GList * nice_interfaces_get_local_ips (gboolean include_loopback) -{ - IP_ADAPTER_ADDRESSES *addresses = NULL, *a; - ULONG status; - guint iterations; - ULONG addresses_size; - DWORD pref = 0; - GList *ret = NULL; - - /* As suggested on - * http://msdn.microsoft.com/en-gb/library/windows/desktop/aa365915%28v=vs.85%29.aspx */ - #define MAX_TRIES 3 - #define INITIAL_BUFFER_SIZE 15000 - - addresses_size = INITIAL_BUFFER_SIZE; - iterations = 0; - - do { - g_free (addresses); - addresses = g_malloc0 (addresses_size); - - status = GetAdaptersAddresses (AF_UNSPEC, - GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | - GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &addresses_size); - } while ((status == ERROR_BUFFER_OVERFLOW) && (iterations++ < MAX_TRIES)); - - nice_debug ("Queried addresses with status %lu.", status); - - #undef INITIAL_BUFFER_SIZE - #undef MAX_TRIES - - /* Error? */ - if (status != NO_ERROR) { - nice_debug ("Error retrieving local addresses (error code %lu).", status); - g_free (addresses); - return NULL; - } - - /* - * Get the best interface for transport to 0.0.0.0. - * This interface should be first in list! - */ - if (GetBestInterface (0, &pref) != NO_ERROR) - pref = 0; - - /* Loop over the adapters. */ - for (a = addresses; a != NULL; a = a->Next) { - IP_ADAPTER_UNICAST_ADDRESS *unicast; - - nice_debug ("Interface ‘%S’:", a->FriendlyName); - - /* Various conditions for ignoring the interface. */ - if (a->Flags & IP_ADAPTER_RECEIVE_ONLY || - a->OperStatus == IfOperStatusDown || - a->OperStatus == IfOperStatusNotPresent || - a->OperStatus == IfOperStatusLowerLayerDown) { - nice_debug ("Rejecting interface due to being down or read-only."); - continue; - } - - if (!include_loopback && - a->IfType == IF_TYPE_SOFTWARE_LOOPBACK) { - nice_debug ("Rejecting loopback interface ‘%S’.", a->FriendlyName); - continue; - } - - /* Grab the interface’s unicast addresses. */ - for (unicast = a->FirstUnicastAddress; - unicast != NULL; unicast = unicast->Next) { - gchar *addr_string; - - addr_string = sockaddr_to_string (unicast->Address.lpSockaddr); - if (addr_string == NULL) { - nice_debug ("Failed to convert address to string for interface ‘%S’.", - a->FriendlyName); - continue; - } - - nice_debug ("IP address: %s", addr_string); - - if (a->IfIndex == pref || a->Ipv6IfIndex == pref) - ret = g_list_prepend (ret, addr_string); - else - ret = g_list_append (ret, addr_string); - } - } - - g_free (addresses); - - return ret; -} - -/* - * returns ip address as an utf8 string - */ -// Source for idx's type (Was IF_INDEX): -// http://msdn.microsoft.com/en-us/library/aa366836(v=VS.85).aspx -// (Title: MIB_IFROW structure) -static gchar * -win32_get_ip_for_interface (DWORD idx) -{ - ULONG size = 0; - PMIB_IPADDRTABLE ip_table; - gchar * ret = NULL; - - GetIpAddrTable (NULL, &size, TRUE); - - if (!size) - return NULL; - - ip_table = (PMIB_IPADDRTABLE)g_malloc0 (size); - - if (GetIpAddrTable (ip_table, &size, TRUE) == ERROR_SUCCESS) { - DWORD i; - for (i = 0; i < ip_table->dwNumEntries; i++) { - PMIB_IPADDRROW ipaddr = &ip_table->table[i]; - if (ipaddr->dwIndex == idx && - !(ipaddr->wType & (MIB_IPADDR_DISCONNECTED | MIB_IPADDR_DELETED))) { - ret = g_strdup_printf ("%lu.%lu.%lu.%lu", - (ipaddr->dwAddr ) & 0xFF, - (ipaddr->dwAddr >> 8) & 0xFF, - (ipaddr->dwAddr >> 16) & 0xFF, - (ipaddr->dwAddr >> 24) & 0xFF); - break; - } - } - } - - g_free (ip_table); - return ret; -} - -gchar * nice_interfaces_get_ip_for_interface (gchar *interface_name) -{ - ULONG size = 0; - PMIB_IFTABLE if_table; - gchar * ret = NULL; - - GetIfTable (NULL, &size, TRUE); - - if (!size) - return NULL; - - if_table = (PMIB_IFTABLE)g_malloc0 (size); - - if (GetIfTable (if_table, &size, TRUE) == ERROR_SUCCESS) { - DWORD i; - gchar * tmp_str; - for (i = 0; i < if_table->dwNumEntries; i++) { - tmp_str = g_utf16_to_utf8 ( - if_table->table[i].wszName, MAX_INTERFACE_NAME_LEN, - NULL, NULL, NULL); - - if (strlen (interface_name) == strlen (tmp_str) && - g_ascii_strncasecmp (interface_name, tmp_str, strlen (interface_name)) == 0) { - ret = win32_get_ip_for_interface (if_table->table[i].dwIndex); - g_free (tmp_str); - break; - } - - g_free (tmp_str); - } - } - - g_free (if_table); - - return ret; -} - - -#else /* G_OS_WIN32 */ -#error Can not use this method for retreiving ip list from OS other than unix or windows -#endif /* G_OS_WIN32 */ -#endif /* G_OS_UNIX */ diff --git a/agent/interfaces.h b/agent/interfaces.h deleted file mode 100644 index 50c627e..0000000 --- a/agent/interfaces.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * interfaces.h - Source for interface discovery code - * - * Farsight Helper functions - * Copyright (C) 2006 Youness Alaoui - * Copyright (C) 2008-2009 Collabora, Nokia - * Contact: Youness Alaoui - * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LIBNICE_INTERFACES_H__ -#define __LIBNICE_INTERFACES_H__ - -/** - * SECTION:interfaces - * @short_description: Utility functions to discover local network interfaces - * @include: interfaces.h - * @stability: Stable - * - * These utility functions allow the discovery of local network interfaces - * in a portable manner, they also allow finding the local ip addresses or - * the address allocated to a network interface. - */ - -#include - -G_BEGIN_DECLS - - -/** - * nice_interfaces_get_ip_for_interface: - * @interface_name: name of local interface - * - * Retrieves the IP address of an interface by its name. If this fails, %NULL - * is returned. - * - * Returns: (nullable) (transfer full): a newly-allocated string with the IP - * address - */ -gchar * nice_interfaces_get_ip_for_interface (gchar *interface_name); - - -/** - * nice_interfaces_get_local_ips: - * @include_loopback: Include any loopback devices - * - * Get a list of local ipv4 interface addresses - * - * Returns: (element-type utf8) (transfer full): a newly-allocated #GList of - * strings. The caller must free it. - */ - -GList * nice_interfaces_get_local_ips (gboolean include_loopback); - - -/** - * nice_interfaces_get_local_interfaces: - * - * Get the list of local interfaces - * - * Returns: (element-type utf8) (transfer full): a newly-allocated #GList of - * strings. The caller must free it. - */ -GList * nice_interfaces_get_local_interfaces (void); - -G_END_DECLS - -#endif /* __LIBNICE_INTERFACES_H__ */ diff --git a/agent/iostream.c b/agent/iostream.c deleted file mode 100644 index f22ee45..0000000 --- a/agent/iostream.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2010, 2013 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/*** - * SECTION:nice_io_stream - * @short_description: #GIOStream implementation for libnice - * @see_also: #NiceAgent - * @include: iostream.h - * @stability: Stable - * - * #NiceIOStream is a #GIOStream wrapper for a single reliable stream and - * component of a #NiceAgent. Given an existing reliable #NiceAgent, plus the - * IDs of an existing stream and component in the agent, it will provide a - * streaming input and output interface for communication over the given - * component. - * - * A single #NiceIOStream can only be used with a single agent, stream and - * component triple, and will be closed as soon as that stream is removed from - * the agent (e.g. if nice_agent_remove_stream() is called from another thread). - * If g_io_stream_close() is called on a #NiceIOStream, the I/O stream and - * underlying #NiceAgent stream will be closed in both directions, but the - * underlying stream will not be removed. Use nice_agent_remove_stream() to do - * that, but only do so after g_io_stream_close() has completed, or the stream - * will return broken pipe errors. - * - * Since: 0.1.5 - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "iostream.h" -#include "inputstream.h" -#include "outputstream.h" - -G_DEFINE_TYPE (NiceIOStream, nice_io_stream, G_TYPE_IO_STREAM); - -enum -{ - PROP_AGENT = 1, - PROP_STREAM_ID, - PROP_COMPONENT_ID, -}; - -struct _NiceIOStreamPrivate -{ - GWeakRef/**/ agent_ref; - guint stream_id; - guint component_id; - - GInputStream *input_stream; /* owned */ - GOutputStream *output_stream; /* owned */ -}; - -static void nice_io_stream_dispose (GObject *object); -static void nice_io_stream_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec); -static void nice_io_stream_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec); -static GInputStream *nice_io_stream_get_input_stream (GIOStream *stream); -static GOutputStream *nice_io_stream_get_output_stream (GIOStream *stream); - -static void streams_removed_cb (NiceAgent *agent, guint *stream_ids, - gpointer user_data); - -static void -nice_io_stream_class_init (NiceIOStreamClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NiceIOStreamPrivate)); - - gobject_class->set_property = nice_io_stream_set_property; - gobject_class->get_property = nice_io_stream_get_property; - gobject_class->dispose = nice_io_stream_dispose; - - stream_class->get_input_stream = nice_io_stream_get_input_stream; - stream_class->get_output_stream = nice_io_stream_get_output_stream; - - /* - * NiceIOStream:agent: - * - * The #NiceAgent to wrap with an I/O stream. This must be an existing - * reliable agent. - * - * A reference is not held on the #NiceAgent. If the agent is destroyed before - * the #NiceIOStream, %G_IO_ERROR_CLOSED will be returned for all subsequent - * operations on the stream. - * - * Since: 0.1.5 - */ - g_object_class_install_property (gobject_class, PROP_AGENT, - g_param_spec_object ("agent", - "NiceAgent", - "The underlying NiceAgent", - NICE_TYPE_AGENT, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /* - * NiceIOStream:stream-id: - * - * ID of the stream to use in the #NiceIOStream:agent. - * - * Since: 0.1.5 - */ - g_object_class_install_property (gobject_class, PROP_STREAM_ID, - g_param_spec_uint ( - "stream-id", - "Agent’s stream ID", - "The ID of the agent’s stream to wrap.", - 0, G_MAXUINT, - 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /* - * NiceIOStream:component-id: - * - * ID of the component to use in the #NiceIOStream:agent. - * - * Since: 0.1.5 - */ - g_object_class_install_property (gobject_class, PROP_COMPONENT_ID, - g_param_spec_uint ( - "component-id", - "Agent’s component ID", - "The ID of the agent’s component to wrap.", - 0, G_MAXUINT, - 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -} - -static void -nice_io_stream_init (NiceIOStream *self) -{ - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NICE_TYPE_IO_STREAM, - NiceIOStreamPrivate); - - g_weak_ref_init (&self->priv->agent_ref, NULL); - - /* Invalidate the stream/component IDs to begin with. */ - self->priv->stream_id = 0; - self->priv->component_id = 0; -} - -static void -nice_io_stream_dispose (GObject *object) -{ - NiceIOStream *self = NICE_IO_STREAM (object); - NiceAgent *agent; - - /* Ensure the stream is closed before continuing. Otherwise, if the input or - * output streams haven’t yet been lazily created, closing the stream in - * g_io_stream_dispose() will lazily create them, but NiceAgent will be NULL - * by that point and things will explode. */ - if (!g_io_stream_is_closed (G_IO_STREAM (object))) - g_io_stream_close (G_IO_STREAM (object), NULL, NULL); - - /* Clear everything away. */ - if (self->priv->input_stream != NULL) - g_object_unref (self->priv->input_stream); - self->priv->input_stream = NULL; - - if (self->priv->output_stream != NULL) - g_object_unref (self->priv->output_stream); - self->priv->output_stream = NULL; - - agent = g_weak_ref_get (&self->priv->agent_ref); - if (agent != NULL) { - g_signal_handlers_disconnect_by_func (agent, streams_removed_cb, self); - g_object_unref (agent); - } - - g_weak_ref_clear (&self->priv->agent_ref); - - G_OBJECT_CLASS (nice_io_stream_parent_class)->dispose (object); -} - -static void -nice_io_stream_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NiceIOStream *self = NICE_IO_STREAM (object); - - switch (prop_id) { - case PROP_AGENT: - g_value_take_object (value, g_weak_ref_get (&self->priv->agent_ref)); - break; - case PROP_STREAM_ID: - g_value_set_uint (value, self->priv->stream_id); - break; - case PROP_COMPONENT_ID: - g_value_set_uint (value, self->priv->component_id); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -nice_io_stream_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NiceIOStream *self = NICE_IO_STREAM (object); - - switch (prop_id) { - case PROP_AGENT: { - /* Construct only. */ - NiceAgent *agent = g_value_dup_object (value); - g_weak_ref_set (&self->priv->agent_ref, agent); - g_signal_connect (agent, "streams-removed", - (GCallback) streams_removed_cb, self); - g_object_unref (agent); - - break; - } - case PROP_STREAM_ID: - /* Construct only. */ - self->priv->stream_id = g_value_get_uint (value); - break; - case PROP_COMPONENT_ID: - /* Construct only. */ - self->priv->component_id = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -/*** - * nice_io_stream_new: - * @agent: A #NiceAgent - * @stream_id: The ID of the agent’s stream to wrap - * @component_id: The ID of the agent’s component to wrap - * - * Create a new #NiceIOStream wrapping the given stream/component from @agent, - * which must be a reliable #NiceAgent. - * - * The constructed #NiceIOStream will not hold a reference to @agent. If @agent - * is destroyed before the I/O stream, %G_IO_ERROR_CLOSED will be returned for - * all subsequent operations on the stream. - * - * Returns: The new #NiceIOStream object - * - * Since: 0.1.5 - */ -GIOStream * -nice_io_stream_new (NiceAgent *agent, guint stream_id, guint component_id) -{ - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id > 0, NULL); - g_return_val_if_fail (component_id > 0, NULL); - - return g_object_new (NICE_TYPE_IO_STREAM, - "agent", agent, - "stream-id", stream_id, - "component-id", component_id, - NULL); -} - -static GInputStream * -nice_io_stream_get_input_stream (GIOStream *stream) -{ - NiceIOStream *self = NICE_IO_STREAM (stream); - - if (G_UNLIKELY (self->priv->input_stream == NULL)) { - NiceAgent *agent; - - /* Note that agent may be NULL here. NiceInputStream must support - * construction with a NULL agent. */ - agent = g_weak_ref_get (&self->priv->agent_ref); - self->priv->input_stream = G_INPUT_STREAM (nice_input_stream_new ( - agent, self->priv->stream_id, self->priv->component_id)); - if (agent != NULL) - g_object_unref (agent); - } - - return self->priv->input_stream; -} - -static GOutputStream * -nice_io_stream_get_output_stream (GIOStream *stream) -{ - NiceIOStream *self = NICE_IO_STREAM (stream); - - if (G_UNLIKELY (self->priv->output_stream == NULL)) { - NiceAgent *agent; - - /* Note that agent may be NULL here. NiceOutputStream must support - * construction with a NULL agent. */ - agent = g_weak_ref_get (&self->priv->agent_ref); - self->priv->output_stream = g_object_new (NICE_TYPE_OUTPUT_STREAM, - "agent", agent, - "stream-id", self->priv->stream_id, - "component-id", self->priv->component_id, - NULL); - - if (agent != NULL) - g_object_unref (agent); - } - - return self->priv->output_stream; -} - -static void -streams_removed_cb (NiceAgent *agent, guint *stream_ids, gpointer user_data) -{ - NiceIOStream *self = NICE_IO_STREAM (user_data); - guint i; - - for (i = 0; stream_ids[i] != 0; i++) { - if (stream_ids[i] == self->priv->stream_id) { - /* The socket has been closed. */ - g_io_stream_close (G_IO_STREAM (self), NULL, NULL); - break; - } - } -} diff --git a/agent/iostream.h b/agent/iostream.h deleted file mode 100644 index ad5b959..0000000 --- a/agent/iostream.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2010, 2013 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef __NICE_IO_STREAM_H__ -#define __NICE_IO_STREAM_H__ - -#include -#include - -G_BEGIN_DECLS - -/* TYPE MACROS */ - -/* IO Stream */ -#define NICE_TYPE_IO_STREAM \ - (nice_io_stream_get_type ()) -#define NICE_IO_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NICE_TYPE_IO_STREAM, \ - NiceIOStream)) -#define NICE_IO_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NICE_TYPE_IO_STREAM, \ - NiceIOStreamClass)) -#define NICE_IS_IO_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), NICE_TYPE_IO_STREAM)) -#define NICE_IS_IO_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NICE_TYPE_IO_STREAM)) -#define NICE_IO_STREAM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), NICE_TYPE_IO_STREAM, \ - NiceIOStreamClass)) - -/* IO Stream */ -typedef struct _NiceIOStreamPrivate NiceIOStreamPrivate; -typedef struct _NiceIOStreamClass NiceIOStreamClass; -typedef struct _NiceIOStream NiceIOStream; - -#include "agent.h" -#include "inputstream.h" -#include "outputstream.h" - -/* IO Stream */ -GType nice_io_stream_get_type (void); - -struct _NiceIOStreamClass -{ - GIOStreamClass parent_class; -}; - -struct _NiceIOStream -{ - GIOStream parent_instance; - NiceIOStreamPrivate *priv; -}; - -GIOStream *nice_io_stream_new (NiceAgent *agent, - guint stream_id, guint component_id); - -G_END_DECLS - -#endif /* __NICE_IO_STREAM_H__ */ diff --git a/agent/meson.build b/agent/meson.build deleted file mode 100644 index 2e5b272..0000000 --- a/agent/meson.build +++ /dev/null @@ -1,49 +0,0 @@ -agent_headers = files([ - 'address.h', - 'agent.h', - 'candidate.h', - 'debug.h', - 'interfaces.h', - 'pseudotcp.h', -]) -install_headers(agent_headers, subdir : 'nice') -agent_include = include_directories('.') - -agent_sources = files([ - 'address.c', - 'agent.c', - 'candidate.c', - 'component.c', - 'conncheck.c', - 'debug.c', - 'discovery.c', - 'inputstream.c', - 'interfaces.c', - 'iostream.c', - 'outputstream.c', - 'pseudotcp.c', - 'stream.c', -]) - -gnome = import('gnome') - -agent_enum_types_c = gnome.mkenums('agent-enum-types.c', sources : agent_headers, - fhead: '#include \n#include \n#include "agent.h"\n#include "pseudotcp.h"\n#include "agent-enum-types.h"', - fprod: '\n/* enumerations from "@filename@" */', - vhead: 'GType\n@enum_name@_get_type (void)\n{\n static GType type = 0;\n if (!type) {\n static const G@Type@Value values[] = {', - vprod: ' { @VALUENAME@, "@VALUENAME@", "@valuenick@" },', - vtail: ' { 0, NULL, NULL }\n };\n type = g_@type@_register_static ("@EnumName@", values);\n }\n return type;\n}\n\n') - -agent_enum_types_h = gnome.mkenums('agent-enum-types.h', sources : agent_headers, - fhead: '#ifndef __AGENT_ENUM_TYPES_H__\n#define __AGENT_ENUM_TYPES_H__ 1\n\n#include \n\nG_BEGIN_DECLS\n', - fprod: '/* enumerations from "@filename@" */\n', - vhead: 'GType @enum_name@_get_type (void) G_GNUC_CONST;\n#define NICE_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n', - ftail: 'G_END_DECLS\n\n#endif /* !AGENT_ENUM_TYPES_H */') - - -libagent = static_library('agent', - agent_enum_types_c, agent_enum_types_h, agent_sources, - c_args: ['-DG_LOG_DOMAIN="libnice"'], - include_directories: nice_incs, - dependencies: nice_deps, - install: false) diff --git a/agent/outputstream.c b/agent/outputstream.c deleted file mode 100644 index 94be750..0000000 --- a/agent/outputstream.c +++ /dev/null @@ -1,663 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2010, 2013 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/*** - * SECTION:nice_output_stream - * @short_description: #GOutputStream implementation for libnice - * @see_also: #NiceAgent - * @include: outputstream.h - * @stability: Stable - * - * #NiceOutputStream is a #GOutputStream wrapper for a single reliable stream - * and component of a #NiceAgent. Given an existing reliable #NiceAgent, plus - * the IDs of an existing stream and component in the agent, it will provide a - * streaming output interface for writing to the given component. - * - * A single #NiceOutputStream can only be used with a single agent, stream and - * component triple, and will be closed as soon as that stream is removed from - * the agent (e.g. if nice_agent_remove_stream() is called from another thread). - * If g_output_stream_close() is called on a #NiceOutputStream, the output - * stream and underlying #NiceAgent stream will be closed, but the underlying - * stream will not be removed. Use nice_agent_remove_stream() to do that. - * - * The output stream can only be used once the - * #NiceAgent::reliable-transport-writable signal has been received for the - * stream/component pair. Any calls to g_output_stream_write() before then will - * return %G_IO_ERROR_BROKEN_PIPE. - * - * Since: 0.1.5 - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "outputstream.h" -#include "agent-priv.h" - -static void nice_output_stream_init_pollable ( - GPollableOutputStreamInterface *iface); -static void streams_removed_cb (NiceAgent *agent, guint *stream_ids, - gpointer user_data); - -G_DEFINE_TYPE_WITH_CODE (NiceOutputStream, - nice_output_stream, G_TYPE_OUTPUT_STREAM, - G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM, - nice_output_stream_init_pollable)); - -enum -{ - PROP_AGENT = 1, - PROP_STREAM_ID, - PROP_COMPONENT_ID, -}; - -struct _NiceOutputStreamPrivate -{ - GWeakRef/**/ agent_ref; - guint stream_id; - guint component_id; - - GCancellable *closed_cancellable; -}; - -static void nice_output_stream_dispose (GObject *object); -static void nice_output_stream_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec); -static void nice_output_stream_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec); - -static gssize nice_output_stream_write (GOutputStream *stream, - const void *buffer, gsize count, GCancellable *cancellable, GError **error); -static gboolean nice_output_stream_close (GOutputStream *stream, - GCancellable *cancellable, GError **error); - -static gboolean nice_output_stream_is_writable (GPollableOutputStream *stream); -static gssize nice_output_stream_write_nonblocking ( - GPollableOutputStream *stream, const void *buffer, gsize count, - GError **error); -static GSource *nice_output_stream_create_source (GPollableOutputStream *stream, - GCancellable *cancellable); - -/* Output Stream */ -static void -nice_output_stream_class_init (NiceOutputStreamClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NiceOutputStreamPrivate)); - - stream_class->write_fn = nice_output_stream_write; - stream_class->close_fn = nice_output_stream_close; - - gobject_class->set_property = nice_output_stream_set_property; - gobject_class->get_property = nice_output_stream_get_property; - gobject_class->dispose = nice_output_stream_dispose; - - /*** - * NiceOutputStream:agent: - * - * The #NiceAgent to wrap with an output stream. This must be an existing - * reliable agent. - * - * A reference is not held on the #NiceAgent. If the agent is destroyed before - * the #NiceOutputStream, %G_IO_ERROR_CLOSED will be returned for all - * subsequent operations on the stream. - * - * Since: 0.1.5 - */ - g_object_class_install_property (gobject_class, PROP_AGENT, - g_param_spec_object ("agent", - "NiceAgent", - "The underlying NiceAgent", - NICE_TYPE_AGENT, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /*** - * NiceOutputStream:stream-id: - * - * ID of the stream to use in the #NiceOutputStream:agent. - * - * Since: 0.1.5 - */ - g_object_class_install_property (gobject_class, PROP_STREAM_ID, - g_param_spec_uint ( - "stream-id", - "Agent’s stream ID", - "The ID of the agent’s stream to wrap.", - 0, G_MAXUINT, - 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /*** - * NiceOutputStream:component-id: - * - * ID of the component to use in the #NiceOutputStream:agent. - * - * Since: 0.1.5 - */ - g_object_class_install_property (gobject_class, PROP_COMPONENT_ID, - g_param_spec_uint ( - "component-id", - "Agent’s component ID", - "The ID of the agent’s component to wrap.", - 0, G_MAXUINT, - 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -} - -static void -nice_output_stream_dispose (GObject *object) -{ - NiceOutputStream *self = NICE_OUTPUT_STREAM (object); - NiceAgent *agent; - - /* Ensure the stream is closed first, otherwise the agent can’t be found in - * the close handler called by the parent implementation. */ - if (!g_output_stream_is_closed (G_OUTPUT_STREAM (object))) - g_output_stream_close (G_OUTPUT_STREAM (object), NULL, NULL); - - agent = g_weak_ref_get (&self->priv->agent_ref); - if (agent != NULL) { - g_signal_handlers_disconnect_by_func (agent, streams_removed_cb, self); - g_object_unref (agent); - } - - g_weak_ref_clear (&self->priv->agent_ref); - - g_clear_object (&self->priv->closed_cancellable); - - G_OBJECT_CLASS (nice_output_stream_parent_class)->dispose (object); -} - -static void -nice_output_stream_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NiceOutputStream *self = NICE_OUTPUT_STREAM (object); - - switch (prop_id) { - case PROP_AGENT: - g_value_take_object (value, g_weak_ref_get (&self->priv->agent_ref)); - break; - case PROP_STREAM_ID: - g_value_set_uint (value, self->priv->stream_id); - break; - case PROP_COMPONENT_ID: - g_value_set_uint (value, self->priv->component_id); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -nice_output_stream_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NiceOutputStream *self = NICE_OUTPUT_STREAM (object); - - switch (prop_id) { - case PROP_AGENT: { - /* Construct only. */ - NiceAgent *agent = g_value_dup_object (value); - g_weak_ref_set (&self->priv->agent_ref, agent); - - /* agent may be NULL if the stream is being constructed by - * nice_io_stream_get_output_stream() after the NiceIOStream’s agent has - * already been finalised. */ - if (agent != NULL) { - g_signal_connect (agent, "streams-removed", - (GCallback) streams_removed_cb, self); - g_object_unref (agent); - } - - break; - } - case PROP_STREAM_ID: - /* Construct only. */ - self->priv->stream_id = g_value_get_uint (value); - break; - case PROP_COMPONENT_ID: - /* Construct only. */ - self->priv->component_id = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -nice_output_stream_init (NiceOutputStream *stream) -{ - stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, NICE_TYPE_OUTPUT_STREAM, - NiceOutputStreamPrivate); - - g_weak_ref_init (&stream->priv->agent_ref, NULL); - stream->priv->closed_cancellable = g_cancellable_new (); -} - -static void -nice_output_stream_init_pollable (GPollableOutputStreamInterface *iface) -{ - iface->is_writable = nice_output_stream_is_writable; - iface->write_nonblocking = nice_output_stream_write_nonblocking; - iface->create_source = nice_output_stream_create_source; -} - -/*** - * nice_output_stream_new: - * @agent: A #NiceAgent - * @stream_id: The ID of the agent’s stream to wrap - * @component_id: The ID of the agent’s component to wrap - * - * Create a new #NiceOutputStream wrapping the given stream/component from - * @agent, which must be a reliable #NiceAgent. - * - * The constructed #NiceOutputStream will not hold a reference to @agent. If - * @agent is destroyed before the output stream, %G_IO_ERROR_CLOSED will be - * returned for all subsequent operations on the stream. - * - * Returns: The new #NiceOutputStream object - * - * Since: 0.1.5 - */ -NiceOutputStream * -nice_output_stream_new (NiceAgent *agent, guint stream_id, guint component_id) -{ - g_return_val_if_fail (NICE_IS_AGENT (agent), NULL); - g_return_val_if_fail (stream_id >= 1, NULL); - g_return_val_if_fail (component_id >= 1, NULL); - - return g_object_new (NICE_TYPE_OUTPUT_STREAM, - "agent", agent, - "stream-id", stream_id, - "component-id", component_id, - NULL); -} - -typedef struct { - volatile gint ref_count; - - GCond cond; - GMutex mutex; - - gboolean writable; - gboolean cancelled; -} WriteData; - -static WriteData * -write_data_ref (WriteData *write_data) -{ - g_atomic_int_inc (&write_data->ref_count); - return write_data; -} - -static void -write_data_unref (WriteData *write_data) -{ - if (g_atomic_int_dec_and_test (&write_data->ref_count)) { - g_cond_clear (&write_data->cond); - g_mutex_clear (&write_data->mutex); - g_slice_free (WriteData, write_data); - } -} - -static void -write_cancelled_cb (GCancellable *cancellable, gpointer user_data) -{ - WriteData *write_data = user_data; - - g_mutex_lock (&write_data->mutex); - g_cond_broadcast (&write_data->cond); - write_data->cancelled = TRUE; - g_mutex_unlock (&write_data->mutex); -} - -static void -reliable_transport_writeable_cb (NiceAgent *agent, guint stream_id, - guint component_id, gpointer user_data) -{ - WriteData *write_data = user_data; - - g_mutex_lock (&write_data->mutex); - write_data->writable = TRUE; - g_cond_broadcast (&write_data->cond); - g_mutex_unlock (&write_data->mutex); -} - -static gssize -nice_output_stream_write (GOutputStream *stream, const void *buffer, gsize count, - GCancellable *cancellable, GError **error) -{ - NiceOutputStream *self = NICE_OUTPUT_STREAM (stream); - const gchar* buf = buffer; - gssize len = 0; - gint n_sent; - NiceAgent *agent = NULL; /* owned */ - gulong cancel_id = 0, closed_cancel_id, writeable_id; - WriteData *write_data; - - /* Closed streams are not writeable. */ - if (g_output_stream_is_closed (stream)) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, - "Stream is closed."); - return -1; - } - - /* Has the agent disappeared? */ - agent = g_weak_ref_get (&self->priv->agent_ref); - if (agent == NULL) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, - "Stream is closed due to the NiceAgent being finalised."); - return -1; - } - - if (count == 0) { - g_object_unref (agent); - return 0; - } - - /* FIXME: nice_agent_send() is non-blocking, which is a bit unexpected - * since nice_agent_recv() is blocking. Currently this uses a fairly dodgy - * GCond solution; would be much better for nice_agent_send() to block - * properly in the main loop. */ - write_data = g_slice_new0 (WriteData); - write_data->ref_count = 1; - g_mutex_init (&write_data->mutex); - g_cond_init (&write_data->cond); - - if (cancellable != NULL) { - cancel_id = g_cancellable_connect (cancellable, - (GCallback) write_cancelled_cb, write_data_ref (write_data), - (GDestroyNotify) write_data_unref); - } - - closed_cancel_id = g_cancellable_connect (self->priv->closed_cancellable, - (GCallback) write_cancelled_cb, write_data_ref (write_data), - (GDestroyNotify) write_data_unref); - - g_mutex_lock (&write_data->mutex); - - writeable_id = g_signal_connect_data (G_OBJECT (agent), - "reliable-transport-writable", - (GCallback) reliable_transport_writeable_cb, write_data_ref (write_data), - (GClosureNotify) G_CALLBACK (write_data_unref), 0); - - - do { - /* Have to unlock while calling into the agent because - * it will take the agent lock which will cause a deadlock if one of - * the callbacks is called. - */ - if (g_cancellable_is_cancelled (cancellable) || - g_cancellable_is_cancelled (self->priv->closed_cancellable)) - break; - - write_data->writable = FALSE; - g_mutex_unlock (&write_data->mutex); - - n_sent = nice_agent_send (agent, self->priv->stream_id, - self->priv->component_id, count - len, buf + len); - - g_mutex_lock (&write_data->mutex); - - if (n_sent <= 0) { - if (!write_data->writable && !write_data->cancelled) - g_cond_wait (&write_data->cond, &write_data->mutex); - } else if (n_sent > 0) { - /* Success. */ - len += n_sent; - } - } while ((gsize) len < count); - - g_signal_handler_disconnect (G_OBJECT (agent), writeable_id); - g_mutex_unlock (&write_data->mutex); - - if (cancel_id) - g_cancellable_disconnect (cancellable, cancel_id); - g_cancellable_disconnect (self->priv->closed_cancellable, closed_cancel_id); - - if (len == 0) { - len = -1; - if (!g_cancellable_set_error_if_cancelled (cancellable, error)) { - if (g_cancellable_is_cancelled (self->priv->closed_cancellable)) - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, - "Stream has been removed from agent"); - } - } - - write_data_unref (write_data); - - g_object_unref (agent); - g_assert_cmpint (len, !=, 0); - - return len; -} - -static gboolean -nice_output_stream_close (GOutputStream *stream, GCancellable *cancellable, - GError **error) -{ - NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv; - NiceComponent *component = NULL; - NiceStream *_stream = NULL; - NiceAgent *agent; /* owned */ - - /* Has the agent disappeared? */ - agent = g_weak_ref_get (&priv->agent_ref); - if (agent == NULL) - return TRUE; - - agent_lock (agent); - - /* Shut down the write side of the pseudo-TCP stream. */ - if (agent_find_component (agent, priv->stream_id, priv->component_id, - &_stream, &component) && agent->reliable && - !pseudo_tcp_socket_is_closed (component->tcp)) { - pseudo_tcp_socket_shutdown (component->tcp, PSEUDO_TCP_SHUTDOWN_WR); - } - - agent_unlock (agent); - - g_object_unref (agent); - - return TRUE; -} - -static gboolean -nice_output_stream_is_writable (GPollableOutputStream *stream) -{ - NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv; - NiceComponent *component = NULL; - NiceStream *_stream = NULL; - gboolean retval = FALSE; - NiceAgent *agent; /* owned */ - - /* Closed streams are not writeable. */ - if (g_output_stream_is_closed (G_OUTPUT_STREAM (stream))) - return FALSE; - - /* Has the agent disappeared? */ - agent = g_weak_ref_get (&priv->agent_ref); - if (agent == NULL) - return FALSE; - - agent_lock (agent); - - if (!agent_find_component (agent, priv->stream_id, priv->component_id, - &_stream, &component)) { - g_warning ("Could not find component %u in stream %u", priv->component_id, - priv->stream_id); - goto done; - } - if (component->selected_pair.local != NULL) { - NiceSocket *sockptr = component->selected_pair.local->sockptr; - - /* If it’s a reliable agent, see if there’s any space in the pseudo-TCP - * output buffer. */ - if (!nice_socket_is_reliable (sockptr)) { - retval = pseudo_tcp_socket_can_send (component->tcp); - } else { - retval = (g_socket_condition_check (sockptr->fileno, G_IO_OUT) != 0); - } - } - -done: - agent_unlock (agent); - - g_object_unref (agent); - - return retval; -} - -static gssize -nice_output_stream_write_nonblocking (GPollableOutputStream *stream, - const void *buffer, gsize count, GError **error) -{ - NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv; - NiceAgent *agent; /* owned */ - gint n_sent; - - /* Closed streams are not writeable. */ - if (g_output_stream_is_closed (G_OUTPUT_STREAM (stream))) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, - "Stream is closed."); - return -1; - } - - /* Has the agent disappeared? */ - agent = g_weak_ref_get (&priv->agent_ref); - if (agent == NULL) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, - "Stream is closed due to the NiceAgent being finalised."); - return -1; - } - - if (count == 0) { - n_sent = 0; - goto done; - } - - n_sent = nice_agent_send (agent, priv->stream_id, priv->component_id, - count, buffer); - - if (n_sent == -1) - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK, - g_strerror (EAGAIN)); - - done: - - g_object_unref (agent); - - return n_sent; -} - -static GSource * -nice_output_stream_create_source (GPollableOutputStream *stream, - GCancellable *cancellable) -{ - NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv; - GSource *component_source = NULL; - NiceComponent *component = NULL; - NiceStream *_stream = NULL; - NiceAgent *agent; /* owned */ - - component_source = g_pollable_source_new (G_OBJECT (stream)); - - if (cancellable) { - GSource *cancellable_source = g_cancellable_source_new (cancellable); - - g_source_set_dummy_callback (cancellable_source); - g_source_add_child_source (component_source, cancellable_source); - g_source_unref (cancellable_source); - } - - /* Closed streams cannot have sources. */ - if (g_output_stream_is_closed (G_OUTPUT_STREAM (stream))) - return component_source; - - /* Has the agent disappeared? */ - agent = g_weak_ref_get (&priv->agent_ref); - if (agent == NULL) - return component_source; - - agent_lock (agent); - - /* Grab the socket for this component. */ - if (!agent_find_component (agent, priv->stream_id, priv->component_id, - &_stream, &component)) { - g_warning ("Could not find component %u in stream %u", priv->component_id, - priv->stream_id); - goto done; - } - - if (component->tcp_writable_cancellable) { - GSource *cancellable_source = - g_cancellable_source_new (component->tcp_writable_cancellable); - - g_source_set_dummy_callback (cancellable_source); - g_source_add_child_source (component_source, cancellable_source); - g_source_unref (cancellable_source); - } - -done: - agent_unlock (agent); - - g_object_unref (agent); - - return component_source; -} - -static void -streams_removed_cb (NiceAgent *agent, guint *stream_ids, gpointer user_data) -{ - NiceOutputStream *self = NICE_OUTPUT_STREAM (user_data); - guint i; - - for (i = 0; stream_ids[i] != 0; i++) { - if (stream_ids[i] == self->priv->stream_id) { - /* The socket has been closed. */ - g_cancellable_cancel (self->priv->closed_cancellable); - - g_output_stream_close (G_OUTPUT_STREAM (self), NULL, NULL); - break; - } - } -} diff --git a/agent/outputstream.h b/agent/outputstream.h deleted file mode 100644 index eefdb3c..0000000 --- a/agent/outputstream.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2010, 2013 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef __NICE_OUTPUT_STREAM_H__ -#define __NICE_OUTPUT_STREAM_H__ - -#include -#include -#include "agent.h" - -G_BEGIN_DECLS - -/* TYPE MACROS */ -#define NICE_TYPE_OUTPUT_STREAM \ - (nice_output_stream_get_type ()) -#define NICE_OUTPUT_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NICE_TYPE_OUTPUT_STREAM, \ - NiceOutputStream)) -#define NICE_OUTPUT_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NICE_TYPE_OUTPUT_STREAM, \ - NiceOutputStreamClass)) -#define NICE_IS_OUTPUT_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), NICE_TYPE_OUTPUT_STREAM)) -#define NICE_IS_OUTPUT_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NICE_TYPE_OUTPUT_STREAM)) -#define NICE_OUTPUT_STREAM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), NICE_TYPE_OUTPUT_STREAM, \ - NiceOutputStreamClass)) - - -typedef struct _NiceOutputStreamPrivate NiceOutputStreamPrivate; -typedef struct _NiceOutputStreamClass NiceOutputStreamClass; -typedef struct _NiceOutputStream NiceOutputStream; - - -GType nice_output_stream_get_type (void); - -struct _NiceOutputStreamClass -{ - GOutputStreamClass parent_class; -}; - -struct _NiceOutputStream -{ - GOutputStream parent_instance; - NiceOutputStreamPrivate *priv; -}; - - -NiceOutputStream *nice_output_stream_new (NiceAgent *agent, - guint stream_id, guint component_id); - -G_END_DECLS - -#endif /* __NICE_OUTPUT_STREAM_H__ */ diff --git a/agent/pseudotcp.c b/agent/pseudotcp.c deleted file mode 100644 index 1fdbec1..0000000 --- a/agent/pseudotcp.c +++ /dev/null @@ -1,2646 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2010, 2014 Collabora Ltd. - * Contact: Philip Withnall - - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* Reproducing license from libjingle for copied code */ - -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include - -#include - -#ifndef G_OS_WIN32 -# include -#endif - -#include "pseudotcp.h" -#include "agent-priv.h" - -struct _PseudoTcpSocketClass { - GObjectClass parent_class; -}; - -typedef struct _PseudoTcpSocketPrivate PseudoTcpSocketPrivate; - - -struct _PseudoTcpSocket { - GObject parent; - PseudoTcpSocketPrivate *priv; -}; - -G_DEFINE_TYPE (PseudoTcpSocket, pseudo_tcp_socket, G_TYPE_OBJECT); - -////////////////////////////////////////////////////////////////////// -// Network Constants -////////////////////////////////////////////////////////////////////// - -// Standard MTUs -const guint16 PACKET_MAXIMUMS[] = { - 65535, // Theoretical maximum, Hyperchannel - 32000, // Nothing - 17914, // 16Mb IBM Token Ring - 8166, // IEEE 802.4 - //4464, // IEEE 802.5 (4Mb max) - 4352, // FDDI - //2048, // Wideband Network - 2002, // IEEE 802.5 (4Mb recommended) - //1536, // Expermental Ethernet Networks - //1500, // Ethernet, Point-to-Point (default) - 1492, // IEEE 802.3 - 1006, // SLIP, ARPANET - //576, // X.25 Networks - //544, // DEC IP Portal - //512, // NETBIOS - 508, // IEEE 802/Source-Rt Bridge, ARCNET - 296, // Point-to-Point (low delay) - //68, // Official minimum - 0, // End of list marker -}; - -// FIXME: This is a reasonable MTU, but we should get it from the lower layer -#define DEF_MTU 1400 -#define MAX_PACKET 65532 -// Note: we removed lowest level because packet overhead was larger! -#define MIN_PACKET 296 - -// (+ up to 40 bytes of options?) -#define IP_HEADER_SIZE 20 -#define ICMP_HEADER_SIZE 8 -#define UDP_HEADER_SIZE 8 -// TODO: Make JINGLE_HEADER_SIZE transparent to this code? -// when relay framing is in use -#define JINGLE_HEADER_SIZE 64 - -////////////////////////////////////////////////////////////////////// -// Global Constants and Functions -////////////////////////////////////////////////////////////////////// -// -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 0 | Conversation Number | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 4 | Sequence Number | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 8 | Acknowledgment Number | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | | |U|A|P|R|S|F| | -// 12 | Control | |R|C|S|S|Y|I| Window | -// | | |G|K|H|T|N|N| | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 16 | Timestamp sending | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 20 | Timestamp receiving | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 24 | data | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// -////////////////////////////////////////////////////////////////////// - -#define MAX_SEQ 0xFFFFFFFF -#define HEADER_SIZE 24 - -#define PACKET_OVERHEAD (HEADER_SIZE + UDP_HEADER_SIZE + \ - IP_HEADER_SIZE + JINGLE_HEADER_SIZE) - -// MIN_RTO = 1 second (RFC6298, Sec 2.4) -#define MIN_RTO 1000 -#define DEF_RTO 1000 /* 1 seconds (RFC 6298 sect 2.1) */ -#define MAX_RTO 60000 /* 60 seconds */ -#define DEFAULT_ACK_DELAY 100 /* 100 milliseconds */ -#define DEFAULT_NO_DELAY FALSE - -#define DEFAULT_RCV_BUF_SIZE (60 * 1024) -#define DEFAULT_SND_BUF_SIZE (90 * 1024) - -/* NOTE: This must fit in 8 bits. This is used on the wire. */ -typedef enum { - /* Google-provided options: */ - TCP_OPT_EOL = 0, /* end of list */ - TCP_OPT_NOOP = 1, /* no-op */ - TCP_OPT_MSS = 2, /* maximum segment size */ - TCP_OPT_WND_SCALE = 3, /* window scale factor */ - /* libnice extensions: */ - TCP_OPT_FIN_ACK = 254, /* FIN-ACK support */ -} TcpOption; - - -/* -#define FLAG_SYN 0x02 -#define FLAG_ACK 0x10 -*/ - -/* NOTE: This must fit in 5 bits. This is used on the wire. */ -typedef enum { - FLAG_NONE = 0, - FLAG_FIN = 1 << 0, - FLAG_CTL = 1 << 1, - FLAG_RST = 1 << 2, -} TcpFlags; - -#define CTL_CONNECT 0 -//#define CTL_REDIRECT 1 -#define CTL_EXTRA 255 - - -#define CTRL_BOUND 0x80000000 - -/* Maximum segment lifetime (1 minute). - * RFC 793, §3.3 specifies 2 minutes; but Linux uses 1 minute, so let’s go with - * that. */ -#define TCP_MSL (60 * 1000) - -// If there are no pending clocks, wake up every 4 seconds -#define DEFAULT_TIMEOUT 4000 -// If the connection is closed, once per minute -#define CLOSED_TIMEOUT (60 * 1000) -/* Timeout after reaching the TIME_WAIT state, in milliseconds. - * See: RFC 1122, §4.2.2.13. - * - * XXX: Since we can control the underlying layer’s channel ID, we can guarantee - * delayed segments won’t affect subsequent connections, so can radically - * shorten the TIME-WAIT timeout (to the extent that it basically doesn’t - * exist). It would normally be (2 * TCP_MSL). */ -#define TIME_WAIT_TIMEOUT 1 - -////////////////////////////////////////////////////////////////////// -// Helper Functions -////////////////////////////////////////////////////////////////////// -#ifndef G_OS_WIN32 -# define min(first, second) ((first) < (second) ? (first) : (second)) -# define max(first, second) ((first) > (second) ? (first) : (second)) -#endif - -static guint32 -bound(guint32 lower, guint32 middle, guint32 upper) -{ - return min (max (lower, middle), upper); -} - -static gboolean -time_is_between(guint32 later, guint32 middle, guint32 earlier) -{ - if (earlier <= later) { - return ((earlier <= middle) && (middle <= later)); - } else { - return !((later < middle) && (middle < earlier)); - } -} - -static gint32 -time_diff(guint32 later, guint32 earlier) -{ - guint32 LAST = 0xFFFFFFFF; - guint32 HALF = 0x80000000; - if (time_is_between(earlier + HALF, later, earlier)) { - if (earlier <= later) { - return (long)(later - earlier); - } else { - return (long)(later + (LAST - earlier) + 1); - } - } else { - if (later <= earlier) { - return -(long) (earlier - later); - } else { - return -(long)(earlier + (LAST - later) + 1); - } - } -} - -//////////////////////////////////////////////////////// -// PseudoTcpFifo works exactly like FifoBuffer in libjingle -//////////////////////////////////////////////////////// - - -typedef struct { - guint8 *buffer; - gsize buffer_length; - gsize data_length; - gsize read_position; -} PseudoTcpFifo; - - -static void -pseudo_tcp_fifo_init (PseudoTcpFifo *b, gsize size) -{ - b->buffer = g_slice_alloc (size); - b->buffer_length = size; -} - -static void -pseudo_tcp_fifo_clear (PseudoTcpFifo *b) -{ - if (b->buffer) - g_slice_free1 (b->buffer_length, b->buffer); - b->buffer = NULL; - b->buffer_length = 0; -} - -static gsize -pseudo_tcp_fifo_get_buffered (PseudoTcpFifo *b) -{ - return b->data_length; -} - -static gboolean -pseudo_tcp_fifo_set_capacity (PseudoTcpFifo *b, gsize size) -{ - if (b->data_length > size) - return FALSE; - - if (size != b->data_length) { - guint8 *buffer = g_slice_alloc (size); - gsize copy = b->data_length; - gsize tail_copy = min (copy, b->buffer_length - b->read_position); - - memcpy (buffer, &b->buffer[b->read_position], tail_copy); - memcpy (buffer + tail_copy, &b->buffer[0], copy - tail_copy); - g_slice_free1 (b->buffer_length, b->buffer); - b->buffer = buffer; - b->buffer_length = size; - b->read_position = 0; - } - - return TRUE; -} - -static void -pseudo_tcp_fifo_consume_read_data (PseudoTcpFifo *b, gsize size) -{ - g_assert_cmpint (size, <=, b->data_length); - - b->read_position = (b->read_position + size) % b->buffer_length; - b->data_length -= size; -} - -static void -pseudo_tcp_fifo_consume_write_buffer (PseudoTcpFifo *b, gsize size) -{ - g_assert_cmpint (size, <=, b->buffer_length - b->data_length); - - b->data_length += size; -} - -static gsize -pseudo_tcp_fifo_get_write_remaining (PseudoTcpFifo *b) -{ - return b->buffer_length - b->data_length; -} - -static gsize -pseudo_tcp_fifo_read_offset (PseudoTcpFifo *b, guint8 *buffer, gsize bytes, - gsize offset) -{ - gsize available = b->data_length - offset; - gsize read_position = (b->read_position + offset) % b->buffer_length; - gsize copy = min (bytes, available); - gsize tail_copy = min(copy, b->buffer_length - read_position); - - /* EOS */ - if (offset >= b->data_length) - return 0; - - memcpy(buffer, &b->buffer[read_position], tail_copy); - memcpy(buffer + tail_copy, &b->buffer[0], copy - tail_copy); - - return copy; -} - -static gsize -pseudo_tcp_fifo_write_offset (PseudoTcpFifo *b, const guint8 *buffer, - gsize bytes, gsize offset) -{ - gsize available = b->buffer_length - b->data_length - offset; - gsize write_position = (b->read_position + b->data_length + offset) - % b->buffer_length; - gsize copy = min (bytes, available); - gsize tail_copy = min(copy, b->buffer_length - write_position); - - if (b->data_length + offset >= b->buffer_length) { - return 0; - } - - memcpy(&b->buffer[write_position], buffer, tail_copy); - memcpy(&b->buffer[0], buffer + tail_copy, copy - tail_copy); - - return copy; -} - -static gsize -pseudo_tcp_fifo_read (PseudoTcpFifo *b, guint8 *buffer, gsize bytes) -{ - gsize copy; - - copy = pseudo_tcp_fifo_read_offset (b, buffer, bytes, 0); - - b->read_position = (b->read_position + copy) % b->buffer_length; - b->data_length -= copy; - - return copy; -} - -static gsize -pseudo_tcp_fifo_write (PseudoTcpFifo *b, const guint8 *buffer, gsize bytes) -{ - gsize copy; - - copy = pseudo_tcp_fifo_write_offset (b, buffer, bytes, 0); - b->data_length += copy; - - return copy; -} - - -////////////////////////////////////////////////////////////////////// -// PseudoTcp -////////////////////////////////////////////////////////////////////// - -/* Only used if FIN-ACK support is disabled. */ -typedef enum { - SD_NONE, - SD_GRACEFUL, - SD_FORCEFUL -} Shutdown; - -typedef enum { - sfNone, - sfDelayedAck, - sfImmediateAck, - sfFin, - sfRst, - sfDuplicateAck, -} SendFlags; - -typedef struct { - guint32 conv, seq, ack; - TcpFlags flags; - guint16 wnd; - const gchar * data; - guint32 len; - guint32 tsval, tsecr; -} Segment; - -typedef struct { - guint32 seq, len; - guint8 xmit; - TcpFlags flags; -} SSegment; - -typedef struct { - guint32 seq, len; -} RSegment; - -/** - * ClosedownSource: - * @CLOSEDOWN_LOCAL: Error detected locally, or connection forcefully closed - * locally. - * @CLOSEDOWN_REMOTE: RST segment received from the peer. - * - * Reasons for calling closedown(). - * - * Since: 0.1.8 - */ -typedef enum { - CLOSEDOWN_LOCAL, - CLOSEDOWN_REMOTE, -} ClosedownSource; - - -struct _PseudoTcpSocketPrivate { - PseudoTcpCallbacks callbacks; - - Shutdown shutdown; /* only used if !support_fin_ack */ - gboolean shutdown_reads; - gint error; - - // TCB data - PseudoTcpState state; - guint32 conv; - gboolean bReadEnable, bWriteEnable, bOutgoing; - guint32 last_traffic; - - // Incoming data - GList *rlist; - guint32 rbuf_len, rcv_nxt, rcv_wnd, lastrecv; - guint8 rwnd_scale; // Window scale factor - PseudoTcpFifo rbuf; - guint32 rcv_fin; /* sequence number of the received FIN octet, or 0 */ - - // Outgoing data - GQueue slist; - GQueue unsent_slist; - guint32 sbuf_len, snd_nxt, snd_wnd, lastsend; - guint32 snd_una; /* oldest unacknowledged sequence number */ - guint8 swnd_scale; // Window scale factor - PseudoTcpFifo sbuf; - - // Maximum segment size, estimated protocol level, largest segment sent - guint32 mss, msslevel, largest, mtu_advise; - // Retransmit timer - guint32 rto_base; - - // Timestamp tracking - guint32 ts_recent, ts_lastack; - - // Round-trip calculation - guint32 rx_rttvar, rx_srtt, rx_rto; - - // Congestion avoidance, Fast retransmit/recovery, Delayed ACKs - guint32 ssthresh, cwnd; - guint8 dup_acks; - guint32 recover; - gboolean fast_recovery; - guint32 t_ack; /* time a delayed ack was scheduled; 0 if no acks scheduled */ - guint32 last_acked_ts; - - gboolean use_nagling; - guint32 ack_delay; - - // This is used by unit tests to test backward compatibility of - // PseudoTcp implementations that don't support window scaling. - gboolean support_wnd_scale; - - /* Current time. Typically only used for testing, when non-zero. When zero, - * the system monotonic clock is used. Units: monotonic milliseconds. */ - guint32 current_time; - - /* This is used by compatible implementations (with the TCP_OPT_FIN_ACK - * option) to enable correct FIN-ACK connection termination. Defaults to - * TRUE unless no compatible option is received. */ - gboolean support_fin_ack; -}; - -#define LARGER(a,b) (((a) - (b) - 1) < (G_MAXUINT32 >> 1)) -#define LARGER_OR_EQUAL(a,b) (((a) - (b)) < (G_MAXUINT32 >> 1)) -#define SMALLER(a,b) LARGER ((b),(a)) -#define SMALLER_OR_EQUAL(a,b) LARGER_OR_EQUAL ((b),(a)) - -/* properties */ -enum -{ - PROP_CONVERSATION = 1, - PROP_CALLBACKS, - PROP_STATE, - PROP_ACK_DELAY, - PROP_NO_DELAY, - PROP_RCV_BUF, - PROP_SND_BUF, - PROP_SUPPORT_FIN_ACK, - LAST_PROPERTY -}; - - -static void pseudo_tcp_socket_get_property (GObject *object, guint property_id, - GValue *value, GParamSpec *pspec); -static void pseudo_tcp_socket_set_property (GObject *object, guint property_id, - const GValue *value, GParamSpec *pspec); -static void pseudo_tcp_socket_finalize (GObject *object); - - -static void queue_connect_message (PseudoTcpSocket *self); -static guint32 queue (PseudoTcpSocket *self, const gchar *data, - guint32 len, TcpFlags flags); -static PseudoTcpWriteResult packet(PseudoTcpSocket *self, guint32 seq, - TcpFlags flags, guint32 offset, guint32 len, guint32 now); -static gboolean parse (PseudoTcpSocket *self, - const guint8 *_header_buf, gsize header_buf_len, - const guint8 *data_buf, gsize data_buf_len); -static gboolean process(PseudoTcpSocket *self, Segment *seg); -static int transmit(PseudoTcpSocket *self, SSegment *sseg, guint32 now); -static void attempt_send(PseudoTcpSocket *self, SendFlags sflags); -static void closedown (PseudoTcpSocket *self, guint32 err, - ClosedownSource source); -static void adjustMTU(PseudoTcpSocket *self); -static void parse_options (PseudoTcpSocket *self, const guint8 *data, - guint32 len); -static void resize_send_buffer (PseudoTcpSocket *self, guint32 new_size); -static void resize_receive_buffer (PseudoTcpSocket *self, guint32 new_size); -static void set_state (PseudoTcpSocket *self, PseudoTcpState new_state); -static void set_state_established (PseudoTcpSocket *self); -static void set_state_closed (PseudoTcpSocket *self, guint32 err); - -static const gchar *pseudo_tcp_state_get_name (PseudoTcpState state); -static gboolean pseudo_tcp_state_has_sent_fin (PseudoTcpState state); -static gboolean pseudo_tcp_state_has_received_fin (PseudoTcpState state); -static gboolean pseudo_tcp_state_has_received_fin_ack (PseudoTcpState state); - -// The following logging is for detailed (packet-level) pseudotcp analysis only. -static PseudoTcpDebugLevel debug_level = PSEUDO_TCP_DEBUG_NONE; - -#define DEBUG(level, fmt, ...) \ - if (debug_level >= level) \ - g_log (level == PSEUDO_TCP_DEBUG_NORMAL ? "libnice-pseudotcp" : "libnice-pseudotcp-verbose", G_LOG_LEVEL_DEBUG, "PseudoTcpSocket %p %s: " fmt, \ - self, pseudo_tcp_state_get_name (self->priv->state), ## __VA_ARGS__) - -void -pseudo_tcp_set_debug_level (PseudoTcpDebugLevel level) -{ - debug_level = level; -} - -static guint32 -get_current_time (PseudoTcpSocket *socket) -{ - if (G_UNLIKELY (socket->priv->current_time != 0)) - return socket->priv->current_time; - - return g_get_monotonic_time () / 1000; -} - -void -pseudo_tcp_socket_set_time (PseudoTcpSocket *self, guint32 current_time) -{ - self->priv->current_time = current_time; -} - -static void -pseudo_tcp_socket_class_init (PseudoTcpSocketClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - - object_class->get_property = pseudo_tcp_socket_get_property; - object_class->set_property = pseudo_tcp_socket_set_property; - object_class->finalize = pseudo_tcp_socket_finalize; - - g_object_class_install_property (object_class, PROP_CONVERSATION, - g_param_spec_uint ("conversation", "TCP Conversation ID", - "The TCP Conversation ID", - 0, G_MAXUINT32, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (object_class, PROP_CALLBACKS, - g_param_spec_pointer ("callbacks", "PseudoTcp socket callbacks", - "Structure with the callbacks to call when PseudoTcp events happen", - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (object_class, PROP_STATE, - g_param_spec_uint ("state", "PseudoTcp State", - "The current state (enum PseudoTcpState) of the PseudoTcp socket", - PSEUDO_TCP_LISTEN, PSEUDO_TCP_CLOSED, PSEUDO_TCP_LISTEN, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (object_class, PROP_ACK_DELAY, - g_param_spec_uint ("ack-delay", "ACK Delay", - "Delayed ACK timeout (in milliseconds)", - 0, G_MAXUINT, DEFAULT_ACK_DELAY, - G_PARAM_READWRITE| G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (object_class, PROP_NO_DELAY, - g_param_spec_boolean ("no-delay", "No Delay", - "Disable the Nagle algorithm (like the TCP_NODELAY option)", - DEFAULT_NO_DELAY, - G_PARAM_READWRITE| G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (object_class, PROP_RCV_BUF, - g_param_spec_uint ("rcv-buf", "Receive Buffer", - "Receive Buffer size", - 1, G_MAXUINT, DEFAULT_RCV_BUF_SIZE, - G_PARAM_READWRITE| G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (object_class, PROP_SND_BUF, - g_param_spec_uint ("snd-buf", "Send Buffer", - "Send Buffer size", - 1, G_MAXUINT, DEFAULT_SND_BUF_SIZE, - G_PARAM_READWRITE| G_PARAM_STATIC_STRINGS)); - - /** - * PseudoTcpSocket:support-fin-ack: - * - * Whether to support the FIN–ACK extension to the pseudo-TCP protocol for - * this socket. The extension is only compatible with other libnice pseudo-TCP - * stacks, and not with Jingle pseudo-TCP stacks. If enabled, support is - * negotiatied on connection setup, so it is safe for a #PseudoTcpSocket with - * support enabled to be used with one with it disabled, or with a Jingle - * pseudo-TCP socket which doesn’t support it at all. - * - * Support is enabled by default. - * - * Since: 0.1.8 - */ - g_object_class_install_property (object_class, PROP_SUPPORT_FIN_ACK, - g_param_spec_boolean ("support-fin-ack", "Support FIN–ACK", - "Whether to enable the optional FIN–ACK support.", - TRUE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); -} - - -static void -pseudo_tcp_socket_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - PseudoTcpSocket *self = PSEUDO_TCP_SOCKET (object); - - switch (property_id) { - case PROP_CONVERSATION: - g_value_set_uint (value, self->priv->conv); - break; - case PROP_CALLBACKS: - g_value_set_pointer (value, (gpointer) &self->priv->callbacks); - break; - case PROP_STATE: - g_value_set_uint (value, self->priv->state); - break; - case PROP_ACK_DELAY: - g_value_set_uint (value, self->priv->ack_delay); - break; - case PROP_NO_DELAY: - g_value_set_boolean (value, !self->priv->use_nagling); - break; - case PROP_RCV_BUF: - g_value_set_uint (value, self->priv->rbuf_len); - break; - case PROP_SND_BUF: - g_value_set_uint (value, self->priv->sbuf_len); - break; - case PROP_SUPPORT_FIN_ACK: - g_value_set_boolean (value, self->priv->support_fin_ack); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -pseudo_tcp_socket_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - PseudoTcpSocket *self = PSEUDO_TCP_SOCKET (object); - - switch (property_id) { - case PROP_CONVERSATION: - self->priv->conv = g_value_get_uint (value); - break; - case PROP_CALLBACKS: - { - PseudoTcpCallbacks *c = g_value_get_pointer (value); - self->priv->callbacks = *c; - } - break; - case PROP_ACK_DELAY: - self->priv->ack_delay = g_value_get_uint (value); - break; - case PROP_NO_DELAY: - self->priv->use_nagling = !g_value_get_boolean (value); - break; - case PROP_RCV_BUF: - g_return_if_fail (self->priv->state == PSEUDO_TCP_LISTEN); - resize_receive_buffer (self, g_value_get_uint (value)); - break; - case PROP_SND_BUF: - g_return_if_fail (self->priv->state == PSEUDO_TCP_LISTEN); - resize_send_buffer (self, g_value_get_uint (value)); - break; - case PROP_SUPPORT_FIN_ACK: - self->priv->support_fin_ack = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -pseudo_tcp_socket_finalize (GObject *object) -{ - PseudoTcpSocket *self = PSEUDO_TCP_SOCKET (object); - PseudoTcpSocketPrivate *priv = self->priv; - GList *i; - SSegment *sseg; - - if (priv == NULL) - return; - - while ((sseg = g_queue_pop_head (&priv->slist))) - g_slice_free (SSegment, sseg); - g_queue_clear (&priv->unsent_slist); - for (i = priv->rlist; i; i = i->next) { - RSegment *rseg = i->data; - g_slice_free (RSegment, rseg); - } - g_list_free (priv->rlist); - priv->rlist = NULL; - - pseudo_tcp_fifo_clear (&priv->rbuf); - pseudo_tcp_fifo_clear (&priv->sbuf); - - g_free (priv); - self->priv = NULL; - - if (G_OBJECT_CLASS (pseudo_tcp_socket_parent_class)->finalize) - G_OBJECT_CLASS (pseudo_tcp_socket_parent_class)->finalize (object); -} - - -static void -pseudo_tcp_socket_init (PseudoTcpSocket *obj) -{ - /* Use g_new0, and do not use g_object_set_private because the size of - * our private data is too big (150KB+) and the g_slice_allow cannot allocate - * it. So we handle the private ourselves */ - PseudoTcpSocketPrivate *priv = g_new0 (PseudoTcpSocketPrivate, 1); - - obj->priv = priv; - - priv->shutdown = SD_NONE; - priv->error = 0; - - priv->rbuf_len = DEFAULT_RCV_BUF_SIZE; - pseudo_tcp_fifo_init (&priv->rbuf, priv->rbuf_len); - priv->sbuf_len = DEFAULT_SND_BUF_SIZE; - pseudo_tcp_fifo_init (&priv->sbuf, priv->sbuf_len); - - priv->state = PSEUDO_TCP_LISTEN; - priv->conv = 0; - g_queue_init (&priv->slist); - g_queue_init (&priv->unsent_slist); - priv->rcv_wnd = priv->rbuf_len; - priv->rwnd_scale = priv->swnd_scale = 0; - priv->snd_nxt = 0; - priv->snd_wnd = 1; - priv->snd_una = priv->rcv_nxt = 0; - priv->bReadEnable = TRUE; - priv->bWriteEnable = FALSE; - priv->rcv_fin = 0; - - priv->t_ack = 0; - - priv->msslevel = 0; - priv->largest = 0; - priv->mss = MIN_PACKET - PACKET_OVERHEAD; - priv->mtu_advise = DEF_MTU; - - priv->rto_base = 0; - - priv->cwnd = 2 * priv->mss; - priv->ssthresh = priv->rbuf_len; - priv->lastrecv = priv->lastsend = priv->last_traffic = 0; - priv->bOutgoing = FALSE; - - priv->dup_acks = 0; - priv->recover = 0; - priv->last_acked_ts = 0; - - priv->ts_recent = priv->ts_lastack = 0; - - priv->rx_rto = DEF_RTO; - priv->rx_srtt = priv->rx_rttvar = 0; - - priv->ack_delay = DEFAULT_ACK_DELAY; - priv->use_nagling = !DEFAULT_NO_DELAY; - - priv->support_wnd_scale = TRUE; - priv->support_fin_ack = TRUE; -} - -PseudoTcpSocket *pseudo_tcp_socket_new (guint32 conversation, - PseudoTcpCallbacks *callbacks) -{ - - return g_object_new (PSEUDO_TCP_SOCKET_TYPE, - "conversation", conversation, - "callbacks", callbacks, - NULL); -} - -static void -queue_connect_message (PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - guint8 buf[8]; - gsize size = 0; - - buf[size++] = CTL_CONNECT; - - if (priv->support_wnd_scale) { - buf[size++] = TCP_OPT_WND_SCALE; - buf[size++] = 1; - buf[size++] = priv->rwnd_scale; - } - - if (priv->support_fin_ack) { - buf[size++] = TCP_OPT_FIN_ACK; - buf[size++] = 1; /* option length; zero is invalid (RFC 1122, §4.2.2.5) */ - buf[size++] = 0; /* currently unused */ - } - - priv->snd_wnd = size; - - queue (self, (char *) buf, size, FLAG_CTL); -} - -static void -queue_fin_message (PseudoTcpSocket *self) -{ - g_assert (self->priv->support_fin_ack); - - /* FIN segments are always zero-length. */ - queue (self, "", 0, FLAG_FIN); -} - -static void -queue_rst_message (PseudoTcpSocket *self) -{ - g_assert (self->priv->support_fin_ack); - - /* RST segments are always zero-length. */ - queue (self, "", 0, FLAG_RST); -} - -gboolean -pseudo_tcp_socket_connect(PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - if (priv->state != PSEUDO_TCP_LISTEN) { - priv->error = EINVAL; - return FALSE; - } - - set_state (self, PSEUDO_TCP_SYN_SENT); - - queue_connect_message (self); - attempt_send(self, sfNone); - - return TRUE; -} - -void -pseudo_tcp_socket_notify_mtu(PseudoTcpSocket *self, guint16 mtu) -{ - PseudoTcpSocketPrivate *priv = self->priv; - priv->mtu_advise = mtu; - if (priv->state == PSEUDO_TCP_ESTABLISHED) { - adjustMTU(self); - } -} - -void -pseudo_tcp_socket_notify_clock(PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - guint32 now = get_current_time (self); - - if (priv->state == PSEUDO_TCP_CLOSED) - return; - - /* If in the TIME-WAIT state, any delayed segments have passed and the - * connection can be considered closed from both ends. - * FIXME: This should probably actually compare a timestamp before - * operating. */ - if (priv->support_fin_ack && priv->state == PSEUDO_TCP_TIME_WAIT) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Notified clock in TIME-WAIT state; closing connection."); - set_state_closed (self, 0); - } - - /* If in the LAST-ACK state, resend the FIN because it hasn’t been ACKed yet. - * FIXME: This should probably actually compare a timestamp before - * operating. */ - if (priv->support_fin_ack && priv->state == PSEUDO_TCP_LAST_ACK) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Notified clock in LAST-ACK state; resending FIN segment."); - queue_fin_message (self); - attempt_send (self, sfFin); - } - - // Check if it's time to retransmit a segment - if (priv->rto_base && - (time_diff(priv->rto_base + priv->rx_rto, now) <= 0)) { - if (g_queue_get_length (&priv->slist) == 0) { - g_assert_not_reached (); - } else { - // Note: (priv->slist.front().xmit == 0)) { - // retransmit segments - guint32 nInFlight; - guint32 rto_limit; - int transmit_status; - - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "timeout retransmit (rto: %u) " - "(rto_base: %u) (now: %u) (dup_acks: %u)", - priv->rx_rto, priv->rto_base, now, (guint) priv->dup_acks); - - transmit_status = transmit(self, g_queue_peek_head (&priv->slist), now); - if (transmit_status != 0) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Error transmitting segment. Closing down."); - closedown (self, transmit_status, CLOSEDOWN_LOCAL); - return; - } - - nInFlight = priv->snd_nxt - priv->snd_una; - priv->ssthresh = max(nInFlight / 2, 2 * priv->mss); - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "ssthresh: %u = (nInFlight: %u / 2) + " - "2 * mss: %u", priv->ssthresh, nInFlight, priv->mss); - //LOG(LS_INFO) << "priv->ssthresh: " << priv->ssthresh << " nInFlight: " << nInFlight << " priv->mss: " << priv->mss; - priv->cwnd = priv->mss; - - // Back off retransmit timer. Note: the limit is lower when connecting. - rto_limit = (priv->state < PSEUDO_TCP_ESTABLISHED) ? DEF_RTO : MAX_RTO; - priv->rx_rto = min(rto_limit, priv->rx_rto * 2); - priv->rto_base = now; - - priv->recover = priv->snd_nxt; - if (priv->dup_acks >= 3) { - priv->dup_acks = 0; - priv->fast_recovery = FALSE; - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "exit recovery on timeout"); - } - } - } - - // Check if it's time to probe closed windows - if ((priv->snd_wnd == 0) - && (time_diff(priv->lastsend + priv->rx_rto, now) <= 0)) { - if (time_diff(now, priv->lastrecv) >= 15000) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Receive window closed. Closing down."); - closedown (self, ECONNABORTED, CLOSEDOWN_LOCAL); - return; - } - - // probe the window - packet(self, priv->snd_nxt - 1, 0, 0, 0, now); - priv->lastsend = now; - - // back off retransmit timer - priv->rx_rto = min(MAX_RTO, priv->rx_rto * 2); - } - - // Check if it's time to send delayed acks - if (priv->t_ack && (time_diff(priv->t_ack + priv->ack_delay, now) <= 0)) { - packet(self, priv->snd_nxt, 0, 0, 0, now); - } - -} - -gboolean -pseudo_tcp_socket_notify_packet(PseudoTcpSocket *self, - const gchar * buffer, guint32 len) -{ - gboolean retval; - - if (len > MAX_PACKET) { - //LOG_F(WARNING) << "packet too large"; - self->priv->error = EMSGSIZE; - return FALSE; - } else if (len < HEADER_SIZE) { - //LOG_F(WARNING) << "packet too small"; - self->priv->error = EINVAL; - return FALSE; - } - - /* Hold a reference to the PseudoTcpSocket during parsing, since it may be - * closed from within a callback. */ - g_object_ref (self); - retval = parse (self, (guint8 *) buffer, HEADER_SIZE, - (guint8 *) buffer + HEADER_SIZE, len - HEADER_SIZE); - g_object_unref (self); - - return retval; -} - -/* Assume there are two buffers in the given #NiceInputMessage: a 24-byte one - * containing the header, and a bigger one for the data. */ -gboolean -pseudo_tcp_socket_notify_message (PseudoTcpSocket *self, - NiceInputMessage *message) -{ - gboolean retval; - - g_assert_cmpuint (message->n_buffers, >, 0); - - if (message->n_buffers == 1) - return pseudo_tcp_socket_notify_packet (self, message->buffers[0].buffer, - message->buffers[0].size); - - g_assert_cmpuint (message->n_buffers, ==, 2); - g_assert_cmpuint (message->buffers[0].size, ==, HEADER_SIZE); - - if (message->length > MAX_PACKET) { - //LOG_F(WARNING) << "packet too large"; - return FALSE; - } else if (message->length < HEADER_SIZE) { - //LOG_F(WARNING) << "packet too small"; - return FALSE; - } - - /* Hold a reference to the PseudoTcpSocket during parsing, since it may be - * closed from within a callback. */ - g_object_ref (self); - retval = parse (self, message->buffers[0].buffer, message->buffers[0].size, - message->buffers[1].buffer, message->length - message->buffers[0].size); - g_object_unref (self); - - return retval; -} - -gboolean -pseudo_tcp_socket_get_next_clock(PseudoTcpSocket *self, guint64 *timeout) -{ - PseudoTcpSocketPrivate *priv = self->priv; - guint32 now = get_current_time (self); - gsize snd_buffered; - guint32 closed_timeout; - - if (priv->shutdown == SD_FORCEFUL) { - if (priv->support_fin_ack) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "‘Forceful’ shutdown used when FIN-ACK support is enabled"); - } - - /* Transition to the CLOSED state. */ - closedown (self, 0, CLOSEDOWN_REMOTE); - - return FALSE; - } - - snd_buffered = pseudo_tcp_fifo_get_buffered (&priv->sbuf); - if ((priv->shutdown == SD_GRACEFUL) - && ((priv->state != PSEUDO_TCP_ESTABLISHED) - || ((snd_buffered == 0) && (priv->t_ack == 0)))) { - if (priv->support_fin_ack) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "‘Graceful’ shutdown used when FIN-ACK support is enabled"); - } - - /* Transition to the CLOSED state. */ - closedown (self, 0, CLOSEDOWN_REMOTE); - - return FALSE; - } - - /* FIN-ACK support. The timeout for closing the socket if nothing is received - * varies depending on whether the socket is waiting in the TIME-WAIT state - * for delayed segments to pass. - * - * See: http://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.html - */ - closed_timeout = CLOSED_TIMEOUT; - if (priv->support_fin_ack && priv->state == PSEUDO_TCP_TIME_WAIT) - closed_timeout = TIME_WAIT_TIMEOUT; - - if (priv->support_fin_ack && priv->state == PSEUDO_TCP_CLOSED) { - return FALSE; - } - - if (*timeout == 0 || *timeout < now) - *timeout = now + closed_timeout; - - if (priv->support_fin_ack && priv->state == PSEUDO_TCP_TIME_WAIT) { - *timeout = min (*timeout, now + TIME_WAIT_TIMEOUT); - return TRUE; - } - - if (priv->state == PSEUDO_TCP_CLOSED && !priv->support_fin_ack) { - *timeout = min (*timeout, now + CLOSED_TIMEOUT); - return TRUE; - } - - *timeout = min (*timeout, now + DEFAULT_TIMEOUT); - - if (priv->t_ack) { - *timeout = min(*timeout, priv->t_ack + priv->ack_delay); - } - if (priv->rto_base) { - *timeout = min(*timeout, priv->rto_base + priv->rx_rto); - } - if (priv->snd_wnd == 0) { - *timeout = min(*timeout, priv->lastsend + priv->rx_rto); - } - - return TRUE; -} - - -gint -pseudo_tcp_socket_recv(PseudoTcpSocket *self, char * buffer, size_t len) -{ - PseudoTcpSocketPrivate *priv = self->priv; - gsize bytesread; - gsize available_space; - - /* Received a FIN from the peer, so return 0. RFC 793, §3.5, Case 2. */ - if (priv->support_fin_ack && priv->shutdown_reads) { - return 0; - } - - /* Return 0 if FIN-ACK is not supported but the socket has been closed. */ - if (!priv->support_fin_ack && pseudo_tcp_socket_is_closed (self)) { - return 0; - } - - /* Return ENOTCONN if FIN-ACK is not supported and the connection is not - * ESTABLISHED. */ - if (!priv->support_fin_ack && priv->state != PSEUDO_TCP_ESTABLISHED) { - priv->error = ENOTCONN; - return -1; - } - - if (len == 0) - return 0; - - bytesread = pseudo_tcp_fifo_read (&priv->rbuf, (guint8 *) buffer, len); - - // If there's no data in |m_rbuf|. - if (bytesread == 0 && - !(pseudo_tcp_state_has_received_fin (priv->state) || - pseudo_tcp_state_has_received_fin_ack (priv->state))) { - priv->bReadEnable = TRUE; - priv->error = EWOULDBLOCK; - return -1; - } - - available_space = pseudo_tcp_fifo_get_write_remaining (&priv->rbuf); - - if (available_space - priv->rcv_wnd >= - min (priv->rbuf_len / 2, priv->mss)) { - // !?! Not sure about this was closed business - gboolean bWasClosed = (priv->rcv_wnd == 0); - - priv->rcv_wnd = available_space; - - if (bWasClosed) { - attempt_send(self, sfImmediateAck); - } - } - - return bytesread; -} - -gint -pseudo_tcp_socket_send(PseudoTcpSocket *self, const char * buffer, guint32 len) -{ - PseudoTcpSocketPrivate *priv = self->priv; - gint written; - gsize available_space; - - if (priv->state != PSEUDO_TCP_ESTABLISHED) { - priv->error = pseudo_tcp_state_has_sent_fin (priv->state) ? EPIPE : ENOTCONN; - return -1; - } - - available_space = pseudo_tcp_fifo_get_write_remaining (&priv->sbuf); - - if (!available_space) { - priv->bWriteEnable = TRUE; - priv->error = EWOULDBLOCK; - return -1; - } - - written = queue (self, buffer, len, FLAG_NONE); - attempt_send(self, sfNone); - - if (written > 0 && (guint32)written < len) { - priv->bWriteEnable = TRUE; - } - - return written; -} - -void -pseudo_tcp_socket_close(PseudoTcpSocket *self, gboolean force) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Closing socket %p %s", self, - force ? "forcefully" : "gracefully"); - - /* Forced closure by sending an RST segment. RFC 1122, §4.2.2.13. */ - if (force && priv->state != PSEUDO_TCP_CLOSED) { - closedown (self, ECONNABORTED, CLOSEDOWN_LOCAL); - return; - } - - /* Fall back to shutdown(). */ - pseudo_tcp_socket_shutdown (self, PSEUDO_TCP_SHUTDOWN_RDWR); -} - -void -pseudo_tcp_socket_shutdown (PseudoTcpSocket *self, PseudoTcpShutdown how) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Shutting down socket %p: %u", self, how); - - /* FIN-ACK--only stuff below here. */ - if (!priv->support_fin_ack) { - if (priv->shutdown == SD_NONE) - priv->shutdown = SD_GRACEFUL; - return; - } - - /* What needs shutting down? */ - switch (how) { - case PSEUDO_TCP_SHUTDOWN_RD: - case PSEUDO_TCP_SHUTDOWN_RDWR: - priv->shutdown_reads = TRUE; - break; - case PSEUDO_TCP_SHUTDOWN_WR: - /* Handled below. */ - break; - default: - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Invalid shutdown method: %u.", how); - break; - } - - if (how == PSEUDO_TCP_SHUTDOWN_RD) { - return; - } - - /* Unforced write closure. */ - switch (priv->state) { - case PSEUDO_TCP_LISTEN: - case PSEUDO_TCP_SYN_SENT: - /* Just abort the connection without completing the handshake. */ - set_state_closed (self, 0); - break; - case PSEUDO_TCP_SYN_RECEIVED: - case PSEUDO_TCP_ESTABLISHED: - /* Local user initiating the close: RFC 793, §3.5, Cases 1 and 3. - * If there is pending receive data, send RST instead of FIN; - * see RFC 1122, §4.2.2.13. */ - if (pseudo_tcp_socket_get_available_bytes (self) > 0) { - closedown (self, ECONNABORTED, CLOSEDOWN_LOCAL); - } else { - queue_fin_message (self); - attempt_send (self, sfFin); - set_state (self, PSEUDO_TCP_FIN_WAIT_1); - } - break; - case PSEUDO_TCP_CLOSE_WAIT: - /* Remote user initiating the close: RFC 793, §3.5, Case 2. - * We’ve previously received a FIN from the peer; now the user is closing - * the local end of the connection. */ - queue_fin_message (self); - attempt_send (self, sfFin); - set_state (self, PSEUDO_TCP_LAST_ACK); - break; - case PSEUDO_TCP_CLOSING: - case PSEUDO_TCP_CLOSED: - /* Already closed on both sides. */ - break; - case PSEUDO_TCP_FIN_WAIT_1: - case PSEUDO_TCP_FIN_WAIT_2: - case PSEUDO_TCP_TIME_WAIT: - case PSEUDO_TCP_LAST_ACK: - /* Already closed locally. */ - break; - default: - /* Do nothing. */ - break; - } -} - -int -pseudo_tcp_socket_get_error(PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - return priv->error; -} - -// -// Internal Implementation -// - -static guint32 -queue (PseudoTcpSocket *self, const gchar * data, guint32 len, TcpFlags flags) -{ - PseudoTcpSocketPrivate *priv = self->priv; - gsize available_space; - - available_space = pseudo_tcp_fifo_get_write_remaining (&priv->sbuf); - if (len > available_space) { - g_assert_cmpint (flags, ==, FLAG_NONE); - len = available_space; - } - - // We can concatenate data if the last segment is the same type - // (control v. regular data), and has not been transmitted yet - if (g_queue_get_length (&priv->slist) && - (((SSegment *)g_queue_peek_tail (&priv->slist))->flags == flags) && - (((SSegment *)g_queue_peek_tail (&priv->slist))->xmit == 0)) { - ((SSegment *)g_queue_peek_tail (&priv->slist))->len += len; - } else { - SSegment *sseg = g_slice_new0 (SSegment); - gsize snd_buffered = pseudo_tcp_fifo_get_buffered (&priv->sbuf); - - sseg->seq = priv->snd_una + snd_buffered; - sseg->len = len; - sseg->flags = flags; - g_queue_push_tail (&priv->slist, sseg); - g_queue_push_tail (&priv->unsent_slist, sseg); - } - - //LOG(LS_INFO) << "PseudoTcp::queue - priv->slen = " << priv->slen; - return pseudo_tcp_fifo_write (&priv->sbuf, (guint8*) data, len);; -} - -// Creates a packet and submits it to the network. This method can either -// send payload or just an ACK packet. -// -// |seq| is the sequence number of this packet. -// |flags| is the flags for sending this packet. -// |offset| is the offset to read from |m_sbuf|. -// |len| is the number of bytes to read from |m_sbuf| as payload. If this -// value is 0 then this is an ACK packet, otherwise this packet has payload. - -static PseudoTcpWriteResult -packet(PseudoTcpSocket *self, guint32 seq, TcpFlags flags, - guint32 offset, guint32 len, guint32 now) -{ - PseudoTcpSocketPrivate *priv = self->priv; - union { - guint8 u8[MAX_PACKET]; - guint16 u16[MAX_PACKET / 2]; - guint32 u32[MAX_PACKET / 4]; - } buffer; - PseudoTcpWriteResult wres = WR_SUCCESS; - - g_assert_cmpuint (HEADER_SIZE + len, <=, MAX_PACKET); - - *buffer.u32 = htonl(priv->conv); - *(buffer.u32 + 1) = htonl(seq); - *(buffer.u32 + 2) = htonl(priv->rcv_nxt); - buffer.u8[12] = 0; - buffer.u8[13] = flags; - *(buffer.u16 + 7) = htons((guint16)(priv->rcv_wnd >> priv->rwnd_scale)); - - // Timestamp computations - *(buffer.u32 + 4) = htonl(now); - *(buffer.u32 + 5) = htonl(priv->ts_recent); - priv->ts_lastack = priv->rcv_nxt; - - if (len) { - gsize bytes_read; - - bytes_read = pseudo_tcp_fifo_read_offset (&priv->sbuf, buffer.u8 + HEADER_SIZE, - len, offset); - g_assert_cmpint (bytes_read, ==, len); - } - - DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "Sending " - "", - priv->conv, (unsigned)flags, seq, seq + len, priv->rcv_nxt, priv->rcv_wnd, - now % 10000, priv->ts_recent % 10000, len); - - wres = priv->callbacks.WritePacket(self, (gchar *) buffer.u8, len + HEADER_SIZE, - priv->callbacks.user_data); - /* Note: When len is 0, this is an ACK packet. We don't read the - return value for those, and thus we won't retry. So go ahead and treat - the packet as a success (basically simulate as if it were dropped), - which will prevent our timers from being messed up. */ - if ((wres != WR_SUCCESS) && (0 != len)) - return wres; - - priv->t_ack = 0; - if (len > 0) { - priv->lastsend = now; - } - priv->last_traffic = now; - priv->bOutgoing = TRUE; - - return WR_SUCCESS; -} - -static gboolean -parse (PseudoTcpSocket *self, const guint8 *_header_buf, gsize header_buf_len, - const guint8 *data_buf, gsize data_buf_len) -{ - Segment seg; - - union { - const guint8 *u8; - const guint16 *u16; - const guint32 *u32; - } header_buf; - - header_buf.u8 = _header_buf; - - if (header_buf_len != 24) - return FALSE; - - seg.conv = ntohl(*header_buf.u32); - seg.seq = ntohl(*(header_buf.u32 + 1)); - seg.ack = ntohl(*(header_buf.u32 + 2)); - seg.flags = header_buf.u8[13]; - seg.wnd = ntohs(*(header_buf.u16 + 7)); - - seg.tsval = ntohl(*(header_buf.u32 + 4)); - seg.tsecr = ntohl(*(header_buf.u32 + 5)); - - seg.data = (const gchar *) data_buf; - seg.len = data_buf_len; - - DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, - "Received " - "", - seg.conv, (unsigned)seg.flags, seg.seq, seg.seq + seg.len, seg.ack, - seg.wnd, seg.tsval % 10000, seg.tsecr % 10000, seg.len); - - return process(self, &seg); -} - -/* True iff the @state requires that a FIN has already been sent by this - * host. */ -static gboolean -pseudo_tcp_state_has_sent_fin (PseudoTcpState state) -{ - switch (state) { - case PSEUDO_TCP_LISTEN: - case PSEUDO_TCP_SYN_SENT: - case PSEUDO_TCP_SYN_RECEIVED: - case PSEUDO_TCP_ESTABLISHED: - case PSEUDO_TCP_CLOSE_WAIT: - return FALSE; - case PSEUDO_TCP_CLOSED: - case PSEUDO_TCP_FIN_WAIT_1: - case PSEUDO_TCP_FIN_WAIT_2: - case PSEUDO_TCP_CLOSING: - case PSEUDO_TCP_TIME_WAIT: - case PSEUDO_TCP_LAST_ACK: - return TRUE; - default: - return FALSE; - } -} - -/* True iff the @state requires that a FIN has already been received from the - * peer. */ -static gboolean -pseudo_tcp_state_has_received_fin (PseudoTcpState state) -{ - switch (state) { - case PSEUDO_TCP_LISTEN: - case PSEUDO_TCP_SYN_SENT: - case PSEUDO_TCP_SYN_RECEIVED: - case PSEUDO_TCP_ESTABLISHED: - case PSEUDO_TCP_FIN_WAIT_1: - case PSEUDO_TCP_FIN_WAIT_2: - return FALSE; - case PSEUDO_TCP_CLOSED: - case PSEUDO_TCP_CLOSING: - case PSEUDO_TCP_TIME_WAIT: - case PSEUDO_TCP_CLOSE_WAIT: - case PSEUDO_TCP_LAST_ACK: - return TRUE; - default: - return FALSE; - } -} - -/* True iff the @state requires that a FIN-ACK has already been received from - * the peer. */ -static gboolean -pseudo_tcp_state_has_received_fin_ack (PseudoTcpState state) -{ - switch (state) { - case PSEUDO_TCP_LISTEN: - case PSEUDO_TCP_SYN_SENT: - case PSEUDO_TCP_SYN_RECEIVED: - case PSEUDO_TCP_ESTABLISHED: - case PSEUDO_TCP_FIN_WAIT_1: - case PSEUDO_TCP_FIN_WAIT_2: - case PSEUDO_TCP_CLOSING: - case PSEUDO_TCP_CLOSE_WAIT: - case PSEUDO_TCP_LAST_ACK: - return FALSE; - case PSEUDO_TCP_CLOSED: - case PSEUDO_TCP_TIME_WAIT: - return TRUE; - default: - return FALSE; - } -} - -static gboolean -process(PseudoTcpSocket *self, Segment *seg) -{ - PseudoTcpSocketPrivate *priv = self->priv; - guint32 now; - SendFlags sflags = sfNone; - gboolean bIgnoreData; - gboolean bNewData; - gboolean bConnect = FALSE; - gsize snd_buffered; - gsize available_space; - guint32 kIdealRefillSize; - gboolean is_valuable_ack, is_duplicate_ack, is_fin_ack = FALSE; - gboolean received_fin = FALSE; - - /* If this is the wrong conversation, send a reset!?! - (with the correct conversation?) */ - if (seg->conv != priv->conv) { - //if ((seg->flags & FLAG_RST) == 0) { - // packet(sock, tcb, seg->ack, 0, FLAG_RST, 0, 0); - //} - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "wrong conversation"); - return FALSE; - } - - now = get_current_time (self); - priv->last_traffic = priv->lastrecv = now; - priv->bOutgoing = FALSE; - - if (priv->state == PSEUDO_TCP_CLOSED || - (pseudo_tcp_state_has_received_fin_ack (priv->state) && seg->len > 0)) { - /* Send an RST segment. See: RFC 1122, §4.2.2.13; RFC 793, §3.4, point 3, - * page 37. We can only send RST if we know the peer knows we’re closed; - * otherwise this could be a timeout retransmit from them, due to our - * packets from data through to FIN being dropped. */ - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Segment received while closed; sending RST."); - if ((seg->flags & FLAG_RST) == 0) { - closedown (self, 0, CLOSEDOWN_LOCAL); - } - - return FALSE; - } - - // Check if this is a reset segment - if (seg->flags & FLAG_RST) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Received RST segment; closing down."); - closedown (self, ECONNRESET, CLOSEDOWN_REMOTE); - return FALSE; - } - - // Check for control data - bConnect = FALSE; - if (seg->flags & FLAG_CTL) { - if (seg->len == 0) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Missing control code"); - return FALSE; - } else if (seg->data[0] == CTL_CONNECT) { - bConnect = TRUE; - - parse_options (self, (guint8 *) &seg->data[1], seg->len - 1); - - if (priv->state == PSEUDO_TCP_LISTEN) { - set_state (self, PSEUDO_TCP_SYN_RECEIVED); - queue_connect_message (self); - } else if (priv->state == PSEUDO_TCP_SYN_SENT) { - set_state_established (self); - } - } else { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Unknown control code: %u", seg->data[0]); - return FALSE; - } - } - - // Update timestamp - if (SMALLER_OR_EQUAL (seg->seq, priv->ts_lastack) && - SMALLER (priv->ts_lastack, seg->seq + seg->len)) { - priv->ts_recent = seg->tsval; - } - - // Check if this is a valuable ack - is_valuable_ack = (LARGER(seg->ack, priv->snd_una) && - SMALLER_OR_EQUAL(seg->ack, priv->snd_nxt)); - is_duplicate_ack = (seg->ack == priv->snd_una); - - if (is_valuable_ack) { - guint32 nAcked; - guint32 nFree; - - // Calculate round-trip time - if (seg->tsecr) { - long rtt = time_diff(now, seg->tsecr); - if (rtt >= 0) { - if (priv->rx_srtt == 0) { - priv->rx_srtt = rtt; - priv->rx_rttvar = rtt / 2; - } else { - priv->rx_rttvar = (3 * priv->rx_rttvar + - labs((long)(rtt - priv->rx_srtt))) / 4; - priv->rx_srtt = (7 * priv->rx_srtt + rtt) / 8; - } - priv->rx_rto = bound(MIN_RTO, - priv->rx_srtt + max(1LU, 4 * priv->rx_rttvar), MAX_RTO); - - DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "rtt: %ld srtt: %u rttvar: %u rto: %u", - rtt, priv->rx_srtt, priv->rx_rttvar, priv->rx_rto); - } else { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Invalid RTT: %ld", rtt); - return FALSE; - } - - priv->last_acked_ts = seg->tsecr; - } - - priv->snd_wnd = seg->wnd << priv->swnd_scale; - - nAcked = seg->ack - priv->snd_una; - priv->snd_una = seg->ack; - - priv->rto_base = (priv->snd_una == priv->snd_nxt) ? 0 : now; - - /* ACKs for FIN segments give an increment on nAcked, but there is no - * corresponding byte to read because the FIN segment is empty (it just has - * a sequence number). */ - if (nAcked == priv->sbuf.data_length + 1 && - pseudo_tcp_state_has_sent_fin (priv->state)) { - is_fin_ack = TRUE; - nAcked--; - } - - pseudo_tcp_fifo_consume_read_data (&priv->sbuf, nAcked); - - for (nFree = nAcked; nFree > 0; ) { - SSegment *data; - - g_assert_cmpuint (g_queue_get_length (&priv->slist), !=, 0); - data = (SSegment *) g_queue_peek_head (&priv->slist); - - if (nFree < data->len) { - data->len -= nFree; - data->seq += nFree; - nFree = 0; - } else { - if (data->len > priv->largest) { - priv->largest = data->len; - } - nFree -= data->len; - g_slice_free (SSegment, data); - g_queue_pop_head (&priv->slist); - } - } - - if (priv->dup_acks >= 3) { - if (LARGER_OR_EQUAL (priv->snd_una, priv->recover)) { // NewReno - guint32 nInFlight = priv->snd_nxt - priv->snd_una; - // (Fast Retransmit) - priv->cwnd = min(priv->ssthresh, - max (nInFlight, priv->mss) + priv->mss); - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "exit recovery cwnd=%d ssthresh=%d nInFlight=%d mss: %d", priv->cwnd, priv->ssthresh, nInFlight, priv->mss); - priv->fast_recovery = FALSE; - priv->dup_acks = 0; - } else { - int transmit_status; - - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "recovery retransmit"); - transmit_status = transmit(self, g_queue_peek_head (&priv->slist), now); - if (transmit_status != 0) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Error transmitting recovery retransmit segment. Closing down."); - closedown (self, transmit_status, CLOSEDOWN_LOCAL); - return FALSE; - } - priv->cwnd += (nAcked > priv->mss ? priv->mss : 0) - - min(nAcked, priv->cwnd); - } - } else { - priv->dup_acks = 0; - // Slow start, congestion avoidance - if (priv->cwnd < priv->ssthresh) { - priv->cwnd += priv->mss; - } else { - priv->cwnd += max(1LU, priv->mss * priv->mss / priv->cwnd); - } - } - } else if (is_duplicate_ack) { - /* !?! Note, tcp says don't do this... but otherwise how does a - closed window become open? */ - priv->snd_wnd = seg->wnd << priv->swnd_scale; - - // Check duplicate acks - if (seg->len > 0) { - // it's a dup ack, but with a data payload, so don't modify priv->dup_acks - } else if (priv->snd_una != priv->snd_nxt) { - guint32 nInFlight; - - priv->dup_acks += 1; - DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "Received dup ack (dups: %u)", - priv->dup_acks); - if (priv->dup_acks == 3) { // (Fast Retransmit) - int transmit_status; - - - if (LARGER_OR_EQUAL (priv->snd_una, priv->recover) || - seg->tsecr == priv->last_acked_ts) { /* NewReno */ - /* Invoke fast retransmit RFC3782 section 3 step 1A*/ - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "enter recovery"); - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "recovery retransmit"); - - transmit_status = transmit(self, g_queue_peek_head (&priv->slist), - now); - if (transmit_status != 0) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Error transmitting recovery retransmit segment. Closing down."); - - closedown (self, transmit_status, CLOSEDOWN_LOCAL); - return FALSE; - } - priv->recover = priv->snd_nxt; - nInFlight = priv->snd_nxt - priv->snd_una; - priv->ssthresh = max(nInFlight / 2, 2 * priv->mss); - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "ssthresh: %u = max((nInFlight: %u / 2), 2 * mss: %u)", - priv->ssthresh, nInFlight, priv->mss); - priv->cwnd = priv->ssthresh + 3 * priv->mss; - priv->fast_recovery = TRUE; - } else { - DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, - "Skipping fast recovery: recover: %u snd_una: %u", priv->recover, - priv->snd_una); - } - } else if (priv->dup_acks > 3) { - if (priv->fast_recovery) - priv->cwnd += priv->mss; - } - } else { - priv->dup_acks = 0; - } - } - - // !?! A bit hacky - if ((priv->state == PSEUDO_TCP_SYN_RECEIVED) && !bConnect) { - set_state_established (self); - } - - /* Check for connection closure. Only pay attention to FIN segments if they - * are in sequence; otherwise we’ve missed a packet earlier in the stream and - * need to request retransmission first. */ - if (priv->support_fin_ack) { - /* @received_fin is set when, and only when, all segments preceding the FIN - * have been acknowledged. This is to handle the case where the FIN arrives - * out of order with a preceding data segment. */ - if (seg->flags & FLAG_FIN) { - priv->rcv_fin = seg->seq; - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Setting rcv_fin = %u", priv->rcv_fin); - } - - /* For the moment, FIN segments must not contain data. */ - if (seg->flags & FLAG_FIN && seg->len != 0) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "FIN segment contained data; ignored"); - return FALSE; - } - - received_fin = (priv->rcv_nxt != 0 && priv->rcv_nxt + seg->len == priv->rcv_fin); - - /* Update the state machine, implementing all transitions on ‘rcv FIN’ or - * ‘rcv ACK of FIN’ from RFC 793, Figure 6; and RFC 1122, §4.2.2.8. */ - switch (priv->state) { - case PSEUDO_TCP_ESTABLISHED: - if (received_fin) { - /* Received a FIN from the network, RFC 793, §3.5, Case 2. - * The code below will send an ACK for the FIN. */ - set_state (self, PSEUDO_TCP_CLOSE_WAIT); - } - break; - case PSEUDO_TCP_CLOSING: - if (is_fin_ack) { - /* Handle the ACK of a locally-sent FIN flag. RFC 793, §3.5, Case 3. */ - set_state (self, PSEUDO_TCP_TIME_WAIT); - } - break; - case PSEUDO_TCP_LAST_ACK: - if (is_fin_ack) { - /* Handle the ACK of a locally-sent FIN flag. RFC 793, §3.5, Case 2. */ - set_state_closed (self, 0); - } - break; - case PSEUDO_TCP_FIN_WAIT_1: - if (is_fin_ack && received_fin) { - /* Simultaneous close with an ACK for a FIN previously sent, - * RFC 793, §3.5, Case 3. */ - set_state (self, PSEUDO_TCP_TIME_WAIT); - } else if (is_fin_ack) { - /* Handle the ACK of a locally-sent FIN flag. RFC 793, §3.5, Case 1. */ - set_state (self, PSEUDO_TCP_FIN_WAIT_2); - } else if (received_fin) { - /* Simultaneous close, RFC 793, §3.5, Case 3. */ - set_state (self, PSEUDO_TCP_CLOSING); - } - break; - case PSEUDO_TCP_FIN_WAIT_2: - if (received_fin) { - /* Local user closed the connection, RFC 793, §3.5, Case 1. */ - set_state (self, PSEUDO_TCP_TIME_WAIT); - } - break; - case PSEUDO_TCP_LISTEN: - case PSEUDO_TCP_SYN_SENT: - case PSEUDO_TCP_SYN_RECEIVED: - case PSEUDO_TCP_TIME_WAIT: - case PSEUDO_TCP_CLOSED: - case PSEUDO_TCP_CLOSE_WAIT: - /* Shouldn’t ever hit these cases. */ - if (received_fin) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Unexpected state %u when FIN received", priv->state); - } else if (is_fin_ack) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Unexpected state %u when FIN-ACK received", priv->state); - } - break; - default: - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Invalid state %u when FIN received", - priv->state); - return FALSE; - } - } else if (seg->flags & FLAG_FIN) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Invalid FIN received when FIN-ACK support is disabled"); - } else if (is_fin_ack) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Invalid FIN-ACK received when FIN-ACK support is disabled"); - } - - // If we make room in the send queue, notify the user - // The goal it to make sure we always have at least enough data to fill the - // window. We'd like to notify the app when we are halfway to that point. - kIdealRefillSize = (priv->sbuf_len + priv->rbuf_len) / 2; - - snd_buffered = pseudo_tcp_fifo_get_buffered (&priv->sbuf); - if (priv->bWriteEnable && snd_buffered < kIdealRefillSize) { - priv->bWriteEnable = FALSE; - if (priv->callbacks.PseudoTcpWritable) - priv->callbacks.PseudoTcpWritable(self, priv->callbacks.user_data); - } - - /* Conditions where acks must be sent: - * 1) Segment is too old (they missed an ACK) (immediately) - * 2) Segment is too new (we missed a segment) (immediately) - * 3) Segment has data (so we need to ACK!) (delayed) - * ... so the only time we don't need to ACK, is an empty segment - * that points to rcv_nxt! - * 4) Segment has the FIN flag set (immediately) — note that the FIN flag - * itself has to be included in the ACK as a numbered byte; - * see RFC 793, §3.3. Also see: RFC 793, §3.5. - */ - if (seg->seq != priv->rcv_nxt) { - sflags = sfDuplicateAck; // (Fast Recovery) - } else if (seg->len != 0) { - if (priv->ack_delay == 0) { - sflags = sfImmediateAck; - } else { - sflags = sfDelayedAck; - } - } else if (received_fin) { - /* FIN flags have a sequence number. Only acknowledge them after all - * preceding octets have been acknowledged. */ - sflags = sfImmediateAck; - } - - if (sflags == sfDuplicateAck) { - if (seg->seq > priv->rcv_nxt) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "too new"); - } else if (SMALLER_OR_EQUAL(seg->seq + seg->len, priv->rcv_nxt)) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "too old"); - } - } - - // Adjust the incoming segment to fit our receive buffer - if (SMALLER(seg->seq, priv->rcv_nxt)) { - guint32 nAdjust = priv->rcv_nxt - seg->seq; - if (nAdjust < seg->len) { - seg->seq += nAdjust; - seg->data += nAdjust; - seg->len -= nAdjust; - } else { - seg->len = 0; - } - } - - available_space = pseudo_tcp_fifo_get_write_remaining (&priv->rbuf); - - if ((seg->seq + seg->len - priv->rcv_nxt) > available_space) { - guint32 nAdjust = seg->seq + seg->len - priv->rcv_nxt - available_space; - if (nAdjust < seg->len) { - seg->len -= nAdjust; - } else { - seg->len = 0; - } - } - - bIgnoreData = (seg->flags & FLAG_CTL); - if (!priv->support_fin_ack) - bIgnoreData |= (priv->shutdown != SD_NONE); - - bNewData = FALSE; - - if (seg->len > 0) { - if (bIgnoreData) { - if (seg->seq == priv->rcv_nxt) { - priv->rcv_nxt += seg->len; - } - } else { - guint32 nOffset = seg->seq - priv->rcv_nxt; - gsize res; - - res = pseudo_tcp_fifo_write_offset (&priv->rbuf, (guint8 *) seg->data, - seg->len, nOffset); - g_assert_cmpint (res, ==, seg->len); - - if (seg->seq == priv->rcv_nxt) { - GList *iter = NULL; - - pseudo_tcp_fifo_consume_write_buffer (&priv->rbuf, seg->len); - priv->rcv_nxt += seg->len; - priv->rcv_wnd -= seg->len; - bNewData = TRUE; - - iter = priv->rlist; - while (iter && - SMALLER_OR_EQUAL(((RSegment *)iter->data)->seq, priv->rcv_nxt)) { - RSegment *data = (RSegment *)(iter->data); - if (LARGER (data->seq + data->len, priv->rcv_nxt)) { - guint32 nAdjust = (data->seq + data->len) - priv->rcv_nxt; - sflags = sfImmediateAck; // (Fast Recovery) - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Recovered %u bytes (%u -> %u)", - nAdjust, priv->rcv_nxt, priv->rcv_nxt + nAdjust); - pseudo_tcp_fifo_consume_write_buffer (&priv->rbuf, nAdjust); - priv->rcv_nxt += nAdjust; - priv->rcv_wnd -= nAdjust; - } - g_slice_free (RSegment, priv->rlist->data); - priv->rlist = g_list_delete_link (priv->rlist, priv->rlist); - iter = priv->rlist; - } - } else { - GList *iter = NULL; - RSegment *rseg = g_slice_new0 (RSegment); - - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Saving %u bytes (%u -> %u)", - seg->len, seg->seq, seg->seq + seg->len); - rseg->seq = seg->seq; - rseg->len = seg->len; - iter = priv->rlist; - while (iter && SMALLER (((RSegment*)iter->data)->seq, rseg->seq)) { - iter = g_list_next (iter); - } - priv->rlist = g_list_insert_before(priv->rlist, iter, rseg); - } - } - } - - if (received_fin) { - /* FIN flags have a sequence number. */ - priv->rcv_nxt++; - } - - - attempt_send(self, sflags); - - // If we have new data, notify the user - if (bNewData && priv->bReadEnable) { - /* priv->bReadEnable = FALSE; — removed so that we’re always notified of - * incoming pseudo-TCP data, rather than having to read the entire buffer - * on each readable() callback before the next callback is enabled. - * (When client-provided buffers are small, this is not possible.) */ - if (priv->callbacks.PseudoTcpReadable) - priv->callbacks.PseudoTcpReadable(self, priv->callbacks.user_data); - } - - return TRUE; -} - -static gboolean -transmit(PseudoTcpSocket *self, SSegment *segment, guint32 now) -{ - PseudoTcpSocketPrivate *priv = self->priv; - guint32 nTransmit = min(segment->len, priv->mss); - - if (segment->xmit >= ((priv->state == PSEUDO_TCP_ESTABLISHED) ? 15 : 30)) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "too many retransmits"); - return ETIMEDOUT; - } - - while (TRUE) { - guint32 seq = segment->seq; - guint8 flags = segment->flags; - PseudoTcpWriteResult wres; - - /* The packet must not have already been acknowledged. */ - g_assert_cmpuint (segment->seq - priv->snd_una, <=, 1024 * 1024 * 64); - - /* Write out the packet. */ - wres = packet(self, seq, flags, - segment->seq - priv->snd_una, nTransmit, now); - - if (wres == WR_SUCCESS) - break; - - if (wres == WR_FAIL) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "packet failed"); - return ECONNABORTED; /* FIXME: This error code doesn’t quite seem right */ - } - - g_assert_cmpint (wres, ==, WR_TOO_LARGE); - - while (TRUE) { - if (PACKET_MAXIMUMS[priv->msslevel + 1] == 0) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "MTU too small"); - return EMSGSIZE; - } - /* !?! We need to break up all outstanding and pending packets - and then retransmit!?! */ - - priv->mss = PACKET_MAXIMUMS[++priv->msslevel] - PACKET_OVERHEAD; - // I added this... haven't researched actual formula - priv->cwnd = 2 * priv->mss; - - if (priv->mss < nTransmit) { - nTransmit = priv->mss; - break; - } - } - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Adjusting mss to %u bytes ", priv->mss); - } - - if (nTransmit < segment->len) { - SSegment *subseg = g_slice_new0 (SSegment); - subseg->seq = segment->seq + nTransmit; - subseg->len = segment->len - nTransmit; - subseg->flags = segment->flags; - subseg->xmit = segment->xmit; - - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "mss reduced to %u", priv->mss); - - segment->len = nTransmit; - g_queue_insert_after (&priv->slist, - g_queue_find (&priv->slist, segment), subseg); - if (subseg->xmit == 0) - g_queue_insert_after (&priv->unsent_slist, - g_queue_find (&priv->unsent_slist, segment), subseg); - } - - if (segment->xmit == 0) { - g_assert (g_queue_peek_head (&priv->unsent_slist) == segment); - g_queue_pop_head (&priv->unsent_slist); - priv->snd_nxt += segment->len; - - /* FIN flags require acknowledgement. */ - if (segment->len == 0 && segment->flags & FLAG_FIN) - priv->snd_nxt++; - } - segment->xmit += 1; - - if (priv->rto_base == 0) { - priv->rto_base = now; - } - - return 0; -} - -static void -attempt_send(PseudoTcpSocket *self, SendFlags sflags) -{ - PseudoTcpSocketPrivate *priv = self->priv; - guint32 now = get_current_time (self); - gboolean bFirst = TRUE; - - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Attempting send with flags %u.", sflags); - - if (time_diff(now, priv->lastsend) > (long) priv->rx_rto) { - priv->cwnd = priv->mss; - } - - - while (TRUE) { - guint32 cwnd; - guint32 nWindow; - guint32 nInFlight; - guint32 nUseable; - guint32 nAvailable; - gsize snd_buffered; - GList *iter; - SSegment *sseg; - int transmit_status; - - cwnd = priv->cwnd; - if ((priv->dup_acks == 1) || (priv->dup_acks == 2)) { // Limited Transmit - cwnd += priv->dup_acks * priv->mss; - } - nWindow = min(priv->snd_wnd, cwnd); - nInFlight = priv->snd_nxt - priv->snd_una; - nUseable = (nInFlight < nWindow) ? (nWindow - nInFlight) : 0; - snd_buffered = pseudo_tcp_fifo_get_buffered (&priv->sbuf); - if (snd_buffered < nInFlight) /* iff a FIN has been sent */ - nAvailable = 0; - else - nAvailable = min(snd_buffered - nInFlight, priv->mss); - - if (nAvailable > nUseable) { - if (nUseable * 4 < nWindow) { - // RFC 813 - avoid SWS - nAvailable = 0; - } else { - nAvailable = nUseable; - } - } - - if (bFirst) { - gsize available_space = pseudo_tcp_fifo_get_write_remaining (&priv->sbuf); - - bFirst = FALSE; - DEBUG (PSEUDO_TCP_DEBUG_VERBOSE, "[cwnd: %u nWindow: %u nInFlight: %u " - "nAvailable: %u nQueued: %" G_GSIZE_FORMAT " nEmpty: %" G_GSIZE_FORMAT - " nWaiting: %zu ssthresh: %u]", - priv->cwnd, nWindow, nInFlight, nAvailable, snd_buffered, - available_space, snd_buffered - nInFlight, priv->ssthresh); - } - - if (sflags == sfDuplicateAck) { - packet(self, priv->snd_nxt, 0, 0, 0, now); - sflags = sfNone; - continue; - } - - if (nAvailable == 0 && sflags != sfFin && sflags != sfRst) { - if (sflags == sfNone) - return; - - // If this is an immediate ack, or the second delayed ack - if ((sflags == sfImmediateAck || sflags == sfDuplicateAck) || - priv->t_ack) { - packet(self, priv->snd_nxt, 0, 0, 0, now); - } else { - priv->t_ack = now; - } - return; - } - - // Nagle algorithm - // If there is data already in-flight, and we haven't a full segment of - // data ready to send then hold off until we get more to send, or the - // in-flight data is acknowledged. - if (priv->use_nagling && sflags != sfFin && sflags != sfRst && - (priv->snd_nxt > priv->snd_una) && - (nAvailable < priv->mss)) { - return; - } - - // Find the next segment to transmit - iter = g_queue_peek_head_link (&priv->unsent_slist); - if (iter == NULL) - return; - sseg = iter->data; - - // If the segment is too large, break it into two - if (sseg->len > nAvailable && sflags != sfFin && sflags != sfRst) { - SSegment *subseg = g_slice_new0 (SSegment); - subseg->seq = sseg->seq + nAvailable; - subseg->len = sseg->len - nAvailable; - subseg->flags = sseg->flags; - - sseg->len = nAvailable; - g_queue_insert_after (&priv->unsent_slist, iter, subseg); - g_queue_insert_after (&priv->slist, g_queue_find (&priv->slist, sseg), - subseg); - } - - transmit_status = transmit(self, sseg, now); - if (transmit_status != 0) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "transmit failed"); - - // TODO: Is this the right thing ? - closedown (self, transmit_status, CLOSEDOWN_REMOTE); - return; - } - - if (sflags == sfImmediateAck || sflags == sfDelayedAck) - sflags = sfNone; - } -} - -/* If @source is %CLOSEDOWN_REMOTE, don’t send an RST packet, since closedown() - * has been called as a result of an RST segment being received. - * See: RFC 1122, §4.2.2.13. */ -static void -closedown (PseudoTcpSocket *self, guint32 err, ClosedownSource source) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Closing down socket %p with %s error %u.", - self, (source == CLOSEDOWN_LOCAL) ? "local" : "remote", err); - - if (source == CLOSEDOWN_LOCAL && priv->support_fin_ack) { - queue_rst_message (self); - attempt_send (self, sfRst); - } else if (source == CLOSEDOWN_LOCAL) { - priv->shutdown = SD_FORCEFUL; - } - - /* ‘Cute’ little navigation through the state machine to avoid breaking the - * invariant that CLOSED can only be reached from TIME-WAIT or LAST-ACK. */ - switch (priv->state) { - case PSEUDO_TCP_LISTEN: - case PSEUDO_TCP_SYN_SENT: - break; - case PSEUDO_TCP_SYN_RECEIVED: - case PSEUDO_TCP_ESTABLISHED: - set_state (self, PSEUDO_TCP_FIN_WAIT_1); - /* Fall through. */ - case PSEUDO_TCP_FIN_WAIT_1: - set_state (self, PSEUDO_TCP_FIN_WAIT_2); - /* Fall through. */ - case PSEUDO_TCP_FIN_WAIT_2: - case PSEUDO_TCP_CLOSING: - set_state (self, PSEUDO_TCP_TIME_WAIT); - break; - case PSEUDO_TCP_CLOSE_WAIT: - set_state (self, PSEUDO_TCP_LAST_ACK); - break; - case PSEUDO_TCP_LAST_ACK: - case PSEUDO_TCP_TIME_WAIT: - case PSEUDO_TCP_CLOSED: - default: - break; - } - - set_state_closed (self, err); -} - -static void -adjustMTU(PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - // Determine our current mss level, so that we can adjust appropriately later - for (priv->msslevel = 0; - PACKET_MAXIMUMS[priv->msslevel + 1] > 0; - ++priv->msslevel) { - if (((guint16)PACKET_MAXIMUMS[priv->msslevel]) <= priv->mtu_advise) { - break; - } - } - priv->mss = priv->mtu_advise - PACKET_OVERHEAD; - // !?! Should we reset priv->largest here? - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Adjusting mss to %u bytes", priv->mss); - // Enforce minimums on ssthresh and cwnd - priv->ssthresh = max(priv->ssthresh, 2 * priv->mss); - priv->cwnd = max(priv->cwnd, priv->mss); -} - -static void -apply_window_scale_option (PseudoTcpSocket *self, guint8 scale_factor) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - priv->swnd_scale = scale_factor; - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Setting scale factor to %u", scale_factor); -} - -static void -apply_fin_ack_option (PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - priv->support_fin_ack = TRUE; -} - -static void -apply_option (PseudoTcpSocket *self, guint8 kind, const guint8 *data, - guint32 len) -{ - switch (kind) { - case TCP_OPT_MSS: - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, - "Peer specified MSS option which is not supported."); - // TODO: Implement. - break; - case TCP_OPT_WND_SCALE: - // Window scale factor. - // http://www.ietf.org/rfc/rfc1323.txt - if (len != 1) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Invalid window scale option received."); - return; - } - apply_window_scale_option(self, data[0]); - break; - case TCP_OPT_FIN_ACK: - // FIN-ACK support. - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "FIN-ACK support enabled."); - apply_fin_ack_option (self); - break; - case TCP_OPT_EOL: - case TCP_OPT_NOOP: - /* Nothing to do. */ - break; - default: - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Invalid TCP option %u", kind); - break; - } -} - - -static void -parse_options (PseudoTcpSocket *self, const guint8 *data, guint32 len) -{ - PseudoTcpSocketPrivate *priv = self->priv; - gboolean has_window_scaling_option = FALSE; - gboolean has_fin_ack_option = FALSE; - guint32 pos = 0; - - // See http://www.freesoft.org/CIE/Course/Section4/8.htm for - // parsing the options list. - while (pos < len) { - guint8 kind = TCP_OPT_EOL; - guint8 opt_len; - - if (len < pos + 1) - return; - - kind = data[pos]; - pos++; - - if (kind == TCP_OPT_EOL) { - // End of option list. - break; - } else if (kind == TCP_OPT_NOOP) { - // No op. - continue; - } - - if (len < pos + 1) - return; - - // Length of this option. - opt_len = data[pos]; - pos++; - - if (len < pos + opt_len) - return; - - // Content of this option. - if (opt_len <= len - pos) { - apply_option (self, kind, data + pos, opt_len); - pos += opt_len; - } else { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Invalid option length received."); - return; - } - - if (kind == TCP_OPT_WND_SCALE) - has_window_scaling_option = TRUE; - else if (kind == TCP_OPT_FIN_ACK) - has_fin_ack_option = TRUE; - } - - if (!has_window_scaling_option) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Peer doesn't support window scaling"); - if (priv->rwnd_scale > 0) { - // Peer doesn't support TCP options and window scaling. - // Revert receive buffer size to default value. - resize_receive_buffer (self, DEFAULT_RCV_BUF_SIZE); - priv->swnd_scale = 0; - } - } - - if (!has_fin_ack_option) { - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "Peer doesn't support FIN-ACK"); - priv->support_fin_ack = FALSE; - } -} - -static void -resize_send_buffer (PseudoTcpSocket *self, guint32 new_size) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - priv->sbuf_len = new_size; - pseudo_tcp_fifo_set_capacity (&priv->sbuf, new_size); -} - - -static void -resize_receive_buffer (PseudoTcpSocket *self, guint32 new_size) -{ - PseudoTcpSocketPrivate *priv = self->priv; - guint8 scale_factor = 0; - gboolean result; - gsize available_space; - - if (priv->rbuf_len == new_size) - return; - - // Determine the scale factor such that the scaled window size can fit - // in a 16-bit unsigned integer. - while (new_size > 0xFFFF) { - ++scale_factor; - new_size >>= 1; - } - - // Determine the proper size of the buffer. - new_size <<= scale_factor; - result = pseudo_tcp_fifo_set_capacity (&priv->rbuf, new_size); - - // Make sure the new buffer is large enough to contain data in the old - // buffer. This should always be true because this method is called either - // before connection is established or when peers are exchanging connect - // messages. - g_assert (result); - priv->rbuf_len = new_size; - priv->rwnd_scale = scale_factor; - priv->ssthresh = new_size; - - available_space = pseudo_tcp_fifo_get_write_remaining (&priv->rbuf); - priv->rcv_wnd = available_space; -} - -gint -pseudo_tcp_socket_get_available_bytes (PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - return pseudo_tcp_fifo_get_buffered (&priv->rbuf); -} - -gboolean -pseudo_tcp_socket_can_send (PseudoTcpSocket *self) -{ - return (pseudo_tcp_socket_get_available_send_space (self) > 0); -} - -gsize -pseudo_tcp_socket_get_available_send_space (PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - gsize ret; - - if (!pseudo_tcp_state_has_sent_fin (priv->state)) { - ret = pseudo_tcp_fifo_get_write_remaining (&priv->sbuf); - } else { - ret = 0; - } - - if (ret == 0) - priv->bWriteEnable = TRUE; - - return ret; -} - -/* State names are capitalised and formatted as in RFC 793. */ -static const gchar * -pseudo_tcp_state_get_name (PseudoTcpState state) -{ - switch (state) { - case PSEUDO_TCP_LISTEN: return "LISTEN"; - case PSEUDO_TCP_SYN_SENT: return "SYN-SENT"; - case PSEUDO_TCP_SYN_RECEIVED: return "SYN-RECEIVED"; - case PSEUDO_TCP_ESTABLISHED: return "ESTABLISHED"; - case PSEUDO_TCP_CLOSED: return "CLOSED"; - case PSEUDO_TCP_FIN_WAIT_1: return "FIN-WAIT-1"; - case PSEUDO_TCP_FIN_WAIT_2: return "FIN-WAIT-2"; - case PSEUDO_TCP_CLOSING: return "CLOSING"; - case PSEUDO_TCP_TIME_WAIT: return "TIME-WAIT"; - case PSEUDO_TCP_CLOSE_WAIT: return "CLOSE-WAIT"; - case PSEUDO_TCP_LAST_ACK: return "LAST-ACK"; - default: return "UNKNOWN"; - } -} - -static void -set_state (PseudoTcpSocket *self, PseudoTcpState new_state) -{ - PseudoTcpSocketPrivate *priv = self->priv; - PseudoTcpState old_state = priv->state; - - if (new_state == old_state) - return; - - DEBUG (PSEUDO_TCP_DEBUG_NORMAL, "State %s → %s.", - pseudo_tcp_state_get_name (old_state), - pseudo_tcp_state_get_name (new_state)); - - /* Check whether it’s a valid state transition. */ -#define TRANSITION(OLD, NEW) \ - (old_state == PSEUDO_TCP_##OLD && \ - new_state == PSEUDO_TCP_##NEW) - - /* Valid transitions. See: RFC 793, p23; RFC 1122, §4.2.2.8. */ - g_assert (/* RFC 793, p23. */ - TRANSITION (CLOSED, SYN_SENT) || - TRANSITION (SYN_SENT, CLOSED) || - TRANSITION (CLOSED, LISTEN) || - TRANSITION (LISTEN, CLOSED) || - TRANSITION (LISTEN, SYN_SENT) || - TRANSITION (LISTEN, SYN_RECEIVED) || - TRANSITION (SYN_SENT, SYN_RECEIVED) || - TRANSITION (SYN_RECEIVED, ESTABLISHED) || - TRANSITION (SYN_SENT, ESTABLISHED) || - TRANSITION (SYN_RECEIVED, FIN_WAIT_1) || - TRANSITION (ESTABLISHED, FIN_WAIT_1) || - TRANSITION (ESTABLISHED, CLOSE_WAIT) || - TRANSITION (FIN_WAIT_1, FIN_WAIT_2) || - TRANSITION (FIN_WAIT_1, CLOSING) || - TRANSITION (CLOSE_WAIT, LAST_ACK) || - TRANSITION (FIN_WAIT_2, TIME_WAIT) || - TRANSITION (CLOSING, TIME_WAIT) || - TRANSITION (LAST_ACK, CLOSED) || - TRANSITION (TIME_WAIT, CLOSED) || - /* RFC 1122, §4.2.2.8. */ - TRANSITION (SYN_RECEIVED, LISTEN) || - TRANSITION (FIN_WAIT_1, TIME_WAIT)); - -#undef TRANSITION - - priv->state = new_state; -} - -static void -set_state_established (PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - set_state (self, PSEUDO_TCP_ESTABLISHED); - - adjustMTU (self); - if (priv->callbacks.PseudoTcpOpened) - priv->callbacks.PseudoTcpOpened (self, priv->callbacks.user_data); -} - -/* (err == 0) means no error. */ -static void -set_state_closed (PseudoTcpSocket *self, guint32 err) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - set_state (self, PSEUDO_TCP_CLOSED); - - /* Only call the callback if there was an error. */ - if (priv->callbacks.PseudoTcpClosed && err != 0) - priv->callbacks.PseudoTcpClosed (self, err, priv->callbacks.user_data); -} - -gboolean -pseudo_tcp_socket_is_closed (PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - return (priv->state == PSEUDO_TCP_CLOSED); -} - -gboolean -pseudo_tcp_socket_is_closed_remotely (PseudoTcpSocket *self) -{ - PseudoTcpSocketPrivate *priv = self->priv; - - return pseudo_tcp_state_has_received_fin (priv->state); -} diff --git a/agent/pseudotcp.h b/agent/pseudotcp.h deleted file mode 100644 index e087ddc..0000000 --- a/agent/pseudotcp.h +++ /dev/null @@ -1,599 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2010, 2014 Collabora Ltd. - * Contact: Philip Withnall - - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef __LIBNICE_PSEUDOTCP_H__ -#define __LIBNICE_PSEUDOTCP_H__ - -/** - * SECTION:pseudotcp - * @short_description: Pseudo TCP implementation - * @include: pseudotcp.h - * @stability: Stable - * - * The #PseudoTcpSocket is an object implementing a Pseudo Tcp Socket for use - * over UDP. - * The socket will implement a subset of the TCP stack to allow for a reliable - * transport over non-reliable sockets (such as UDP). - * - * See the file tests/test-pseudotcp.c in the source package for an example - * of how to use the object. - * - * Since: 0.0.11 - */ - - - -#include - -#ifndef __GTK_DOC_IGNORE__ -#ifdef G_OS_WIN32 -# include - -#ifndef ECONNABORTED -# define ECONNABORTED WSAECONNABORTED -#endif - -#ifndef ENOTCONN -# define ENOTCONN WSAENOTCONN -#endif - -#ifndef EWOULDBLOCK -# define EWOULDBLOCK WSAEWOULDBLOCK -#endif - -#ifndef ECONNRESET -# define ECONNRESET WSAECONNRESET -#endif - -#ifndef EMSGSIZE -# define EMSGSIZE WSAEMSGSIZE -#endif - -#ifndef ETIMEDOUT -# define ETIMEDOUT WSAETIMEDOUT -#endif -#endif -#endif - -#include "agent.h" - -G_BEGIN_DECLS - -/** - * PseudoTcpSocket: - * - * The #PseudoTcpSocket is the GObject implementing the Pseudo TCP Socket - * - * Since: 0.0.11 - */ -typedef struct _PseudoTcpSocket PseudoTcpSocket; - -typedef struct _PseudoTcpSocketClass PseudoTcpSocketClass; - -GType pseudo_tcp_socket_get_type (void); - -/* TYPE MACROS */ -#define PSEUDO_TCP_SOCKET_TYPE \ - (pseudo_tcp_socket_get_type ()) -#define PSEUDO_TCP_SOCKET(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), PSEUDO_TCP_SOCKET_TYPE, \ - PseudoTcpSocket)) -#define PSEUDO_TCP_SOCKET_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), PSEUDO_TCP_SOCKET_TYPE, \ - PseudoTcpSocketClass)) -#define IS_PSEUDO_TCP_SOCKET(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), PSEUDO_TCP_SOCKET_TYPE)) -#define IS_PSEUDO_TCP_SOCKET_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), PSEUDO_TCP_SOCKET_TYPE)) -#define PSEUDOTCP_SOCKET_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), PSEUDO_TCP_SOCKET_TYPE, \ - PseudoTcpSocketClass)) - -/** - * PseudoTcpDebugLevel: - * @PSEUDO_TCP_DEBUG_NONE: Disable debug messages - * @PSEUDO_TCP_DEBUG_NORMAL: Enable basic debug messages - * @PSEUDO_TCP_DEBUG_VERBOSE: Enable verbose debug messages - * - * Valid values of debug levels to be set. - * - * Since: 0.0.11 - */ -typedef enum { - PSEUDO_TCP_DEBUG_NONE = 0, - PSEUDO_TCP_DEBUG_NORMAL, - PSEUDO_TCP_DEBUG_VERBOSE, -} PseudoTcpDebugLevel; - -/** - * PseudoTcpState: - * @PSEUDO_TCP_LISTEN: The socket's initial state. The socket isn't connected and is - * listening for an incoming connection - * @PSEUDO_TCP_SYN_SENT: The socket has sent a connection request (SYN) packet and is - * waiting for an answer - * @PSEUDO_TCP_SYN_RECEIVED: The socket has received a connection request (SYN) packet. - * @PSEUDO_TCP_ESTABLISHED: The socket is connected - * @PSEUDO_TCP_CLOSED: The socket has been closed - * @PSEUDO_TCP_FIN_WAIT_1: The socket has been closed locally but not remotely - * (Since: 0.1.8) - * @PSEUDO_TCP_FIN_WAIT_2: The socket has been closed locally but not remotely - * (Since: 0.1.8) - * @PSEUDO_TCP_CLOSING: The socket has been closed locally and remotely - * (Since: 0.1.8) - * @PSEUDO_TCP_TIME_WAIT: The socket has been closed locally and remotely - * (Since: 0.1.8) - * @PSEUDO_TCP_CLOSE_WAIT: The socket has been closed remotely but not locally - * (Since: 0.1.8) - * @PSEUDO_TCP_LAST_ACK: The socket has been closed locally and remotely - * (Since: 0.1.8) - * - * An enum representing the state of the #PseudoTcpSocket. These states - * correspond to the TCP states in RFC 793. - * See also: #PseudoTcpSocket:state - * - * Since: 0.0.11 - */ -typedef enum { - PSEUDO_TCP_LISTEN, - PSEUDO_TCP_SYN_SENT, - PSEUDO_TCP_SYN_RECEIVED, - PSEUDO_TCP_ESTABLISHED, - PSEUDO_TCP_CLOSED, - PSEUDO_TCP_FIN_WAIT_1, - PSEUDO_TCP_FIN_WAIT_2, - PSEUDO_TCP_CLOSING, - PSEUDO_TCP_TIME_WAIT, - PSEUDO_TCP_CLOSE_WAIT, - PSEUDO_TCP_LAST_ACK, -} PseudoTcpState; - -/** - * PseudoTcpWriteResult: - * @WR_SUCCESS: The write operation was successful - * @WR_TOO_LARGE: The socket type requires that message be sent atomically - * and the size of the message to be sent made this impossible. - * @WR_FAIL: There was an error sending the message - * - * An enum representing the result value of the write operation requested by - * the #PseudoTcpSocket. - * See also: %PseudoTcpCallbacks:WritePacket - * - * Since: 0.0.11 - */ -typedef enum { - WR_SUCCESS, - WR_TOO_LARGE, - WR_FAIL -} PseudoTcpWriteResult; - -/** - * PseudoTcpShutdown: - * @PSEUDO_TCP_SHUTDOWN_RD: Shut down the local reader only - * @PSEUDO_TCP_SHUTDOWN_WR: Shut down the local writer only - * @PSEUDO_TCP_SHUTDOWN_RDWR: Shut down both reading and writing - * - * Options for which parts of a connection to shut down when calling - * pseudo_tcp_socket_shutdown(). These correspond to the values passed to POSIX - * shutdown(). - * - * Since: 0.1.8 - */ -typedef enum { - PSEUDO_TCP_SHUTDOWN_RD, - PSEUDO_TCP_SHUTDOWN_WR, - PSEUDO_TCP_SHUTDOWN_RDWR, -} PseudoTcpShutdown; - -/** - * PseudoTcpCallbacks: - * @user_data: A user defined pointer to be passed to the callbacks - * @PseudoTcpOpened: The #PseudoTcpSocket is now connected - * @PseudoTcpReadable: The socket is readable - * @PseudoTcpWritable: The socket is writable - * @PseudoTcpClosed: The socket was closed (both sides) - * @WritePacket: This callback is called when the socket needs to send data. - * - * A structure containing callbacks functions that will be called by the - * #PseudoTcpSocket when some events happen. - * See also: #PseudoTcpWriteResult - * - * Since: 0.0.11 - */ -typedef struct { - gpointer user_data; - void (*PseudoTcpOpened) (PseudoTcpSocket *tcp, gpointer data); - void (*PseudoTcpReadable) (PseudoTcpSocket *tcp, gpointer data); - void (*PseudoTcpWritable) (PseudoTcpSocket *tcp, gpointer data); - void (*PseudoTcpClosed) (PseudoTcpSocket *tcp, guint32 error, gpointer data); - PseudoTcpWriteResult (*WritePacket) (PseudoTcpSocket *tcp, - const gchar * buffer, guint32 len, gpointer data); -} PseudoTcpCallbacks; - -/** - * pseudo_tcp_socket_new: - * @conversation: The conversation id for the socket. - * @callbacks: A pointer to the #PseudoTcpCallbacks structure for getting - * notified of the #PseudoTcpSocket events. - * - * Creates a new #PseudoTcpSocket for the specified conversation - * - - - The @callbacks must be non-NULL, in order to get notified of packets the - socket needs to send. - - - If the @callbacks structure was dynamicly allocated, it can be freed - after the call @pseudo_tcp_socket_new - - - * - * Returns: The new #PseudoTcpSocket object, %NULL on error - * - * Since: 0.0.11 - */ -PseudoTcpSocket *pseudo_tcp_socket_new (guint32 conversation, - PseudoTcpCallbacks *callbacks); - - -/** - * pseudo_tcp_socket_connect: - * @self: The #PseudoTcpSocket object. - * - * Connects the #PseudoTcpSocket to the peer with the same conversation id. - * The connection will only be successful after the - * %PseudoTcpCallbacks:PseudoTcpOpened callback is called - * - * Returns: %TRUE on success, %FALSE on failure (not in %TCP_LISTEN state) - * See also: pseudo_tcp_socket_get_error() - * - * Since: 0.0.11 - */ -gboolean pseudo_tcp_socket_connect(PseudoTcpSocket *self); - - -/** - * pseudo_tcp_socket_recv: - * @self: The #PseudoTcpSocket object. - * @buffer: The buffer to fill with received data - * @len: The length of @buffer - * - * Receive data from the socket. - * - - - Only call this on the %PseudoTcpCallbacks:PseudoTcpReadable callback. - - - This function should be called in a loop. If this function does not - return -1 with EWOULDBLOCK as the error, the - %PseudoTcpCallbacks:PseudoTcpReadable callback will not be called again. - - - * - * Returns: The number of bytes received or -1 in case of error - * See also: pseudo_tcp_socket_get_error() - * - * Since: 0.0.11 - */ -gint pseudo_tcp_socket_recv(PseudoTcpSocket *self, char * buffer, size_t len); - - -/** - * pseudo_tcp_socket_send: - * @self: The #PseudoTcpSocket object. - * @buffer: The buffer with data to send - * @len: The length of @buffer - * - * Send data on the socket. - * - - - If this function return -1 with EWOULDBLOCK as the error, or if the return - value is lower than @len, then the %PseudoTcpCallbacks:PseudoTcpWritable - callback will be called when the socket will become writable. - - - * - * Returns: The number of bytes sent or -1 in case of error - * See also: pseudo_tcp_socket_get_error() - * - * Since: 0.0.11 - */ -gint pseudo_tcp_socket_send(PseudoTcpSocket *self, const char * buffer, - guint32 len); - - -/** - * pseudo_tcp_socket_close: - * @self: The #PseudoTcpSocket object. - * @force: %TRUE to close the socket forcefully, %FALSE to close it gracefully - * - * Close the socket for sending. If @force is set to %FALSE, the socket will - * finish sending pending data before closing. If it is set to %TRUE, the socket - * will discard pending data and close the connection immediately (sending a TCP - * RST segment). - * - * The socket will be closed in both directions – sending and receiving – and - * any pending received data must be read before calling this function, by - * calling pseudo_tcp_socket_recv() until it blocks. If any pending data is in - * the receive buffer when pseudo_tcp_socket_close() is called, a TCP RST - * segment will be sent to the peer to notify it of the data loss. - * - - - The %PseudoTcpCallbacks:PseudoTcpClosed callback will not be called once - the socket gets closed. It is only used for aborted connection. - Instead, the socket gets closed when the pseudo_tcp_socket_get_next_clock() - function returns FALSE. - - - * - * See also: pseudo_tcp_socket_get_next_clock() - * - * Since: 0.0.11 - */ -void pseudo_tcp_socket_close(PseudoTcpSocket *self, gboolean force); - -/** - * pseudo_tcp_socket_shutdown: - * @self: The #PseudoTcpSocket object. - * @how: The directions of the connection to shut down. - * - * Shut down sending, receiving, or both on the socket, depending on the value - * of @how. The behaviour of pseudo_tcp_socket_send() and - * pseudo_tcp_socket_recv() will immediately change after this function returns - * (depending on the value of @how), though the socket may continue to process - * network traffic in the background even if sending or receiving data is - * forbidden. - * - * This is equivalent to the POSIX shutdown() function. Setting @how to - * %PSEUDO_TCP_SHUTDOWN_RDWR is equivalent to calling pseudo_tcp_socket_close(). - * - * Since: 0.1.8 - */ -void pseudo_tcp_socket_shutdown (PseudoTcpSocket *self, PseudoTcpShutdown how); - -/** - * pseudo_tcp_socket_get_error: - * @self: The #PseudoTcpSocket object. - * - * Return the last encountered error. - * - - - The return value can be : - - EINVAL (for pseudo_tcp_socket_connect()). - - - EWOULDBLOCK or ENOTCONN (for pseudo_tcp_socket_recv() and - pseudo_tcp_socket_send()). - - - - * - * Returns: The error code - * See also: pseudo_tcp_socket_connect() - * See also: pseudo_tcp_socket_recv() - * See also: pseudo_tcp_socket_send() - * - * Since: 0.0.11 - */ -int pseudo_tcp_socket_get_error(PseudoTcpSocket *self); - - -/** - * pseudo_tcp_socket_get_next_clock: - * @self: The #PseudoTcpSocket object. - * @timeout: A pointer to be filled with the new timeout. - * - * Call this to determine the timeout needed before the next time call - * to pseudo_tcp_socket_notify_clock() should be made. - * - * Returns: %TRUE if @timeout was filled, %FALSE if the socket is closed and - * ready to be destroyed. - * - * See also: pseudo_tcp_socket_notify_clock() - * - * Since: 0.0.11 - */ -gboolean pseudo_tcp_socket_get_next_clock(PseudoTcpSocket *self, - guint64 *timeout); - - -/** - * pseudo_tcp_socket_notify_clock: - * @self: The #PseudoTcpSocket object. - * - * Start the processing of receiving data, pending data or syn/acks. - * Call this based on timeout value returned by - * pseudo_tcp_socket_get_next_clock(). - * It's ok to call this too frequently. - * - * See also: pseudo_tcp_socket_get_next_clock() - * - * Since: 0.0.11 - */ -void pseudo_tcp_socket_notify_clock(PseudoTcpSocket *self); - - -/** - * pseudo_tcp_socket_notify_mtu: - * @self: The #PseudoTcpSocket object. - * @mtu: The new MTU of the socket - * - * Set the MTU of the socket - * - * Since: 0.0.11 - */ -void pseudo_tcp_socket_notify_mtu(PseudoTcpSocket *self, guint16 mtu); - - -/** - * pseudo_tcp_socket_notify_packet: - * @self: The #PseudoTcpSocket object. - * @buffer: The buffer containing the received data - * @len: The length of @buffer - * - * Notify the #PseudoTcpSocket when a new packet arrives - * - * Returns: %TRUE if the packet was processed successfully, %FALSE otherwise - * - * Since: 0.0.11 - */ -gboolean pseudo_tcp_socket_notify_packet(PseudoTcpSocket *self, - const gchar * buffer, guint32 len); - - -/** - * pseudo_tcp_socket_notify_message: - * @self: The #PseudoTcpSocket object. - * @message: A #NiceInputMessage containing the received data. - * - * Notify the #PseudoTcpSocket that a new message has arrived, and enqueue the - * data in its buffers to the #PseudoTcpSocket’s receive buffer. - * - * Returns: %TRUE if the packet was processed successfully, %FALSE otherwise - * - * Since: 0.1.5 - */ -gboolean pseudo_tcp_socket_notify_message (PseudoTcpSocket *self, - NiceInputMessage *message); - - -/** - * pseudo_tcp_set_debug_level: - * @level: The level of debug to set - * - * Sets the debug level to enable/disable normal/verbose debug messages. - * - * Since: 0.0.11 - */ -void pseudo_tcp_set_debug_level (PseudoTcpDebugLevel level); - - -/** - * pseudo_tcp_socket_get_available_bytes: - * @self: The #PseudoTcpSocket object. - * - * Gets the number of bytes of data in the buffer that can be read without - * receiving more packets from the network. - * - * Returns: The number of bytes or -1 if the connection is not established - * - * Since: 0.1.5 - */ - -gint pseudo_tcp_socket_get_available_bytes (PseudoTcpSocket *self); - -/** - * pseudo_tcp_socket_can_send: - * @self: The #PseudoTcpSocket object. - * - * Returns if there is space in the send buffer to send any data. - * - * Returns: %TRUE if data can be sent, %FALSE otherwise - * - * Since: 0.1.5 - */ - -gboolean pseudo_tcp_socket_can_send (PseudoTcpSocket *self); - -/** - * pseudo_tcp_socket_get_available_send_space: - * @self: The #PseudoTcpSocket object. - * - * Gets the number of bytes of space available in the transmission buffer. - * - * Returns: The number of bytes, or 0 if the connection is not established. - * - * Since: 0.1.5 - */ -gsize pseudo_tcp_socket_get_available_send_space (PseudoTcpSocket *self); - -/** - * pseudo_tcp_socket_set_time: - * @self: The #PseudoTcpSocket object. - * @current_time: Current monotonic time, in milliseconds; or zero to use the - * system monotonic clock. - * - * Sets the current monotonic time to be used by the TCP socket when calculating - * timeouts and expiry times. If this function is not called, or is called with - * @current_time as zero, g_get_monotonic_time() will be used. Otherwise, the - * specified @current_time will be used until it is updated by calling this - * function again. - * - * This function is intended for testing only, and should not be used in - * production code. - * - * Since: 0.1.8 - */ -void pseudo_tcp_socket_set_time (PseudoTcpSocket *self, guint32 current_time); - -/** - * pseudo_tcp_socket_is_closed: - * @self: The #PseudoTcpSocket object. - * - * Gets whether the socket is closed, with the shutdown handshake completed, - * and both peers no longer able to read or write data to the connection. - * - * Returns: %TRUE if the socket is closed in both directions, %FALSE otherwise - * Since: 0.1.8 - */ -gboolean pseudo_tcp_socket_is_closed (PseudoTcpSocket *self); - -/** - * pseudo_tcp_socket_is_closed_remotely: - * @self: The #PseudoTcpSocket object. - * - * Gets whether the socket has been closed on the remote peer’s side of the - * connection (i.e. whether pseudo_tcp_socket_close() has been called there). - * This is guaranteed to return %TRUE if pseudo_tcp_socket_is_closed() returns - * %TRUE. It will not return %TRUE after pseudo_tcp_socket_close() is called - * until a FIN segment is received from the remote peer. - * - * Returns: %TRUE if the remote peer has closed its side of the connection, - * %FALSE otherwise - * Since: 0.1.8 - */ -gboolean pseudo_tcp_socket_is_closed_remotely (PseudoTcpSocket *self); - -G_END_DECLS - -#endif /* __LIBNICE_PSEUDOTCP_H__ */ - diff --git a/agent/stream.c b/agent/stream.c deleted file mode 100644 index b8f42dc..0000000 --- a/agent/stream.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "stream.h" - -/* Simple tracking for the number of alive streams. These must be accessed - * atomically. */ -static volatile unsigned int n_streams_created = 0; -static volatile unsigned int n_streams_destroyed = 0; - -G_DEFINE_TYPE (NiceStream, nice_stream, G_TYPE_OBJECT); - -static void -nice_stream_finalize (GObject *obj); - -/* - * @file stream.c - * @brief ICE stream functionality - */ -NiceStream * -nice_stream_new (guint stream_id, guint n_components, NiceAgent *agent) -{ - NiceStream *stream = NULL; - guint n; - - stream = g_object_new (NICE_TYPE_STREAM, NULL); - - stream->id = stream_id; - - /* Create the components. */ - for (n = 0; n < n_components; n++) { - NiceComponent *component = NULL; - - component = nice_component_new (n + 1, agent, stream); - stream->components = g_slist_append (stream->components, component); - } - - stream->n_components = n_components; - - stream->peer_gathering_done = !agent->use_ice_trickle; - - return stream; -} - -void -nice_stream_close (NiceAgent *agent, NiceStream *stream) -{ - GSList *i; - - for (i = stream->components; i; i = i->next) { - NiceComponent *component = i->data; - nice_component_close (agent, component); - } -} - -NiceComponent * -nice_stream_find_component_by_id (NiceStream *stream, guint id) -{ - GSList *i; - - for (i = stream->components; i; i = i->next) { - NiceComponent *component = i->data; - if (component && component->id == id) - return component; - } - - return NULL; -} - -/* - * Initialized the local crendentials for the stream. - */ -void -nice_stream_initialize_credentials (NiceStream *stream, NiceRNG *rng) -{ - /* note: generate ufrag/pwd for the stream (see ICE 15.4. - * '"ice-ufrag" and "ice-pwd" Attributes', ID-19) */ - nice_rng_generate_bytes_print (rng, NICE_STREAM_DEF_UFRAG - 1, stream->local_ufrag); - nice_rng_generate_bytes_print (rng, NICE_STREAM_DEF_PWD - 1, stream->local_password); -} - -/* - * Resets the stream state to that of a ICE restarted - * session. - */ -void -nice_stream_restart (NiceStream *stream, NiceAgent *agent) -{ - GSList *i; - - /* step: clean up all connectivity checks */ - conn_check_prune_stream (agent, stream); - - stream->initial_binding_request_received = FALSE; - - nice_stream_initialize_credentials (stream, agent->rng); - - for (i = stream->components; i; i = i->next) { - NiceComponent *component = i->data; - - nice_component_restart (component); - } -} - -static void -nice_stream_class_init (NiceStreamClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = nice_stream_finalize; -} - -static void -nice_stream_init (NiceStream *stream) -{ - g_atomic_int_inc (&n_streams_created); - nice_debug ("Created NiceStream (%u created, %u destroyed)", - n_streams_created, n_streams_destroyed); - - stream->n_components = 0; - stream->initial_binding_request_received = FALSE; -} - -/* Must be called with the agent lock released as it could dispose of - * NiceIOStreams. */ -static void -nice_stream_finalize (GObject *obj) -{ - NiceStream *stream; - - stream = NICE_STREAM (obj); - - g_free (stream->name); - g_slist_free_full (stream->components, (GDestroyNotify) g_object_unref); - - g_atomic_int_inc (&n_streams_destroyed); - nice_debug ("Destroyed NiceStream (%u created, %u destroyed)", - n_streams_created, n_streams_destroyed); - - G_OBJECT_CLASS (nice_stream_parent_class)->finalize (obj); -} diff --git a/agent/stream.h b/agent/stream.h deleted file mode 100644 index de1d456..0000000 --- a/agent/stream.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2010 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2010 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _NICE_STREAM_H -#define _NICE_STREAM_H - -#include - -typedef struct _NiceStream NiceStream; - -#include "component.h" -#include "random.h" - -G_BEGIN_DECLS - -/* Maximum and default sizes for ICE attributes, - * last updated from ICE ID-19 - * (the below sizes include the terminating NULL): */ - -#define NICE_STREAM_MAX_UFRAG 256 + 1 /* ufrag + NULL */ -#define NICE_STREAM_MAX_UNAME 256 * 2 + 1 + 1 /* 2*ufrag + colon + NULL */ -#define NICE_STREAM_MAX_PWD 256 + 1 /* pwd + NULL */ -#define NICE_STREAM_DEF_UFRAG 4 + 1 /* ufrag + NULL */ -#define NICE_STREAM_DEF_PWD 22 + 1 /* pwd + NULL */ - -#define NICE_TYPE_STREAM nice_stream_get_type() -#define NICE_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), NICE_TYPE_STREAM, NiceStream)) -#define NICE_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), NICE_TYPE_STREAM, NiceStreamClass)) -#define NICE_IS_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NICE_TYPE_STREAM)) -#define NICE_IS_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), NICE_TYPE_STREAM)) -#define NICE_STREAM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), NICE_TYPE_STREAM, NiceStreamClass)) - -struct _NiceStream { - /*< private >*/ - GObject parent; - - gchar *name; - guint id; - guint n_components; - gboolean initial_binding_request_received; - GSList *components; /* list of 'NiceComponent' objects */ - GSList *conncheck_list; /* list of CandidateCheckPair items */ - gchar local_ufrag[NICE_STREAM_MAX_UFRAG]; - gchar local_password[NICE_STREAM_MAX_PWD]; - gchar remote_ufrag[NICE_STREAM_MAX_UFRAG]; - gchar remote_password[NICE_STREAM_MAX_PWD]; - gboolean gathering; - gboolean gathering_started; - gboolean peer_gathering_done; - gint tos; - guint tick_counter; -}; - -typedef struct { - GObjectClass parent_class; -} NiceStreamClass; - -GType nice_stream_get_type (void); - -NiceStream * -nice_stream_new (guint stream_id, guint n_components, NiceAgent *agent); - -void -nice_stream_close (NiceAgent *agent, NiceStream *stream); - -NiceComponent * -nice_stream_find_component_by_id (NiceStream *stream, guint id); - -void -nice_stream_initialize_credentials (NiceStream *stream, NiceRNG *rng); - -void -nice_stream_restart (NiceStream *stream, NiceAgent *agent); - -G_END_DECLS - -#endif /* _NICE_STREAM_H */ - diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index b6efba6..0000000 --- a/autogen.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# Run this to generate all the initial makefiles, etc. -test -n "$srcdir" || srcdir=$(dirname "$0") -test -n "$srcdir" || srcdir=. - -olddir=$(pwd) - -cd $srcdir - -(test -f configure.ac) || { - echo "*** ERROR: Directory '$srcdir' does not look like the top-level project directory ***" - exit 1 -} - -# shellcheck disable=SC2016 -PKG_NAME=$(autoconf --trace 'AC_INIT:$1' configure.ac) - -if [ "$#" = 0 -a "x$NOCONFIGURE" = "x" ]; then - echo "*** WARNING: I am going to run 'configure' with no arguments." >&2 - echo "*** If you wish to pass any to it, please specify them on the" >&2 - echo "*** '$0' command line." >&2 - echo "" >&2 -fi - -aclocal --install || exit 1 -gtkdocize --copy || exit 1 -autoreconf --verbose --force --install || exit 1 - -cd "$olddir" -if [ "$NOCONFIGURE" = "" ]; then - $srcdir/configure "$@" || exit 1 - - if [ "$1" = "--help" ]; then exit 0 else - echo "Now type 'make' to compile $PKG_NAME" || exit 1 - fi -else - echo "Skipping configure process." -fi diff --git a/common.mk b/common.mk deleted file mode 100644 index b16380d..0000000 --- a/common.mk +++ /dev/null @@ -1,11 +0,0 @@ -CLEANFILES = *.gcno *.gcda - -pkgincludedir = $(includedir)/nice - - -check-valgrind: - $(MAKE) TESTS_ENVIRONMENT="USE_VALGRIND=1 " check - -LOG_DRIVER=$(top_srcdir)/scripts/valgrind-test-driver - -.PHONY: check-valgrind diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 04c1614..0000000 --- a/configure.ac +++ /dev/null @@ -1,417 +0,0 @@ - -AC_PREREQ(2.62) - -dnl Always compile with -Wall; if --enable-compile-warnings=error is passed, -dnl also use -Werror. git and pre-releases default to -Werror - -dnl use a three digit version number for releases, and four for cvs/prerelease -AC_INIT([libnice],[0.1.17]) -LIBNICE_RELEASE="yes" - -AC_CANONICAL_TARGET - -AC_CONFIG_SRCDIR([agent/agent.c]) -AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([1.12 -Wall -Wno-portability subdir-objects]) - -AC_CONFIG_FILES([ - Makefile - agent/Makefile - stun/Makefile - stun/tests/Makefile - stun/tools/Makefile - socket/Makefile - nice/Makefile - nice/nice.pc - random/Makefile - gst/Makefile - docs/Makefile - docs/reference/Makefile - docs/reference/libnice/Makefile - tests/Makefile - examples/Makefile - ]) - -# Set the libtool C/A/R version info -# If the source code was changed, but there were no interface changes: -# Increment REVISION. -# If there was a compatible interface change: -# Increment CURRENT and AGE. Set REVISION to 0 -# If there was an incompatible interface change: -# Increment CURRENT. Set AGE and REVISION to 0 -LIBNICE_CURRENT=20 -LIBNICE_REVISION=0 -LIBNICE_AGE=10 -LIBNICE_LIBVERSION=${LIBNICE_CURRENT}:${LIBNICE_REVISION}:${LIBNICE_AGE} -LIBNICE_LT_LDFLAGS="-version-info ${LIBNICE_LIBVERSION} -no-undefined" -AC_SUBST(LIBNICE_LT_LDFLAGS) - -dnl use pretty build output -AM_SILENT_RULES([yes]) - - -# Checks for programs. - -AC_USE_SYSTEM_EXTENSIONS -AC_PROG_CC -AM_PROG_AR -LT_PREREQ([2.2.6]) -LT_INIT([dlopen win32-dll disable-static]) -AC_PATH_PROG([GLIB_MKENUMS],[glib-mkenums]) - -# Check Operating System -AC_MSG_CHECKING([operating system]) -case "$host" in - *-*-*mingw*|*-*-*cygwin*) - platform=win32 - AC_MSG_RESULT($platform) - ;; - *) - platform=linux/other - AC_MSG_RESULT($platform) - ;; -esac - -AM_CONDITIONAL([WINDOWS], [test "$platform" = "win32"]) - -# Checks for compiler features - -AC_C_RESTRICT -AC_C_VARARRAYS -AC_HEADER_ASSERT -AC_HEADER_STDBOOL -AH_VERBATIM([_FORTIFY_SOURCE], -[/* Define to `2' to get GNU/libc warnings. */ -/* Only define if -O1 or more is enabled */ -#if defined __OPTIMIZE__ && __OPTIMIZE__ > 0 -# define _FORTIFY_SOURCE 2 -#endif]) -AC_DEFINE([NICEAPI_EXPORT], [ ], [Public library function implementation]) -AC_CHECK_HEADERS([arpa/inet.h net/in.h netdb.h]) -AC_CHECK_HEADERS([ifaddrs.h], - [AC_CHECK_FUNCS([getifaddrs], - [AC_DEFINE(HAVE_GETIFADDRS, [1], - [Whether getifaddrs() is available on the system])])]) -AC_CHECK_TYPES([size_t, ssize_t]) - -# Also put matching version in LIBNICE_CFLAGS -GLIB_REQ=2.54 - -LIBNICE_CFLAGS="-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_54 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_54" - -dnl Support different levels of compiler error reporting. -dnl This configure flag is designed to mimic one from gnome-common, -dnl Defaults to "error" except for releases where it defaults to "yes" -AC_ARG_ENABLE(compile-warnings, - AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@], - [Enable different levels of compiler warnings]),, - [AS_IF([test "$LIBNICE_RELEASE" = "yes"], - [enable_compile_warnings="yes"], - [enable_compile_warnings="error"])]) - -AC_DEFUN([NICE_ADD_FLAG], - AS_COMPILER_FLAG([-Werror $1], LIBNICE_CFLAGS="$LIBNICE_CFLAGS $1", []) -) - -NICE_ADD_FLAG([-fno-strict-aliasing]) - -AS_IF([test "$enable_compile_warnings" != "no"],[ - NICE_ADD_FLAG([-Wall]) -]) -AS_IF([test "x$enable_compile_warnings" != "xno" -a \ - "x$enable_compile_warnings" != "xminimum"],[ - NICE_ADD_FLAG([-Wextra]) - NICE_ADD_FLAG([-Wundef]) - NICE_ADD_FLAG([-Wnested-externs]) - NICE_ADD_FLAG([-Wwrite-strings]) - NICE_ADD_FLAG([-Wpointer-arith]) - NICE_ADD_FLAG([-Wmissing-declarations]) - NICE_ADD_FLAG([-Wmissing-prototypes]) - NICE_ADD_FLAG([-Wstrict-prototypes]) - NICE_ADD_FLAG([-Wredundant-decls]) - NICE_ADD_FLAG([-Wno-unused-parameter]) - NICE_ADD_FLAG([-Wno-missing-field-initializers]) - NICE_ADD_FLAG([-Wdeclaration-after-statement]) - NICE_ADD_FLAG([-Wformat=2]) - NICE_ADD_FLAG([-Wold-style-definition]) - NICE_ADD_FLAG([-Wcast-align]) - NICE_ADD_FLAG([-Wformat-nonliteral]) - NICE_ADD_FLAG([-Wformat-security]) - NICE_ADD_FLAG([-Wno-cast-function-type]) -]) -AS_IF([test "$enable_compile_warnings" = "yes" -o \ - "$enable_compile_warnings" = "maximum" -o \ - "$enable_compile_warnings" = "error"],[ - NICE_ADD_FLAG([-Wsign-compare]) - NICE_ADD_FLAG([-Wstrict-aliasing]) - NICE_ADD_FLAG([-Wshadow]) - NICE_ADD_FLAG([-Winline]) - NICE_ADD_FLAG([-Wpacked]) - NICE_ADD_FLAG([-Wmissing-format-attribute]) - NICE_ADD_FLAG([-Winit-self]) - NICE_ADD_FLAG([-Wredundant-decls]) - NICE_ADD_FLAG([-Wmissing-include-dirs]) - NICE_ADD_FLAG([-Wunused-but-set-variable]) - NICE_ADD_FLAG([-Warray-bounds]) -]) -AS_IF([test "$enable_compile_warnings" = "maximum" -o \ - "$enable_compile_warnings" = "error"],[ - NICE_ADD_FLAG([-Wswitch-default]) - NICE_ADD_FLAG([-Waggregate-return]) -]) -AS_IF([test "x$enable_compile_warnings" = "xerror"],[ - NICE_ADD_FLAG([-Werror]) - NICE_ADD_FLAG([-Wno-suggest-attribute=format]) -]) - -# -# Fixes for Solaris -# -AC_SEARCH_LIBS([inet_pton],[nsl]) -AC_SEARCH_LIBS([socket],[socket inet]) -case $host in - *-*-solaris* ) - AC_DEFINE(_XOPEN_SOURCE, 600, Needed to get declarations for msg_control and msg_controllen on Solaris) - AC_DEFINE(__EXTENSIONS__, 1, Needed to get declarations for msg_control and msg_controllen on Solaris) - ;; -esac - -AC_SUBST(LIBNICE_CFLAGS) -AC_MSG_NOTICE([set LIBNICE_CFLAGS to $LIBNICE_CFLAGS]) - -# Checks for libraries. -AC_CHECK_LIB(rt, clock_gettime, [LIBRT="-lrt"], [LIBRT=""]) -AC_CHECK_FUNCS([poll]) -AC_SUBST(LIBRT) - -# Dependencies - -NICE_PACKAGES_PUBLIC="glib-2.0 >= $GLIB_REQ gio-2.0 >= $GLIB_REQ gobject-2.0 >= $GLIB_REQ" -NICE_PACKAGES_PRIVATE="gthread-2.0" - -PKG_CHECK_MODULES(GLIB, [$NICE_PACKAGES_PUBLIC $NICE_PACKAGES_PRIVATE]) - -AC_ARG_WITH(crypto-library, - AS_HELP_STRING([--with-crypto-library=\{gnutls,openssl,auto\}],[select Crypto library (gnutls or openssl)]), - [with_crypto_library=${withval}], - [with_crypto_library=auto]) - - -AS_IF([test "$with_crypto_library" != "openssl"], - [ - GNUTLS_PACKAGES_PRIVATE="gnutls >= 2.12.0" - PKG_CHECK_MODULES(GNUTLS, [$GNUTLS_PACKAGES_PRIVATE], - [ - AC_DEFINE([HAVE_GNUTLS], [1], [Use GnuTLS]) - GNUTLS_FOUND=yes - NICE_PACKAGES_PRIVATE="$NICE_PACKAGES_PRIVATE $GNUTLS_PACKAGES_PRIVATE" - ], - [ - AS_IF([test "$with_crypto_library" == "gnutls"], - [ - AC_MSG_ERROR([Neither GnuTLS is not available]) - ] - ) - ] - ) - ] -) - -AS_IF([test "x${GNUTLS_FOUND}" != "xyes"], - [ - AX_CHECK_OPENSSL( - [ - AC_DEFINE([HAVE_OPENSSL], [1], [Use OpenSSL]) - NICE_PACKAGES_PRIVATE="$NICE_PACKAGES_PRIVATE libcrypto" - AC_MSG_NOTICE([OpenSSL selected]) - ], - [ - AC_MSG_ERROR([Neither GnuTLS or OpenSSL is available]) - ] - ) - ], - [ - AC_MSG_NOTICE([GnuTLS selected]) - ] -) - -AC_SUBST([NICE_PACKAGES_PUBLIC]) -AC_SUBST([NICE_PACKAGES_PRIVATE]) - - -AC_ARG_WITH(gstreamer, - AS_HELP_STRING([--with-gstreamer],[build GStreamer plugin]), - [with_gstreamer=${withval}], - [with_gstreamer=auto]) - -AC_ARG_WITH(gstreamer-0.10, - AS_HELP_STRING([--with-gstreamer-0.10],[build GStreamer 0.10 plugin]), - [with_gstreamer010=${withval}], - [with_gstreamer010=auto]) - -AS_IF([test "$with_gstreamer" != no], [ - - PKG_CHECK_MODULES(GST, [ - gstreamer-1.0 >= 0.11.91 - gstreamer-base-1.0 >= 0.11.91 - ], - [ - with_gstreamer=yes - GST_MAJORMINOR=1.0 - gstplugindir="\$(libdir)/gstreamer-$GST_MAJORMINOR" - ], - [ - AS_IF([test "$with_gstreamer" = yes], [ - AC_MSG_ERROR([GStreamer 1.0 support was requested but GStreamer 1.0 libraries are not available]) - ]) - - with_gstreamer=no - ]) - - PKG_CHECK_MODULES(GST_CHECK, [ - gstreamer-check-1.0 >= 0.11.91 - ], - [ - have_gst_check=yes - ], - [ - have_gst_check=no - ]) -]) - -AS_IF([test "$with_gstreamer010" != no], [ - - PKG_CHECK_MODULES(GST010, [ - gstreamer-0.10 >= 0.10.10 - gstreamer-base-0.10 >= 0.10.10 - ], - [ - with_gstreamer010=yes - GST_MAJORMINOR=0.10 - gstplugin010dir="\$(libdir)/gstreamer-$GST_MAJORMINOR" - ], - [ - AS_IF([test "$with_gstreamer010" = yes], [ - AC_MSG_ERROR([GStreamer 0.10 support was requested but GStreamer 0.10 libraries are not available]) - ]) - - with_gstreamer010=no - ]) -]) - -AC_SUBST(gstplugindir) -AC_SUBST(gstplugin010dir) - -AM_CONDITIONAL(WITH_GSTREAMER, test "$with_gstreamer" = yes) -AM_CONDITIONAL(HAVE_GST_CHECK, test "$have_gst_check" = yes) -AM_CONDITIONAL(WITH_GSTREAMER010, test "$with_gstreamer010" = yes) - -GUPNP_IGD_REQUIRED=0.2.4 - -AC_ARG_ENABLE([gupnp], - AS_HELP_STRING([--disable-gupnp],[Disable GUPnP IGD support]), - [case "${enableval}" in - yes) WANT_GUPNP=yes ;; - no) WANT_GUPNP=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-gupnp) ;; - esac], - WANT_GUPNP=test) - -GUPNP_PACKAGES_PUBLIC="" -GUPNP_PACKAGES_PRIVATE="gupnp-igd-1.0 >= $GUPNP_IGD_REQUIRED" -GUPNP_PACKAGES="$GUPNP_PACKAGES_PUBLIC $GUPNP_PACKAGES_PRIVATE" - -HAVE_GUPNP=no -if test "x$WANT_GUPNP" != "xno"; then - PKG_CHECK_MODULES(GUPNP, [$GUPNP_PACKAGES], - [ HAVE_GUPNP=yes ], - [ HAVE_GUPNP=no ]) -fi -if test "x$WANT_GUPNP" = "xyes" && test "x$HAVE_GUPNP" = "xno"; then - AC_MSG_ERROR([Requested GUPnP IGD, but it is not available]) -fi - -if test "x$HAVE_GUPNP" = "xyes"; then - AC_DEFINE(HAVE_GUPNP,,[Have the GUPnP IGD library]) - UPNP_ENABLED="true" -else - GUPNP_PACKAGES_PUBLIC="" - GUPNP_PACKAGES_PRIVATE="" - GUPNP_PACKAGES="" -fi - -AC_SUBST([GUPNP_PACKAGES_PUBLIC]) -AC_SUBST([GUPNP_PACKAGES_PRIVATE]) -AC_SUBST([GUPNP_PACKAGES]) - -AC_SUBST(HAVE_GUPNP) -AC_SUBST([UPNP_ENABLED]) - -dnl Test coverage -AC_ARG_ENABLE([coverage], - [AS_HELP_STRING([--enable-coverage], - [build for test coverage (default disabled)])],, - [enable_coverage="no"]) -AS_IF([test "${enable_coverage}" != "no"], [ - CFLAGS="${CFLAGS} -g -O0 -fprofile-arcs -ftest-coverage" - LDFLAGS="-lgcov" - CCACHE_DISABLE=1 -]) -AC_SUBST(CCACHE_DISABLE) - -dnl build static plugins or not -AC_MSG_CHECKING([whether to build static plugins or not]) -AC_ARG_ENABLE( - static-plugins, - AC_HELP_STRING( - [--enable-static-plugins], - [build static plugins @<:@default=no@:>@]), - [AS_CASE( - [$enableval], [no], [], [yes], [], - [AC_MSG_ERROR([bad value "$enableval" for --enable-static-plugins])])], - [enable_static_plugins=no]) -AC_MSG_RESULT([$enable_static_plugins]) -if test "x$enable_static_plugins" = xyes; then - AC_DEFINE(GST_PLUGIN_BUILD_STATIC, 1, - [Define if static plugins should be built]) -fi -AM_CONDITIONAL(GST_PLUGIN_BUILD_STATIC, test "x$enable_static_plugins" = "xyes") - -case $host_os in - solaris*) - LDFLAGS="$LDFLAGS -lsocket -lnsl" - ;; - *) - ;; -esac - -# check for gtk-doc -m4_ifdef([GTK_DOC_CHECK], [ -GTK_DOC_CHECK([1.10],[--flavour no-tmpl]) -],[ -AM_CONDITIONAL([ENABLE_GTK_DOC], false) -]) - -# GObject introspection -GOBJECT_INTROSPECTION_CHECK([1.30.0]) - -dnl Ignore specific network interface name prefixes from the connection check -AC_MSG_CHECKING([whether to ignore specific network interface name prefixes]) -AC_ARG_WITH([ignored-network-interface-prefix], - [AS_HELP_STRING([--with-ignored-network-interface-prefix=string@<:@,string...@:>@], - [Ignore network interfaces whose name starts with a string from this list in the ICE connection - check algorithm. For example, interfaces "virbr" in the case of the virtual bridge - handled by libvirtd, do not help in finding connectivity.])], - [interface_prefix="$withval"], - [interface_prefix="docker,veth,virbr,vnet"]) -AS_IF([test -n "$interface_prefix" && test "x$interface_prefix" != "xno"], - [[interface_prefix_list=`echo $interface_prefix | sed 's/,/","/g'`] - AC_DEFINE_UNQUOTED([IGNORED_IFACE_PREFIX],["$interface_prefix_list"], - [Ignore this network interface prefix from the connection check]) - AC_MSG_RESULT([yes, $interface_prefix])], - [AC_MSG_RESULT([no])]) - -AC_CONFIG_MACRO_DIR(m4) - -AC_OUTPUT - diff --git a/docs/Makefile.am b/docs/Makefile.am deleted file mode 100644 index fcd5f1b..0000000 --- a/docs/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ - -SUBDIRS = reference - -EXTRA_DIST = design.txt diff --git a/docs/design.txt b/docs/design.txt deleted file mode 100644 index 6a3bf12..0000000 --- a/docs/design.txt +++ /dev/null @@ -1,215 +0,0 @@ -Nice: Design documentation -========================== - -Socket ownership ----------------- - -For UDP candidates, one socket is created for each component and bound -to INADDR_ANY. The same local socket is used for the host candidate, -STUN candidate as well as the TURN candidate. The socket handles are -stored to the Component structure. - -The library will use the source address of incoming packets in order -to identify from which remote candidates, if any (peer-derived -candidates), packets were sent. - -XXX: Describe the subtle issues with ICMP error handling when one -socket is used to send to multiple destinations. - -Real-time considerations ------------------------- - -One potential use for libnice code is providing network connectivity -for media transport in voice and video telephony applications. This -means that the libnice code is potentially run in real-time context -(for instance under POSIX SCHED_FIFO/SHCED_RR scheduling policy) and -ideally has deterministic execution time. - -To be real-time friendly, operations with non-deterministic execution -time (dynamic memory allocation, file and other resource access) should -be done at startup/initialization phase. During an active session -(connectivity has been established and non-STUN traffic is being sent), -code should be as deterministic as possible. - -Memory management ------------------ - -To work on platforms where available memory may be constrained, libnice -should gracefully handle out of memory situations. If memory allocation -fails, the library should return an error via the originating public -library API function. - -Use of glib creates some challenges to meet the above: - -- A lot of glib's internal code assumes memory allocations will - always work. Use of these glib facilities should be limited. - While the glib default policy (see g_malloc() documentation) of terminating - the process is ok for applications, this is not acceptable for library - components. -- Glib has weak support for preallocating structures needed at - runtime (for instance use of timers creates a lot of memory - allocation activity). - -To work around the above limitations, the following guidelines need -to be followed: - -- Always check return values of glib functions. -- Use safe variants: g_malloc_try(), etc -- Current issues (last update 2007-05-04) - - g_slist_append() will crash if alloc fails - -Timers ------- - -Management of timers is handled by the 'agent' module. Other modules -may use timer APIs to get timestamps, but they do not run timers. - -Glib's timer interface has some problems that have affected the design: - - - an expired timer will destroy the source (a potentially costly - operation) - - it is not possible to cancel, or adjust the timer expiration - timer without destroying the associated source and creating - a new one, which again causes malloc/frees and is potentially - a costly operation - - on Linux, glib uses gettimeofday() which is subject to clock - skew, and no monotonic timer API is available - -Due to the above, 'agent' code runs fixed interval periodic timers -(started with g_timeout_add()) during candidate gathering, connectivity -check, and session keepalive phases. Timer frequency is set separately -for each phase of processing. A more elegant design would use dynamic -timeouts, but this would be too expensive with glib timer -infrastructure. - -Control flow for NICE agent API (NiceAgentClass) ------------------------------------------------- - -The main library interface for applications using libnice is the -NiceAgent GObject interface defined in 'nice/agent.h'. - -The rough order of control follow is as follows: - -- creation of NiceAgent object instance -- setting agent properties such as STUN and TURN server addresses -- connecting the GObject signals with g_signal_connect() to application - callback functions -- adding local interface addresses to use with - nice_agent_add_local_address() - -And continues when making an initial offer: - -- creating the streams with nice_agent_add_stream() -- attach the mainloop context to connect the NiceAgent sockets to - the application's event loop (using nice_agent_attach_recv()) -- start candidate gathering by calling nice_agent_gather_candidates() -- the application should wait for the "candidate-gathering-done" signal - before going forward (so that ICE can gather the needed set of local - connectiviy candidates) -- get the information needed for sending offer using - nice_agent_get_local_candidates() and - nice_agent_get_local_credentials() -- client should now send the session offer -- once it receives an answer, it can pass the information to NiceAgent - using nice_agent_set_remote_candidates() and - nice_agent_set_remote_credentials() - -Alternatively, when answering to an initial offer: - -- the first five steps are the same as above (making initial offer) -- pass the remote session information to NiceAgent using - nice_agent_set_remote_candidates() and - nice_agent_set_remote_credentials() -- client can send the answer to session offer - -Special considerations for a SIP client: - -- Upon sending the initial offer/answer, client should pick one - local candidate as the default one, and encode it to the SDP - "m" and "c" lines, in addition to the ICE "a=candidate" lines. -- Client should connect to "new-selected-pair" signals. If this - signal is received, a new candidate pair has been set as - a selected pair (highest priority nominated pair). See - ICE specification for a definition of "nominated pairs". -- Once all components of a stream have reached the - "NICE_COMPONENT_STATE_READY" state (as reported by - "component-state-changed" signals), the client should check - whether its original default candidate matches the latest - selected pair. If not, it needs to send an updated offer - it is in controlling mode. Before sending the offer, client - should check the "controlling-mode" property to check that - it still is in controlling mode (might change during ICE - processing due to ICE role conflicts). -- The "remote-attributes" SDP attribute can be created from - the information provided by "component-state-changed" (which - components are ready), "new-selected-pair" (which candidates - are selected) and "new-remote-candidate" (peer-reflexive - candidates discovered during processing) signals. -- Supporting forked calls is not yet supported by the API (multiple - sets of remote candidates for one local set of candidates). - -Restarting ICE: - -- ICE processing can be restarted by calling nice_agent_restart() -- Restart will clean the set of remote candidates, so client must - afterwards call nice_agent_set_remote_candidates() after receiving - a new offer/answer for the restarted ICE session. -- Restart will reinitialize the local credentials (see - nice_agent_get_local_credentials()). -- Note that to modify the set of local candidates, a new stream - has to be created. For the remote party, this looks like a ICE - restart as well. - -Handling fallback to non-ICE operation: - -- If we are the offering party, and the remote party indicates - it doesn't support ICE, we can use nice_agent_set_selected_pair() - to force selection of a candidate pair (for remote party, - the information on SDP 'm=' and 'c=' lines needs to be used - to generate one remote candidate for each component of the - streams). This function will halt all ICE processing (excluding - keepalives), while still allowing to send and receive media (assuming - NATs won't interfere). - -Notes about sending media: - -- Client may send media once all components of a stream have reached - state of NICE_COMPONENT_STATE_CONNECTED or NICE_COMPONENT_STATE_READY, - (as reported by "component-state-changed" signals), and a selected pair - is set for all components (as reported by "new-selected-pair" signals). - -STUN API --------- - -The underlying STUN library takes care of formatting and parsing STUN -messages (lower layer), - -Applications should only need to use the higher layer API which then -uses the lower layer API. - -The following STUN usages are currently implemented by the -transaction layer: -- Binding discovery (RFC5389 with RFC3489 backward compatibility) -- Binding keep-alive -- ICE connectivity checks -- TURN -- STUN retransmission timers - - -STUN message API ----------------- - -STUN message API provide thin wrappers to parse and format STUN -messages. To achieve maximum cross-architectures portability and retain -real-time friendliness, these functions are fully "computational" [1]. -They also make no assumption about endianess or memory alignment -(reading single bytes or using memcpy()). - -Message buffers are provided by the caller (so these can be -preallocated). Because STUN uses a relatively computer-friendly binary -format, STUN messages are stored in wire format within the buffers. -There is no intermediary translation, so the APIs can operate directly -with data received from or sent to the network. - -[1] With one exception: The random number generated might access the -system entropy pool (/dev/urandom) if available. diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am deleted file mode 100644 index ff46f5e..0000000 --- a/docs/reference/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ - -SUBDIRS = libnice diff --git a/docs/reference/libnice/Makefile.am b/docs/reference/libnice/Makefile.am deleted file mode 100644 index f6c2d52..0000000 --- a/docs/reference/libnice/Makefile.am +++ /dev/null @@ -1,117 +0,0 @@ -## Process this file with automake to produce Makefile.in - -# We require automake 1.6 at least. -AUTOMAKE_OPTIONS = 1.6 - -# The name of the module, e.g. 'glib'. -DOC_MODULE=libnice - -# The top-level SGML file. You can change this if you want to. -DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml - -# The directory containing the source code. Relative to $(srcdir). -# gtk-doc will search all .c & .h files beneath here for inline comments -# documenting the functions and macros. -# e.g. DOC_SOURCE_DIR=../../../gtk -DOC_SOURCE_DIR=$(top_srcdir)/agent $(top_srcdir)/stun - -# Extra options to pass to gtkdoc-scangobj. Not normally needed. -SCANGOBJ_OPTIONS= - -# Extra options to supply to gtkdoc-scan. -# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" -SCAN_OPTIONS=--rebuild-types - -# Extra options to supply to gtkdoc-mkdb. -# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml -MKDB_OPTIONS=--xml-mode --output-format=xml --name-space=Nice - -# Extra options to supply to gtkdoc-mktmpl -# e.g. MKTMPL_OPTIONS=--only-section-tmpl -MKTMPL_OPTIONS= - -# Extra options to supply to gtkdoc-fixref. Not normally needed. -# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html -FIXXREF_OPTIONS= - -# Used for dependencies. The docs will be rebuilt if any of these change. -# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h -# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c -HFILE_GLOB=$(top_srcdir)/agent/agent.h $(top_srcdir)/agent/address.h \ - $(top_srcdir)/agent/debug.h $(top_srcdir)/agent/candidate.h \ - $(top_srcdir)/agent/interfaces.h \ - $(top_srcdir)/agent/pseudotcp.h \ - $(top_srcdir)/stun/stunagent.h \ - $(top_srcdir)/stun/stunmessage.h \ - $(top_srcdir)/stun/debug.h \ - $(top_srcdir)/stun/usages/bind.h \ - $(top_srcdir)/stun/usages/ice.h \ - $(top_srcdir)/stun/usages/timer.h \ - $(top_srcdir)/stun/usages/turn.h - -CFILE_GLOB=$(top_srcdir)/agent/agent.c \ - $(top_srcdir)/agent/pseudotcp.c - -# Header files to ignore when scanning. -# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h -IGNORE_HFILES= conncheck.h discovery.h stream.h component.h agent-priv.h \ - iostream.h inputstream.h outputstream.h \ - gstnice.h gstnicesrc.h gstnicesink.h \ - md5.h sha1.h stunhmac.h utils.h rand.h stun5389.h stuncrc32.h \ - stund.h agent-signals-marshal.h win32_common.h - -# Images to copy into HTML directory. -# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png -HTML_IMAGES = states.png - -# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). -# e.g. content_files=running.sgml building.sgml changes-2.0.sgml -content_files= - -# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded -# These files must be listed here *and* in content_files -# e.g. expand_content_files=running.sgml -expand_content_files= - -# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. -# Only needed if you are using gtkdoc-scangobj to dynamically query widget -# signals and properties. -# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) -# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) -AM_CFLAGS = $(LIBNICE_CFLAGS) \ - $(GLIB_CFLAGS) \ - -I $(top_srcdir) \ - -I $(top_srcdir)/random \ - -I $(top_srcdir)/socket \ - -I $(top_srcdir)/stun - -GTKDOC_LIBS= $(top_builddir)/agent/libagent.la $(GLIB_LIBS) $(top_builddir)/stun/libstun.la \ - $(GUPNP_LIBS) - - -# This includes the standard gtk-doc make rules, copied by gtkdocize. -include $(top_srcdir)/gtk-doc.make - -# Other files to distribute -# e.g. EXTRA_DIST += version.xml.in -EXTRA_DIST += states.gv - -EXTRA_DIST += meson.build - -# Files not to distribute -# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types -# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt -#DISTCLEANFILES += - -# If we ever need to regenerate this diagram. -# Since it’s not expected to change much, let’s not depend on GraphViz to -# build the docs. -states.png: states.gv - dot -Tpng -Gsize=9.6,2.9\! -Gdpi=200 $^ > $@ - -if ENABLE_GTK_DOC -TESTS_ENVIRONMENT = \ - DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \ - SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir) -TESTS = $(GTKDOC_CHECK) -endif diff --git a/docs/reference/libnice/libnice-docs.xml b/docs/reference/libnice/libnice-docs.xml deleted file mode 100644 index e3e0966..0000000 --- a/docs/reference/libnice/libnice-docs.xml +++ /dev/null @@ -1,122 +0,0 @@ - - - - - libnice Reference Manual - - The latest version of this documentation can be found on-line at - http://nice.freedesktop.org/libnice/. - - - - - - ICE Library - - - - - - - Libnice helper functions - - - - - - STUN Library - - - - - - - STUN usages - - - - - - - - - Pseudo TCP Socket implementation - - - - - - The libnice library contains the ICE library and the - STUN library as well as a Pseudo TCP socket implementation. - - - - Appendices - - API Index - - - - Index of deprecated symbols - - - - Index of new symbols in 0.0.4 - - - - Index of new symbols in 0.0.6 - - - - Index of new symbols in 0.0.7 - - - - Index of new symbols in 0.0.9 - - - - Index of new symbols in 0.0.10 - - - - Index of new symbols in 0.0.11 - - - - Index of new symbols in 0.1.4 - - - - Index of new symbols in 0.1.5 - - - - Index of new symbols in 0.1.6 - - - - Index of new symbols in 0.1.8 - - - - Index of new symbols in 0.1.14 - - - - Index of new symbols in 0.1.15 - - - - Index of new symbols in 0.1.16 - - - - Index of new symbols in 0.1.17 - - - - - diff --git a/docs/reference/libnice/libnice-sections.txt b/docs/reference/libnice/libnice-sections.txt deleted file mode 100644 index 0e73585..0000000 --- a/docs/reference/libnice/libnice-sections.txt +++ /dev/null @@ -1,370 +0,0 @@ -
-agent -NiceAgent -NiceAgent -NiceComponentState -NiceComponentType -NiceProxyType -NiceNominationMode -NiceCompatibility -NiceAgentRecvFunc -NiceInputMessage -NiceOutputMessage -NICE_AGENT_MAX_REMOTE_CANDIDATES -nice_agent_new -nice_agent_new_reliable -nice_agent_new_full -NiceAgentOption -nice_agent_add_local_address -nice_agent_set_port_range -nice_agent_add_stream -nice_agent_remove_stream -nice_agent_set_relay_info -nice_agent_forget_relays -nice_agent_gather_candidates -nice_agent_set_remote_credentials -nice_agent_get_local_credentials -nice_agent_set_local_credentials -nice_agent_set_remote_candidates -nice_agent_get_remote_candidates -nice_agent_get_local_candidates -nice_agent_get_selected_pair -nice_agent_peer_candidate_gathering_done -nice_agent_send -nice_agent_send_messages_nonblocking -nice_agent_recv -nice_agent_recv_messages -nice_agent_recv_nonblocking -nice_agent_recv_messages_nonblocking -nice_agent_attach_recv -nice_agent_set_selected_pair -nice_agent_set_selected_remote_candidate -nice_agent_set_stream_tos -nice_agent_set_software -nice_agent_restart -nice_agent_restart_stream -nice_agent_set_stream_name -nice_agent_get_stream_name -nice_agent_get_default_local_candidate -nice_agent_generate_local_sdp -nice_agent_generate_local_stream_sdp -nice_agent_generate_local_candidate_sdp -nice_agent_parse_remote_sdp -nice_agent_parse_remote_stream_sdp -nice_agent_parse_remote_candidate_sdp -nice_agent_get_io_stream -nice_agent_get_selected_socket -nice_agent_get_sockets -nice_agent_get_component_state -nice_agent_close_async -nice_component_state_to_string - -NICE_AGENT -NICE_IS_AGENT -NICE_TYPE_AGENT -nice_agent_get_type -NICE_AGENT_CLASS -NICE_IS_AGENT_CLASS -NICE_AGENT_GET_CLASS -NICE_TYPE_AGENT_OPTION -NICE_TYPE_COMPATIBILITY -NICE_TYPE_COMPONENT_STATE -NICE_TYPE_COMPONENT_TYPE -NICE_TYPE_NOMINATION_MODE -NICE_TYPE_PROXY_TYPE -nice_agent_option_get_type -nice_compatibility_get_type -nice_component_state_get_type -nice_component_type_get_type -nice_nomination_mode_get_type -nice_proxy_type_get_type - -NiceAgentClass -
- -
-candidate -NiceCandidate -NiceCandidate -NiceCandidateType -NiceCandidateTransport -TurnServer -NiceRelayType -NICE_CANDIDATE_MAX_FOUNDATION -NICE_CANDIDATE_MAX_TURN_SERVERS -NICE_CANDIDATE_MAX_LOCAL_ADDRESSES -nice_candidate_new -nice_candidate_free -nice_candidate_copy -nice_candidate_equal_target - -NICE_TYPE_CANDIDATE -nice_candidate_get_type -nice_candidate_transport_get_type -nice_candidate_type_get_type -nice_relay_type_get_type -NICE_TYPE_RELAY_TYPE -NICE_TYPE_CANDIDATE_TRANSPORT -NICE_TYPE_CANDIDATE_TYPE - -NICE_CANDIDATE_TYPE_PREF_HOST -NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE -NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE -NICE_CANDIDATE_TYPE_PREF_RELAYED -NICE_CANDIDATE_TYPE_PREF_NAT_ASSISTED -NICE_CANDIDATE_TYPE_PREF_UDP_TUNNELED -NICE_CANDIDATE_TYPE_PREF_RELAYED_UDP -NICE_CANDIDATE_DIRECTION_MS_PREF_ACTIVE -NICE_CANDIDATE_DIRECTION_MS_PREF_PASSIVE -NICE_CANDIDATE_TRANSPORT_MS_PREF_TCP -NICE_CANDIDATE_TRANSPORT_MS_PREF_UDP -
- -
-address -NiceAddress -NiceAddress -NICE_ADDRESS_STRING_LEN -nice_address_init -nice_address_new -nice_address_free -nice_address_dup -nice_address_set_ipv4 -nice_address_set_ipv6 -nice_address_set_port -nice_address_get_port -nice_address_set_from_string -nice_address_set_from_sockaddr -nice_address_copy_to_sockaddr -nice_address_equal -nice_address_equal_no_port -nice_address_to_string -nice_address_is_private -nice_address_is_valid -nice_address_ip_version -
- - -
-debug -Debug messages -nice_debug_enable -nice_debug_disable -
- -
-interfaces -Network interfaces discovery -nice_interfaces_get_ip_for_interface -nice_interfaces_get_local_interfaces -nice_interfaces_get_local_ips -
- -
-stunagent -StunAgent -StunAgent -StunCompatibility -StunAgentUsageFlags -StunValidationStatus -StunMessageIntegrityValidate -StunDefaultValidaterData -StunDebugHandler -stun_agent_init -stun_agent_validate -stun_agent_default_validater -stun_agent_init_request -stun_agent_init_indication -stun_agent_init_response -stun_agent_init_error -stun_agent_build_unknown_attributes_error -stun_agent_finish_message -stun_agent_forget_transaction -stun_agent_set_software -stun_debug_enable -stun_debug_disable -stun_set_debug_handler - -StunAgentSavedIds -stun_debug -stun_debug_bytes -stun_agent_t -
- - -
-stunmessage -StunMessage -StunMessage -StunClass -StunMethod -StunAttribute -StunTransactionId -StunError -StunMessageReturn -STUN_MESSAGE_BUFFER_INCOMPLETE -STUN_MESSAGE_BUFFER_INVALID -stun_message_init -stun_message_length -stun_message_find -stun_message_find_flag -stun_message_find32 -stun_message_find64 -stun_message_find_string -stun_message_find_addr -stun_message_find_xor_addr -stun_message_find_xor_addr_full -stun_message_find_error -stun_message_append -stun_message_append_bytes -stun_message_append_flag -stun_message_append32 -stun_message_append64 -stun_message_append_string -stun_message_append_addr -stun_message_append_xor_addr -stun_message_append_xor_addr_full -stun_message_append_error -stun_message_validate_buffer_length -StunInputVector -stun_message_validate_buffer_length_fast -stun_message_id -stun_message_get_class -stun_message_get_method -stun_message_has_attribute -stun_message_has_cookie -stun_optional -stun_strerror -
- -
-stunconstants -STUN Constants -STUN_AGENT_MAX_SAVED_IDS -STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES -STUN_ATTRIBUTE_HEADER_LENGTH -STUN_ATTRIBUTE_LENGTH_LEN -STUN_ATTRIBUTE_LENGTH_POS -STUN_ATTRIBUTE_TYPE_LEN -STUN_ATTRIBUTE_TYPE_POS -STUN_ATTRIBUTE_VALUE_POS -STUN_ID_LEN -STUN_MAGIC_COOKIE -STUN_MAX_MESSAGE_SIZE -STUN_MAX_MESSAGE_SIZE_IPV4 -STUN_MAX_MESSAGE_SIZE_IPV6 -STUN_MESSAGE_ATTRIBUTES_POS -STUN_MESSAGE_HEADER_LENGTH -STUN_MESSAGE_LENGTH_LEN -STUN_MESSAGE_LENGTH_POS -STUN_MESSAGE_TRANS_ID_LEN -STUN_MESSAGE_TRANS_ID_POS -STUN_MESSAGE_TYPE_LEN -STUN_MESSAGE_TYPE_POS -TURN_MAGIC_COOKIE -
- -
-turn -TURN -StunUsageTurnCompatibility -StunUsageTurnRequestPorts -StunUsageTurnReturn -stun_usage_turn_create -stun_usage_turn_create_refresh -stun_usage_turn_process -stun_usage_turn_refresh_process -stun_usage_turn_create_permission -
- -
-ice -ICE -StunUsageIceCompatibility -StunUsageIceReturn -stun_usage_ice_conncheck_create -stun_usage_ice_conncheck_process -stun_usage_ice_conncheck_create_reply -stun_usage_ice_conncheck_priority -stun_usage_ice_conncheck_use_candidate -
- -
-timer -Timer -StunTimer -StunUsageTimerReturn -STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS -STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT -STUN_TIMER_DEFAULT_TIMEOUT -stun_timer_start -stun_timer_start_reliable -stun_timer_refresh -stun_timer_remainder - -stun_timer_s -
- -
-bind -Bind -StunUsageBindReturn -stun_usage_bind_create -stun_usage_bind_process -stun_usage_bind_keepalive -stun_usage_bind_run -
- -
-pseudotcp -Pseudo TCP Socket -PseudoTcpSocket -PseudoTcpState -PseudoTcpWriteResult -PseudoTcpCallbacks -PseudoTcpDebugLevel -PseudoTcpShutdown -pseudo_tcp_socket_new -pseudo_tcp_socket_connect -pseudo_tcp_socket_recv -pseudo_tcp_socket_send -pseudo_tcp_socket_close -pseudo_tcp_socket_shutdown -pseudo_tcp_socket_is_closed -pseudo_tcp_socket_is_closed_remotely -pseudo_tcp_socket_get_error -pseudo_tcp_socket_get_next_clock -pseudo_tcp_socket_notify_clock -pseudo_tcp_socket_notify_mtu -pseudo_tcp_socket_notify_packet -pseudo_tcp_set_debug_level -pseudo_tcp_socket_get_available_bytes -pseudo_tcp_socket_can_send -pseudo_tcp_socket_get_available_send_space -pseudo_tcp_socket_notify_message -pseudo_tcp_socket_set_time - -pseudo_tcp_socket_get_type -PseudoTcpSocketClass -PSEUDOTCP_SOCKET_GET_CLASS -PSEUDO_TCP_SOCKET -PSEUDO_TCP_SOCKET_CLASS -PSEUDO_TCP_SOCKET_TYPE -IS_PSEUDO_TCP_SOCKET -IS_PSEUDO_TCP_SOCKET_CLASS -pseudo_tcp_debug_level_get_type -pseudo_tcp_shutdown_get_type -pseudo_tcp_state_get_type -pseudo_tcp_write_result_get_type -NICE_TYPE_TCP_DEBUG_LEVEL -NICE_TYPE_TCP_SHUTDOWN -NICE_TYPE_TCP_STATE -NICE_TYPE_TCP_WRITE_RESULT - -PseudoTcpSocketPrivate -ECONNRESET -EMSGSIZE -ENOTCONN -ETIMEDOUT -EWOULDBLOCK -
diff --git a/docs/reference/libnice/meson.build b/docs/reference/libnice/meson.build deleted file mode 100644 index 6a20000..0000000 --- a/docs/reference/libnice/meson.build +++ /dev/null @@ -1,76 +0,0 @@ -docpath = join_paths(nice_datadir, 'gtk-doc', 'html') - -ignore_headers = [ - 'conncheck.h', - 'discovery.h', - 'stream.h', - 'component.h', - 'agent-priv.h', - 'iostream.h', - 'inputstream.h', - 'outputstream.h', - 'gstnice.h', - 'gstnicesrc.h', - 'gstnicesink.h', - 'md5.h', - 'sha1.h', - 'stunhmac.h', - 'utils.h', - 'rand.h', - 'stun5389.h', - 'stuncrc32.h', - 'stund.h', - 'agent-signals-marshal.h', - 'win32_common.h', -] - -if dependency('gtk-doc', version: '<1.30', required: false).found() - prog_python = import('python').find_installation('python3') - fake_makefile = custom_target ('libnice-docs-test-Makefile', - output: 'Makefile', - command: [ - prog_python, '-c', - 'with open("@OUTPUT@","w") as f: f.writelines(["""DOC_MODULE=libnice\nDOC_MAIN_SGML_FILE=libnice-docs.sgml\n"""])' - ]) -else - fake_makefile = [] -endif - -gnome.gtkdoc('libnice', - content_files: [fake_makefile], - main_xml: 'libnice-docs.xml', - namespace: 'nice', - mode: 'none', - src_dir: [agent_include, stun_include], - content_files: fake_makefile, - dependencies: libnice_dep, - scan_args: [ - '--rebuild-types', - #'--deprecated-guards=G_DISABLE_DEPRECATED', - #'--ignore-decorators=' + '|'.join(ignore_decorators), - '--ignore-headers=' + ' '.join(ignore_headers), - ], - html_assets: [ - 'states.png', - ], - fixxref_args:[ - '--html-dir=' + docpath, - ], - mkdb_args: [ # not sure if these need to be specified explicitly here - '--xml-mode', - '--output-format=xml', - '--name-space=Nice', - ], - install: true, - check: true) - -# If we ever need to regenerate this diagram. -# Since it’s not expected to change much, let’s not depend on GraphViz to -# build the docs (that's also why we don't use find_program('dot') here) -run_target('update-states.png', - command: ['dot', - '-Tpng', - '-o', join_paths(meson.current_source_dir(), 'states.png'), - '-Gsize=9.6,2.9!', - '-Gdpi=200', - files('states.gv')]) diff --git a/docs/reference/libnice/states.gv b/docs/reference/libnice/states.gv deleted file mode 100644 index 609be2e..0000000 --- a/docs/reference/libnice/states.gv +++ /dev/null @@ -1,25 +0,0 @@ -/* libnice state transition diagram for NiceComponentState. */ -digraph NiceComponentState { - rankdir=TB; - node [shape = doublecircle]; DISCONNECTED; - node [shape = circle]; - - /* Colour the normal control flow in green. */ - DISCONNECTED -> GATHERING [ label = "nice_agent_gather_candidates()", color = chartreuse3 ]; - GATHERING -> CONNECTING [ label = "nice_agent_set_remote_candidates()", color = chartreuse3 ]; - CONNECTING -> CONNECTED [ label = "At least one candidate pair succeeds", color = chartreuse3 ]; - CONNECTED -> READY [ label = "All candidate pairs checks finished", color = chartreuse3 ]; - - READY -> CONNECTED [ label = "Selected candidate pair fails" ]; - - FAILED -> CONNECTING [ label = "nice_agent_set_remote_candidates()" ]; - - DISCONNECTED -> CONNECTING [ label = "nice_agent_set_remote_candidates()" ]; - - /* Colour the failure paths in grey. */ - DISCONNECTED -> FAILED [ label = "Failure", color = gray ]; - GATHERING -> FAILED [ label = "Failure", color = gray ]; - CONNECTING -> FAILED [ label = "Failure", color = gray ]; - CONNECTED -> FAILED [ label = "Failure", color = gray ]; - READY -> FAILED [ label = "Failure", color = gray ]; -} diff --git a/docs/reference/libnice/states.png b/docs/reference/libnice/states.png deleted file mode 100644 index ba23739804cf222ecbcdee307b4fba94dd31892b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48732 zcmZsD2RxQ--~ZJlWMn2=A(fGm>{WycNyCg1Np{&}i;PNU$t=k#8D-B($Out(h-@PB z|2=!&_y2zWxXLiHrBthna*@iXNpV7R5#Xl}_6sloF|TLy&8wl%}4l zN~GR-WBQumNn538sn4sj8w|{o$9rA3dBnRm$wbw$m~#2jDh7(jiw;O`;`XIAQQfLf z#^uW*RLe3uHy82rX=q;Fk?$q0%yva=f{_#h@mQ_kY^{5k*T z&6{aiSjdfxj9B*Uv3Hj6m8Rn`xWVUZ9;}^S9eLnF_@hU@pFe9%|8;Zt)v|4UeVv?~ z+^eiiPUH0HgcpY*)%@b)*;1ZA=RJCqF(xL)+}zwNGxLz5l2UVlwb8}Pm-FZ7=w{m* zHT(DZ<{gO9@E@!T8;mmYxEm2cXXrL_Vt%TZv$V97)u`jk7q9twhpX4FCFbWd?F!oZ z_U+pj>FIaXQoY~4J$mraA#MhWD^^xJX=rGcR#vLo+jWzlynHDbf82iiNK=A}fdRYA z{ODa#)7tW$9>chR(;uq-ePmcLv+zLq-7Vp&dsz-&CGT+>+_{iyoO>~3Zlr1OdyzeD zkTQuRCMHI_XLt7=adB~43P1ehQ7cMGx$@w6aufBO(1dDyc^Q%~@a!u=UJU2XieSM8T zM~jYCI*+#>Vw12T)zsABb4FXA(_pc#T)*DI=U#vHuzs-<-N%m~1q21XH3h2sDtzcT zIH+Y4Xo~bh>G{v}eMwYuTK_vDYSndw+^%zp;ZAi$(|eQ zEK;`*Zr!};)2B~4ccu*WOI#R#yuVY|nQPiVJe(G(fz=HP3Q|>5^G;6Y<>BRRE^)m> zDmU_6^UE$GP1>g8w1c~8c%UXYFf6PtTGUkJW~a!sll1p@j+AlY zR>U>pU1tV@h3#T^QF7vaGkJFf<(M_FUc7jbOHz_GEiJ9kV@)#Ox|iD0((-eH+{WFYv-*~-F`SYP zaHj1o`@IC3cHtN0y(T-?omKuFq?AZ!KE+9z{i&etfX+$jrSwMwe5YxrdrP zmio!!W!+iz@^5Y;VH0lIe3yj(-<**|Nt!BM5gPs+T8x*T%Zh!5T{{FRP&onr-ch~2*V>HPs zVJDrOB-U5w&ffg-juAVg<-MGEV0&|_nWAdF?8K7FdJ^rNKXKSpj`Lr4AiLQ6xc#s(7HYIPnXDt%L0d^_3!g@`*F<-LPu<{^*`be} zMfUuk8ybp2PfBi&)jtuKDCMy#p|7t${pmn#Hn1a?Hl)O`=>OR@@$+s4`=%W=Du3fYYA%fy*^eXZWu#Kha8HSNlHd#1h$ z4?Bs`P?4$)WjWWlVsoG}53%#DOBR?qA|%=P`S~5j+jnlPO?iqMmy^C1JJVmgb`47? z8H#hiT>xLgeR=+FWF#Z;wfCt%wqZ}Nx_9rMqN3tv);)V>X6iTx>xIjPBzHC25{n?; z>#=f(SXwkew9l%Jj;L`}b|#dmp^pzE!ox|NoSZs3I?s}lyvHvp2cS|_m#<<+IQ>eE zGBz{wUs`hd{8T0muj#>Qx0(EY9J}~)j2KzmG3#M`$Q9y4M7r~>s`4yaHMO-j^YZc* zzI$iKeo8om^(X}yHJiMqCM~+XmY!a{IBdAAj1-uO@#%rb9=0dD{OhzOs%Z$`}=QKP1P=5nS9^*<~mJBL?AVeTHsv?hf!J{ z9v;o}=eOri?swojks}w%9w0*EZbZqd`dz z+@yNyR7FO1={?}9e+5uw$}b>*cmMt!Xd*yBeUjA8qQspe9gd+=Or#xYd~z<#?bOPz z_RKw#-;1`8rl+UnwY2E!f&zsS@qSNDLln4ZNrj8lJ-9^sc-4&=Cux@5KUNl4Sy%!A zJVNQ|42TvW6P1uabL`kLk~~f{&hPOvS6OhK+z&s}($adhwdrIH(z5^O7au?N_wpiT znX<%Z8NBB?aDWoXt%Ue{-@;OA^ZKukD^dhk=ShguMTBVv?N*^b}!nN(y_5Iq7S`#b?~B|UctL3I14** zdMfZ8xFgjf9zOKhM#?cse|OHvd)C(0vdFj`;XC^@#JX&aDS(>2(su_vEgfBA?i3lP z+n0fv9e$O%PlSOr+P;2$yX;0UQ%lb6VzoT~D@3#wWw+|jME9bG)zOW}T;Lb+Yo8eI zPdt&jV}{M8k*b~B*?EzPoxS1qL|1Ch$eSiv(-2W6M#dUy4(S&?rPjT&;_k~1;wIJP zC}nbdQS~wULf574OkNGiWh%(f5xg&b?ACYl+%j}J%d5riE4PDJWXF~+Cue1ax}!FR zSSVpupIxn^5RrjqEf)X^1^uFy?d2tG6eEm7`fgU zzk?*j^dVxYPHz3KA0@LQ7p+&*$QJqFZf9u@k}+yDz#G}i zmoG2>78Vdt_-}}G$)-Pr=(P}vwOX4nWDX)#T3n8?}G;q+Pa$(2lOdj z8lZe-RL0TkzQ}&l$|?fK@XHrXHaQPAY(jB1HnwS0O|E0dnCrqg>(b9X=jin4uiQo| zZ+s#Jl$nElLjY934EJYcpeS1kFZ8Wo9}bjqdal|A*L7SLj8v0}yOgf;@&XO7Z(Y~y zS!2b(#u!<5$^2VC?!CF*lvG&A0tltAa+uuF(eYxb+i~4&!~46%%#7aod0 zp|W>$JaOd;_dADQv*lZPT0CCAe%<%;=Qfg+Wcqyvw|`~hv~^u#)N9KNt@Zn>O>E<2 zqsH-DGxtU&E9Qoh1CMzpTKuBmi2~6mY4r5Ep43C8$0AERl z8PRzqwY4YF!o2DR`_axvdrG7Z=_~%bOnC_jiDxM(TdVwcR-Khwt9E27SxDGeCEG$q zy_Lkk!0-&nG+ZrJRb5>P$SF9RYp=iGzdok(IP})ki=69C94NO+JQ13k%=w93gwA>w zJpv3?iHo-UWZvH1_#40CVrfwQQd0UNFBmG=*&Rj|pHp5z z8^vmu_x5rU8%$VO}#HFfnw?ewnWNBcJeNk~dW6q5od-|nx^%iUx^+op=okt zrQqOjV|)@EOsUL6M=*QWKR0i7r#p z+Wo!IH{;~=!&X*u_xrqenZH_}4|ZFZ)j)h9KrAk{-*bJ$vr8ni-~8sy>ZdZUIhGwl zP*=zd4Gpaf9X2&+=sS5~9XYbOPQda5TqM#Y*K+vu@^PzYB)W+t!vBs$8c^0vyNND{#^d zxYz%*!=_RajI8YGc`BrIhw3^}(k0cBUR0uGNEqaAQi^9beNq2F{J=ZX^sna$Cg7Jq zJmoo8s-{7<^DcG!^T^3@LX{cq$mS$~C0Ou{%+bw@?LQ`4QYly0))I9DZATi}0byFi zDkMXNj?yQYvYua173%f1yR?0~1NHZwDG`PX~i_qK!E0mKQJf)F1p;m3bZg+XvDjHj${)v@x-omRmR# z4l)sp|KdA`{Wx+1gM+!|%{*DAGLMRij=QW+soeyJqq}n#`1#pCh0;n*GI}L%aF!ZW9Az3QdYmYw&*Un|{54G<*^t-{4?d^jH zyOdQ_OuWTir-7|G=0z^L@Z?A@83WaX2w0m&N=A8IJ#z^qc;U9 zS2`YfLc3>Aa88a0p`(HJc_}82=0Ljm{P}Yq_8WLD)`mw)YL8m#11!(olf}MyVvOgw zidGLWs9Br%j*sMs-yV=`;bjLDi4roXe6Ua52AlcS#oWyh{*L|=18QRm3ne((&nzO_9 zX(vju*X*p_=OGHiGQV%Z5r1uBN=+;D@7UNm;SrjE{5 z2toL4dv+C0(Bu@E7tx!`9%rhYH|6ND)7y3~Ike#Mr2o!6#y4+h58^(Le;3QJ%6$2f0@(8e%C^hm z1A&JW?6?qH2?*{S36x9auJT92zpCa^4nm*$SV_FZ!Z?v?JF)RnE`Yk2$NechmNuE zXLfe*!_~w1kgB#ehRMmvyw?yVE7eu?UPML>)Fp+@Xpd--PtNmo*mmiwsZo^v9p3Xw zuYel(LBeHTfGB2fEjw;3q>?6ZA5O=Kb3<@Ep!LCxJ=1{5nSHkS3^(^ODHo+xLVLr{bwa`R}epOvv%_Skh!V^Ibr0fG_8_IA0=;#N>YLy%4YM{~K z@$n&O+744a?D#EWr?9cJ)3LK#SS`e-;WuBfPoN^psz8~uA zmE7EByZiV3c#H5=n=#3AMcr=DnvsFMfu=n3MMu! zp#$E!b<1hw$sIuNSCP{D_U$8-9U-IA5C{^=Cr>6}r;oiN2ofBd#74C)f1HI|w}jA@ zq@|_J=U2FhFBz(=6|}a^o_11#8Mv}2G3bZb`{);L!i{i~ zfvwxASiFFS zn!RZ!UReA(1@$XBCdQUsB?`5FNK5V7ucdSWrl~?}ueZ5k9k!B>ps)}+!|vU?3E!qR zWcQW>2M&-HCwCZ@y6uK-gB!Jt1X_#LD~FqupP!$Tm*<CE?#6Ybn4#*<8Glt zv^G2;Aq-qc=fVZ0gG~5Ie)o=*1R(acrVzEw=FXjfu&|~rO%Z0-uMYHlJ-+G8$D(9r5w%htHou z!vdD?`4WWX!>^Wo#iyXoosQEdxDs~EApj@-#I*)t@#zmk2# zj@@rH0ZQd=X$~6e(sWNt<2^6YF+lwtCc3`TG7BCzwNcUdP_=qFpIWV5^~8lb99kF= zcI-ZR+~`?_@81*N=gyrw_3N4?@!q7RREMJnm&D2Km%PRWhGcb|79PT&fzKKq7nku= z{<;7vkk6v!Hz4yykmKE!3j2_)CSnQwi%Qks+)eQ$HYcOxOU~x59{QeD!O}bZXjx4zL z*^7#bUaoKMV!XWD^h0A~EoAgAiRR=~IMUM6Y+l38H%d#KYxyIhqXWT&fi?%)($9sh zErT_v`>b;O6CMKwe-$(7ysDwuigQjy)YjK#Ux z*-Bv6ZoK*5zkj)LM*jQF>yEoEiGU>nq;3Zgd-Ui-JUh*QX8|7dpj-^=WMnLd*NWeZ46PIP$~e( ziBH9<9X)z<>1UJ?Ei-cfx01hk@v+;V9_=T2L6IcrHNY$-)4_6dd>cqh0+DKjj&Eyg zONbCe#htVUdm`Vl<8D+`$CjF*_1gqkCWt6{xRLt;BfJix9RiOHj%SzE3YV>V3mLq7 zVGpH~F}rkG5K;^jL0nOCvxl16y=4~2?$i*a7ev2%8vdS`0A2GM8@utlyMV^DHbg;L zc`E??(R^kGh8ImI&Yct%76vm^d2&EhlnzCk@HEk>2uaP=)s?i!*9=2sPixv~*U_^6 znZY{Is~^I}|9Wt-Gl$jrAX#wu@L^OfsoC@4Y$A&DogjAyFW8+}%T-G?Aw_GaUj=D` zc`HKt3@aw`(Ib%}{l;n&(KrBgDd*X}dt}`t)K8siHlG8o`rVSM9?~?@J3ct7#Y9hE z1=}S0&6_v1r3e&sjM6wQg?(R}I5PFzqAYC#WXtU4&F>~g5G!l`#BmN5*^e9v?O&hU z#lTPvgQ%@LuCaBkTkq2cmevp3yzX<#J^eW}Btl6^$rqv8X2j1F9HS}VHdNLR{LcB; z+2kU)$a}|eriUM|>Z@2}UVYc5F|Vstbx0tF&ETM+j&H94j0@Q&t4lMiE3%8kSj_9H*5Rj;QZ1qB6S4*&HfI3MRaXQ3%n zR9A0R3ZV8&NZ`cz_!@(Mz*+xlg4$m>GS@#c5&%JeVbMUPb@r?PH#?gT#m4@1wn3S) z=FX>)k=sax;EE(J-~p0|{ji2c?2#RaFjS|UdMI-H_eB7K0qo&g-yN~z62ZzmtIOlr z(+dkVkg41Jl5=usA>)PD{~Uv@KatUFgfog@KqwSbS)25t^unWW=SC7dU#{$jsN>*p zgw%(7IToa`0jayqy<~N^p5z4!O?J9&GpV|+E+Z`W^=s`xmRLic-beObc^1&k6~j1W z0M`6~MmCZ7&cwgSm64G#;5BW{Ju2r3S-uWV|CK9O?uLic5`M9V$0A>m0opvLyK+WA z#BpsAiR6ojNKRG5rasa3PZp1TM|0GZO8VwBrcFj7n!dNEosK&q8yXVgd;k9Z zHA_R>^)kCkKZ2BD8D+znfF@qJctVRyrIjl zeK^Ft2M>m{-j?)EQ*SwWGOVl{?zFTTw85)~zlp6yyu5~&uOC0R&KTd|O>6!&VO$_( zC(utA7{C@NbDdpXcI-b-#V39|ublniy!KF=QBo2du$kFe#Y>lVv$C=lhR!OZZ&F*=3`A@$j1-EiNf%If#BI4re9Us-9 z>Pr^KFV_Rn_Jd^K|6C`l>wr~(1a)h8el?40(slP87LCv#f!qWR9r`J$7Cb5y>)=GS z*lzh&Y^Iv3m-9-+)Ms0s7Tv3dV;T*G_P%RqZl(ii!dBH+afbEW(w`o^tG)INOZPR( zc#SP^EW0#8QG6A-J498M}5ySmG`SFc`u26TmF4pe*i z7seqKU0tkCBpo57ZUJ=AG(GQqOyBg&kL8_NgAc_~RE)1&sc@ufQHY6-mKR`9+`H>n zwdBv!xD#iBYE0s#?odOxK5_m$BVa#~hbb?YFP^F0lk@hipQeCLmtP=Uc4xWz)DafNbUs|oIl<TMX^YN5N-1 zHxJKdH`%h&E4&lILPsCwe<`xR{^-%8@`{R0n>Q_93p-hy^5f_5unEL%lGnF4*OBeg z%UBbuwfWsC`n$J`69+q5!Zzv5>U2ci3d#^yq?#!BK~{1&^%hk(bkBUpdCJsHMJp0(Y6vEDC7qavT320`a!>FpcIbvKQ^Dq{f@XS!{d~^hVN>cxogG`=B zrl+TeaGhE#=PyMeL~NH&W7g82@F5R8;ZBBB3DY$aYrM28TrupwU6 zas#9cH)V^sb`6jh~c?d%ktosaXopX=Xu_H?3VACb&LRiFQ} zt_OyN<2i$LfIYh(Z3{urG>wd!PW9?IeLM&7w%ZJjECl?l zaGo2sWj|qw&!J^!zb{<6@=kQNdOB zjDIf@gD{uZ#gAK}+@56+jKp1*sZAQT!sxd*{9xlvjto8uP1C!qM%&Wqfq&or``wG! z0yzZ*9V?eUhl#;7|J|AEGtROd&Ng*>d%J!emkXhsKVjhH47>Ek%$D899x^{zV)f7Z zsQ)5)QmcnkQcO_=FS{#H;Nw-11qF+doa1rLI-MZP4j+9;(qG|4Mh3WWUL`hmhV?deaKeM zFIu0U9mEzNk@RoupZg0n|8l|(3v-wo^NhH7P2zAvH*9dEdeZjh`dQRLzi}3q`zMQ) z<3d70^2EnrU~;^KM1=sPe%+T-h&nnH6+OY3HGc@wie%2)7G~`5Bp5W1*m1?z|1K@T zLyp4RoZh=D5qAX3y1f$G;NcjJ1MVPPM72^P1Ts+v*3*)fMyO#TVq$}m+eK;7D52^V zfb`MP(w5_*Y6oZX-gWKdPFXXzUl7EJKY^n(JvTQf>3?P%dN|TWMWKlWqmf?!E*Kr= z*7*w;3dYuBu`7|s2tg3>W^XAwlmXTRIZz>FC$^ASj+oPyu1rc{o!l0G++mS+5cuGaEjyMCPv`1+;$$2Y-2LCu$qGXL^Eli9E_Z_00NZ6&g^@^fs*dV69I zBJf)1vLFaZ^;KM2H|th=atI?wr~v{JTLUHzttW__E{%AI1LmZ4cuO2sH?}E{lR`0JC+27?_I5ro-LI zfgY28!)VqC4ybGgU7PI2s(t3~WJ;^vjW>S^C(b_jiB@+LP69pv#$P9)!Cr6t){Z-V z>Gth>@po!W=Ff}im2!y;Z?Tisn(fV-ua-BUb0@xcWMB=VYEZ)j!4gEBXNSmUL)eb*!ey5ubD0ZHJN@da$ldd@rIWa5(`iSa$E0`C@kawz#3^nj>KK`5(1OCxSUT`Jtd# zm;U7=VjiF{M6$Z1iD(^Nmf8Ktn$@9E(sFQwf^ZP#7Q#G=wzi^#?F9qiWjBQGTDTYs zUrf)OI;EA6fE{_zsFY1^b$Sc-*GBpACr2!HJ$U#Kl!>aZXKOtSgo6g}bWC06<_Zy) zW_p8NN-PoF+i0=t)I?B~psz@@^g*XIfQ$X&N2$?erMReAi)!`DZC!NP@TDHA?!}#h z+*J#L`wh_`7Sj;-nHuJsO;2TR!g;#+_2v07_sI=$WlG+j;SHlpm(tgRcaysFEa>-0 zItW0QqWS#>OdIK-ONfrFz`^UpyK%(KSP*RJH;UQW5>Dr0sD|QqCiNHUPA4Bq)&2;X z$kN>0m=v9zEqq}A{wsDx@g>O8{YK*O=F)Wk!F~IF-WAW*FRDc4s>Uya^b6o{TtRN> z^S5s?4bh@XroAgGuASMRdP-d1pfSCHJWAGOZjq37`={M;(-4c__Uo(8jtQh_#YE%b z;bDAB{6@6uUK1$IW(d=bK?{-hHT+AeSxXwSZFdnf=Y>@rA{xRj#Y7^28zQ0q$t;G1 z5G-*)I2hTXWb5A2rHO)G5($ZOoeg87LK}r2>;DrpI(RXMM4E<=Pgv~)D$Ft}qb3pV z33OK5v9|riYk#_JY;4Mp^}6{$It?&$y9{!&eSG*hpDM^=`DpzrWzIh;Skr5l?&hm$9}4(Fx(+qX-DEYDBJ`J)05*<|Ds z3LSp!A{pbdS-a6Pj&@l{HV$7Rv<56QGIX0sIfxPeM*;94g6Fc!qsjd1hF?^q+q)8X zHd~5aZ>)ydSTTYwne>Lpbs!*qUPhbSihtj}ZAC>zh^pLl+(TsHmn04!);9PI`}H2O zZ7AL3K*)EIGQsLTO>fBm{`_s;w~kgxyCL%8;$oY%Wk;-^!U)qdElAjnjs6IhxZZK} z2e~#vo^$1I0HPJZz5Du#O$pkx4}p+*t@h_!XLht8(LJDeeTzY(+};Wj7?Lq!@wG6nDu-*Zt zd>!QRLYVAcs(TerpWcbw3NiPCa`#*)Z;^86&KfkQ^ywZI(7m>{M|`?;ikJN;tjPe3 zfJe5b>rfz=gb>Km(vtMK#1fy{Xk1Z1~-;F%DUbrgbqP8BxWJ7989JmS$wo5C;cu2faZh!U`C(< z!mrHBufxKr$eEZT`K05taaKWLQ~Z-B7W*4+>mc$2*aM^;ep?BzL)u4AFBo9*!%sU5 zXjQ@^ZLKecX*fMUUyTg@>9D50o}@X%!GT6CfByWL$H3ognPFP4Iw6t(B z1!E2-6qa6LQPHpJlCJ>sSK#OC*Y)W`T>^&rbzgY`__+Dbk%6CH7~{f9LXJR9y?OIy z->+ZkZ=!^)tgNn>n)-xf(vga7}+R7sC7P9Z{Y{%`kLa0O{3k*vE+3M`YO$_sP1esE)4X18hv1BNIy@kyGe5ECsnS50Ccsq zwn8MMR99Cg#?x9`&kY`uTi%PZfmFV#s%oF4+WT{Yk;GI6tN;~CNprd5z51by~Q98lmv&6Xt{QvOb zgO{d&G8hEpAIYJs>DS-hp12H0otvLOU|e8=Fpa_f6%u6K3qwt8SWNX*xKa$X`rWBu zLxPVH*)OO(aQ7AQ9w4_xp|$&Q@(7Iw$pIpSgsg%N;=?$YB3Ra}WEQsCi*co+KC}kP zz5O&qfIKE92s;CgEKw;rI5=p@&3T;YAxc8gHU0DZo69*j8cx{|0y&^>=&OjTGBPqA zag8695iDLz$4>oE+7Enc6AY=#Ics$IGC9t3X2ht{ovEImP!_%+01eFL4>{J3y~dak z!9*f6z=B~#!Q#R@&KbqUY)G=)Rpz-185~s^!zPuEdDIn+jnu>l5fbdv;6MnFq$7ZM z@Y3t8ur=$WghwPp6%HUsk&$trLzLX&!gd3v-KGNj_bc4EK^Q2=Q}&IGsVzodCbUbb z+rP^(u5|BO{bPkxZCmzVLBtFfS`u8Eibwm;6^5El<3K1Ghco(%`eS(s%@Zo6f`Y>Q z2h}|w%1iUDX9*~50!%LH*}DkODO%1`7L#JrK$7pOwC1Mt{y0&(pXyj=Xs*U4VL7iIH0bdaH@Rl9^e%zluUv zuv%);%0xBS=;{8*`kx<~n#fFv>BLmVG>3RxlWf|&&(5sJzPDHUpQL&Hv#C1S?&m+TcX9Ye!2XPIez%1znb zPT1A5z@b9_`I4&6%=%;WZr;1A3_3l2r#xtJ`cTM;mRh7w4PpuLhL978IAU2@Sx>2V z^Osdf8%vP5M6oW?!it}-N zI9e9+PhRmer<18tr#caEuozVl&M8uGgyZ^yxkW6WkAwCjWnrj7-Ye`$VxtjfG6J?rpA*nIoMlRTD4BULty1%qlf{7Y1So>e1AQDiJGq5v-VH`k z2KJ=s$5BxTDeoe(3bkBYDxYo69yEBworz0#xM88C*cE(cL)Y@=O=T1a5|@Zb_`R%6 zwnr9}E-BS{lnHbD<|$uSDMrF4H8u6fr=yxrnS{BYuOE*8Jeu##Z5+~Ua;(~T^m|~G zs6R+9!W=CE9bV3quDp7)WF4Y`kBLO1`hmcTFX?pII)Wz<+(7*B%C&1Xj%=0Oro8qa zVje*rR=2aahb~_Ou`N&W`pII%E3hX5Fj&oK0L*!8=44FBM8lncoRwSI<{|pOt3rTZJhCoDl zuutCs!4!gH!7F>0r@`@3<2Ey&8@J@{UcHOxC1lXD(Mqc!cwz`0#DN@$sSgf4F`O*V zB@gK3@%JY)8qbvv;oPhjw9_&U+I@G(V9l832LC4xRAQn6uQf5>fcYcn zwr;RTQM3PRpviW5-hyb>*cib4IwJssjY?t1_w73|xQYSdi|*7e3uCFaXD0p+3w(xQ z$E*L&0{mZgxOsdXWF>LVR-@jkwPGMz_F27%#`}X>OGy}H#;+MOg|B`^}Wf~$AUhvm;voVFAcT8NI z7-A57yMj7F?qZUYlTUVsNe-_xot?9{+4#Stg2jZow1bNy<{pNihSADAS|huHYcvEH zUL$HD*Sxp|;fQpd*MI?54w0`G)Em&@VayTPzaLHe!mjPJ@zVcF3QF2VYU4c#lN@#j zqB)yM|3mC?THq{jV~_(1AUQR4ySe@UuzL~__=CMv39cvVvFdc+JptVP{<@dzfrD?a z0^^8?idI0RJNi!?88mmXo?mm0FSSvI1m(EN(0gH^h;q<$ExK(J+kQdf6rt zJiKi-)(=|2taBk!5%b(W+jnXg;9G`bAX!4Lp@}#cM?-D@N{e5! z@K`4Zzw@OW+B5Ug2`#eU`NSGuPq@*clnOq0dGc zy6nI^0E<}8$p)sS)emC2T*7Y1^V|EmoEM+gJ^QAv$p3L?zD7sq-j;V{<$P>Xw7Tr2 zbiaG*YH2)Xsb;BZX%d8??%$<3xAHXEDyUzhc< z`@M)z=1Hv33{z}HGS(PrpmZ)b-gcEq95 zCewCoB5f`7?YC2)qDZ}T)D;8GKQd@M98jDb&J-9H zrUI2v6l0PY)!9KLm5^4emtx{(O?+GzL{tPk5e4#BM)GmR*pw&EG!A*cgM01Est%lK zb*|%X_>!r2j365bW02qn6Hj?K&d42`_?Wk6Xy~fL=of`w-=r0fB!*QG^qit{+Q^R~61$raiFrAl%yFt9tea9{4jeA2aPIwhP zC{_hAGC4TouB4=NoS#S8{^`r<;h#T=%nj7+u}?~>Z@zxN>Bud-Ifn6=Q=O5zF5+^M2Rzgzdr3*c_^WI1@qk7X}UIA5*n07NN z^B}^5U{A5`d9jg^#B(^1wtfcC2ZTq=+YkZR8kQy&BWxSLb-9nV=R<<#+xY*RQMNI6$QBqt(by1OrBpO_y_FW#lK*rW2So-MDy>G2)5ClxHj1YF2}9w|bJ*^aN~ z!VVzt5-_vQB*@-Jb^?irDqOW`J-@$t2BkHKD>VOKVRy|-Ztzvy4Wao`HRJrDm==EV%@3_MAaig3aB5|-l!bdwHCn~Dt(G|eY|w5cRRcPrGS!CdOc zwbaFfHjdaw1m{J3_V`oh;oUv9u?Hc3-D2J!sg?>iGws&*z#cpE z!Jvo8Qx?T^^ z1_f>jpbIOYe5#~U&%oex)jC}ZIrBNWt**CJn8zz5!bQo-q%Q`kT@szTc=7es9ZZKV zS4;Wp#z5o|zxACQnQSQvZi)p8tiLQwPS+tO#n{T$f#VwUT|txiRdf#*M9;`x41GQ3 zCUl7i=$}1%)@8Dk8V#Rtc_eK5NLW09wgbg5od`8E!jJYzTVpX9pOZ(}(|qebr$0Pw zjj;jJr(#cv5e}@F+2=2#haGExIzu6=C<=9y)Kvz0XglBU2%qxbo08fUd#9@NkDkbf zYt)S+lk#mPi`dl{GK7yI_KPv6WZ};{pD~76k9)3ih zalXc_JQYJ})!byk%IEA?)$mFz^s2k}+U~@{^A5WX^I6??MfRFS#Mo=uXDkuw*Z=_a zyg6O}87(M+4(AxTS%tXijaEzDBrbCi8r6US9t(wz#BI{iBWQI|5*Kjs;P6Gc`C2lOLU@L zQ7~J1sAMrm&Xnna`ryn;@Nz@6))wu{=_ ztJH%Q2Z!b9C2~OH9VoKN(XO{#~Vccwpn{uGJD?qzkS+hUnS#M(9%mi47U z8lT;k7Yw@ct%%2b^oR!D70dby?f${`5`N|2i@T*Ns*0u5UUKeFV?6a{X1vNeT+@x> z=V3WG5Ox|b;xIs@rK@|gJJcpw$0zReb8?&}iB2 ze5*@L-bV-sgC@(cgqYHu4OOIiltdhRJS4~eI+LO*dsA1*-Rl!QFOIFD=_;OhuS^}} zkN|B3gNGPgut_egRljqDK1m89J4P;?k-EVo0`z_W;Vo&ev&|F(Z_@|Y5FYRpi{wYl zQJ@(Se|Hi?t?Z8y5_$)2@j%`s28nqvW&q=;nwWFb)%8b;iI^@Trg9-__`iOA7_w?5 zrg@PqAbDX%t{h4o5T06VZ5U@5JUMwTTH?t~P(LABY8So2_z&@xFtH(AvmmbyyoTt- zH0nc!{_xVwpw`8UfoEm^ZY7?z1~}V{7cg1NNmi*8nrwhPhtMYN!PIE;fHPw3P0%_S z%REuA58_c{VDtiMCsb74VDZFiSzHJ2AG^4*z80e+cuhO~(F7tSKaU{Aa>G3(2Tx~t zp|6Xl9+`&hH`H5P^nY9gQId&+Bg?4)5gEPWolnhH=+^c={CE-1;^1R)^bf@|V-)ao zlO|U@9|VuV)0tVpd?4{8D|kdTdBi`=Wl`!C;Th!E^eYmNR1jcz8Lw;4up41ENI#fw z%+S{b!Fx2@wpNmOZL+t_C_S?#n7P1d4{aqq@!TJcTeq@W=#kN*HV)a(Xdk1IHopS9 zl^~tOSm6CLTfCk<<07IQ=wpIWUv(V2n?Uh^tw_X!Xq+$y9Uk5JTIzkma4;qJ*YGr8K9<~>B92G@eUdyZbs?@8Hb6RRqz?}R?5oCeW=sKgVFH36g=#yz)JN) zD{YQvnG4^(eHBejVRtwbRq2Tb!$I;GM82%~53eJhz=22GK~gAq%lyB%dJnjs_xJz* zojtNcA}i9#3Rxwq$SO%zh{{M5j#A2|5-Q^ml2MXM5-L(gsScfJNR%QO4OCP{2mkx! ze18A+y`9_ldv51Tz2C3bb6nSBUCu{MF}v?7U4Japu)wd%NOl2=Wuu1i;~K}`*!$mq zcun)qZz~$&)ZTVKs{zLmD?;{_w^4#^={d^pn)lB-K&){|Hk6Pwb%4Hp+6e>uwD*P$ z+54Z#2cHkFreG4YTy$-EmagwT(dhseEzqMY+f>5ysIIdvE!J1~%{1@_Cq@dv%jP{n z)_MB)v;rm{9oqLh8t-0u0-&L$bx{ud3s(y6WV7mHkaDkHhj7M%W>(|rcT{4Lvt5lV%S8jSFAW6_SERnZ&&#b=o-pizgJ&ykKf@l z!l8)u{QS(*4~GOg-hiV6OU%8vi4P^e`}ONa3Sh4k$Zd(o0;m^zS5i{Y@K@~(CcQIh zmSqEkgyPG*+ZLtmR9BLEB>8~1HXpauE8GAfqugca>#%(Ev^(SCMsnr}a{;;sNClac z6)0hG1a1tR&Edj*{)+XZ*v_Jt90Hz^I5W7rBq;Rd`gTZ;=XCQq=!vTkj*bRBBGQD< zG|62+Z1Q^0%kmP6u{Tg(#0=b5+D2|z2`Ld>lh{IdRzktjs81bo&IRHA*#8o z0*(ntcvS1Gg5mL-vvp5&>$5`+wYDf^p@=#_>u3NTWsyRcQ2S(|$@ip!r|Q>)wcvza zSZimRXR!IJ$Sc(b$17C)w9x`+fN)dkiQyMXwe^}AJ??t$DRQ1@Ig3Xmz_vhC3LTQ@ z1VAoxs?KqvQE98DHq9fhokYvgDco4W`7@b~nHB4>5RH3Jh+Vcalw0V{pjOJP(#IF+ zG%#VMa;y^trbDx_=IQ0LxsKO{3>&tKTMr@FZeZKE2Sc3}P#=nUB-+-vXqJk-?@l_i z?qgiHQ+dgfLZ$7Z8>Ga}owX}JC6>+u15gSgl8z&dV`8cLdJY(%3`qFo?@vzmPYhoz zHu<6<7WO&kTjA)Sj|O)aw}7Osz@tt!%eLibtvZXLl54Ox4l~v%qWm1Y=*SEV4p9l8 zT8KS;WRa_3NqXMg=FOWcw)4t2m}ZYcLD9K$XF|UOC%{|_xU&7`O?~ItVP24-*^<~G zE`&jgu9E_@9Xi66EdyX%tlkPK=O9g!6T4~LVYI4!lhtjN@w?w)3A-AvI(lNzgnj$= zLDe-vB!A7J;AnT_Y>k>x?Rw2LWBH516xk4`Nvc%0EVb2dniflpDKW0N+7G#?eB4-B z)C$A|DZ8i3U!mroXIv&J5l3=qv+GAPON@4}gNpQ!eS|1a1Wf^JZ+U}D*e{Qc{BV5b zsk>sT6TxEG&B>3KPn|kdGWMcL0V|qy>I8OSc7xfXMat3h<;X!_ku`j&I;F>fZ5+yr zuCG&qYPrLcmN3>e&#ri+4=)HEvhC+)p%PHO*%ibNtQ@5_56A;8t%QOk1Yekwv1cmm zn?N^k(x`=8(|QjaA9}+3?oA}=0-BO*Ae}O#@*+J;vrup(37>@MjGMb?+mmy+C^YCE zAC38}T&WdV&hr+&3g(inz9}thlT-Nd19OiaJh+1zN8DJYgxz5!BtPV#{?UB7%?{5T zdzaebcOt}%L0?H!Jqt4Aw!}&44yO#2x$wFqSQeL+O*ODCYo_-K<0#Ccd|M>6tyivG zIpfrrF5D;ywlU$f#4ia2_^)$Z#VouH(h2{E9O!O_wV0JfJs7CQp*I}RTf;PLb`Ij7tONFfNd7DC}qcI-=tig@&ROq_=eOD zT|Umb`}Ef!tAsto)dfK?u1%8E6>HX7oP|*0cTW{XHSxvogubt@DbHG0!{Ket|WU{}zff_E067}i*TdC?O zP+=V#y1a$t=Wt$s_I)gJP02Ew?Ay&d&&u7$rCTH#;6|`sq$u5a_|WBqj{xig&1 zxf|;~7XHqssCs!V-m= z`n2h;Td%WK<5Q>aX@PTFHZ8d;r~vl-G5dUG)3q&!q>3Mg7uIIU=4ubiw5E;&IVJ=G zf+o53@2Ba36;F4^@lHkekdt%x`=`11OM1mfWCy{)1kQ*KS$Z@#t63)UE)fMaYSd^c zB3#RYR>h!Wm)TsX;#v+)tZ834N^klge+{5-7zL;D8?E6&Us6K!Lh(%8V4G80>K1_a z<@lIKmI5!1BDRBtOv2(FecvQG2SCasMHITQ#$&n(cY;V4SR#=>u7s?@?{+sH?X?^c zq&9=s?Q(y6w4b-pPVmK(V>Y!HxC4jDjV)SBU@p;qY!3+N%DP1W_o%PeSlWt-2&DBk zzMrzh4n>mcu@kG~Xd$cW>Qbqf%1Vz0i@O#R6Oppq%ad?@vJ5P@+`!N%VSww&-IGF# zw;$Z~t>pqtbpK_YHDvXHw~5U<3Eov$9SJX%R1Vtkz`E?AoU#&}2P2$GWyTXcgG|PL z^hBHe#jKh=`}QRh8AiD(MK+ymTJ0#59Bw)!WsXemPY zAp8HF-Ltd7))mC~sUYT{Xq&)!i2S1sQj?Lr6K5|H~JhfDo{S&}pF&>Q$L7t4^x=Dh z)TePIP&fXg?`y?Fe>}POK?!^k_L^oorR-{6rKst&EVNxU`!VkOprn5+Tz6EqMmdc*8fQB_nyQ>_eXO zBYoe8$nh*#LULNuu1i!Y#PDpd&bw8`AkEdl$K2Ju&E{$Bo%ZY*?tl`Cd})4zf`UpP zx9`>kXICAviv(<}p7EqetM?LoC@;*t~~VXy2qvr+xqj{%4UrkNN@~C2N!3p)m8rdips0Cm$xC$ zoUH5x+fGK`O0?rEsomQ|9{4|6fbPrC?X$9sgR(>WZ?yu_Yl((_|BzUll)Y|IV8R!l z7-w||vo|~pclsb9{QT#K`R1)6Z5<%*r-qof>TADc=<)p&u75;+;Y_l)6?>z8jrz(` zi>o`Ve--IESG}AdQAk{iI}WxB{Ms{8gK(pUO_arKPk`5D;U_#gG7Z zk-}Yk9E&PmK#Tu!^Chm0L(XhKCAreKEC7f0uG2902)al)IF{aA!LlpGH!RC?y=Tu_K<^(QBqG(WFl z^~2@Wz2+dXqhcu%H4op1!F0R$c8?1sDc-0pYv`}U4$`W7U&T_e)1|k6)OGDjbm=}n zzm;UItmr)0YT3lI2NEes#5zJvWwN|0UE#$uXSVn4(?^F&IHg^{3{BgKXD?gfND?&% zb^9F>e)J$C#B<&O8`hLz`u z<%$a~PR}w&D4DG-wEs0$x}k0{87 z^Ra4l^f*6A@jlR{$eM0^Na}nlHTTaMBahD?utEV;miLsKZ2=X~oLHeIm~eX~E=zYG7Cm!E$E(M!E|&g!_?`VryE!#|Lmd6_$EujEirY?pm^K6mR(o^Vrz6mXL3uwYd| z9$~C2c2$m4H2WF(R5V+sPcNys)G=!hl`lQ0q~6WHzV7VZR(2*|3*6T>Np*JwU#e){ zr~#rJ(XFqnjA1*wWd$5rG{_ijEUfB6_gO2;-fA0|lNyHgNBrb8^nU=u%hh&H2@g^e z#Uhdz@W1wcr#o<^z5QM$fuQ^Oan2D`y{g-81J3BciT^ms7~JeoN+}@ z*l0Qm0;&>%OO*@9#7$5Uw=o$|N(vOkyH=jwa&$xQiF*{PlJe9m) zE>5n+%u&a8w;goB|K{7^qzGGfpqM_GGs4N;5ykT>exuDx0kmh$nqcTTf-H3PKS5w9 znUNt~vl={fx81H|7yS-cZEPNryJ^10*2Z&FA08_z)~TF-?#Q#JPtRPxeyqjX4zr4L zmDtT`td1Svg5CLXdi770vbLEo=y+(_qyAgJ#C89BNUJOr&gU_1HO)9J_)?9u6D%*j zb$mmTAK88rqrMyU{l4mQh4FQBC)K{$UOGdDPFfNg#=YN4;s}}W0Nj^(_VCeoQgtyq z2`ofyh_XZPF67(B)Q<{<{^5euwW9BqjOa5c2=U(V9nB zKKQAz5quxnNGv0J&twOc_b`NZFXrHip?55_kMR)@m z#Z4ti4VmZ);}@P*Rn|^8N$jBHj4s`8P2E@X;j~={ASml#0Wp3&7t1sZ;tqR3TR@0O^MIcHf}%o1B%H&g z%ZhXR#9s*N1zk_dLT||{2k-3;wvd(8Lw(OD!5UVrB=XP5sFA2$Z0EL*?0xut6}3ulsv6P60RvV}5$B&w zdVpKrOYx!xO`go|QKHB!%9_%!QG*>;l>7Omd*V6*&Pm>=#5l9>4JY~A9ckL8`|p_< zxe=Xt$mixviW|XS#3!o4+?ph0_>7&A6KEzzpZ@oODkM&xT9(=;E4aN;gq-^vIBAGS zfA@-}hl!^DHGwxFKIr#Fi2*L%vK4NpzTCf{c5NrsQWqwkBta5YeM%qv+1GH-AqsiP zYNG7%#Mo6iD#M2S8Hzh@17_@`I9bkaxxmsg=;FowF3OQufP7SKzrGDvyAFdQMfmT! zxX;ADMExY^ZoE^N>1mJSbo~-k4Qoms7s3U5qHyq+G>WhH4_%I3jEkVjxN+k|>so`6 zLJ!aH4xZ-Nf2$0OW3Oq2s5-0(Y2L{*2KqecCrK z!fFcwlY%8}JNs>ES#}6aL3SSt*V9R21?bWx?C{92w#ik%CAbN?x@~Z~(MybrveH@H z@PJicoi<=Hs#LYy*J5qUNE9XD@S<{XZf1JTT+oCcbqjGd>~~S|k&6}Za69B(m9I_J ze+TwmR$EX~!HoSwB;aBlzGCE(6mv#>{|kJ-Xc_b1%;a0&dF+=liI>M77^a=z6P#3_ zj6SQ!)~~&!8s>WDeNNd0`6dz|uI_0tZjJvv~) z&PQYGSr(VXWG*h7nmz5Z=%-E#c#2&}$S10;b0iq0vmCp9ka-3fKQEVn z6sn9gea{KJ2OaGMXD%E;Za`Z^L{>R!x30HQ?+IMa$m)@yXoI+ejZCJTs?=)Y)naY( zg{mh>sxr4pX8qKBEM(tJJn8>k zH$0@ZTQ{9oIK-*ctZ2wJa}HrznNrRELBlUp{j7l8g?C6f(94jE>f8eD{{5{fC(ITb zj+jTG8)n$5wcVmWb1zgixW4g&8l9<$pLN^78ZPkc1tyllt2nNqVQC(wubO4 zMeF(VoLy&t3gyqA&=?&5Fk%60iG}MNozf)zwMApd`$T;;o^&?k~nm89=!N}!_Gls>Q2lh0(fi?VOBz?IxQ zQ5>Tu+U=r(Mh|N>M8oe}HR>%>sG9s{-6Cz*dCcSRqKB4)iXZwqtPr?`@)$;NH_8v< zLXW#BPy9L0b>^ut&B5_$(xp(+(z;Nzuk(QU3I#By??c}&HvruvzJ`^>q44Q3VPrBi z?fo}YUH?BCUZIep;nwESf@)LwSwFk7TxwP*n2veIe*8xXV*#1h4y}B4HMD4@cleuD z>Ut{h?MPCZwP}+EEI_5c!|n4=RDAq5!3*#}37pR9d+}Mt8s?r57q{Y(@t*wXZLG(+ z74tTdcmJd<*$Xw6iw~YS!GNnI*R-BS4gz2vJ#r-X{kOOO5%Nd!t@lTx{0GYoKGvNX zB0~GgWV$CLBxoL)CVV`10Bz5aoHu`NN_^CQPWtpIQxb_jQpfFg zg)3=A)G*uqq@pBF`h4&xqJ;zvUGM+ew-fUpcS&it)})OF_BfgNL^CFsGUs^-tr(ZE znDe%$ZCUr^)H@n*zNqkgoUGA|)8Z{yV?pEWIZ@xKx)JqlDt~5^d?RcGOatHxweB|R z%;S{T@cc>&9F2(N%x1JfDMx~>j{RdT0T}2Ub^}ztGPR$RvwGW6%IBWr#w~gCi4hV( ze}&O?XupfB;H#wacTOZe+}#F%JO1H9L^Y9;A#n>#EBtEc-VUeEan>KE2&BPRPsO;8lY87U%b}`1-#|GzHpVbejn5|Nj zzikapL<+ZiwA7-NK0f2g%N}uy2F+93A;SxxSkU??gwvuxjI;UoeAvZ{MlcM-z~A9~ zwO_t!)w7_AKtf8VE!LWAVX=LPr+C2!4Kf|_167(UzHGG9)}&kmD%z5%q3HhWL&OQI z0F=IxKFyv9U(|i|Im3M?Hn9o+I)55SncHJkonD8rDDe$F;#!xS=z%n*g@Wp4XV8nh z|EDM2d-vSx7rx_|79**{Ou>k<$(Lzj;1&`b{HyZUk8ubdr)u=iKGv%12r)y`C0q}< z?tSVi4biGqWgYx_R^-zZAH~DY&@!etG!&IOaEy!@k$7Hq5yUIL>7?yS4Xfa_L`WeQ zDYv$tP{628F(FwbmSI&;D5#6N;uIBAC|o<$-NLmZT=}1xVdk3z!V;P*$iQsCO)dsP z`q72g5-;Rz%~%cV2*H4QN4r5?<-CUwSWIK8ei*z_$O)8jxcKExvyY=m6)+n{AtBh# zAXQa{+#%TG+Bc(plOZM_K4j=m69p-TpyAc7MGF$gHClu`gBzA5e{PO|lvrO85)k5A z@P1gs*JT8++2xwV=8unRxfVPF8ld{0VUJMNPl*uW5D9!7hf?WtgF7W2To;<>;X*|! z9v}IUx!kmRG!PudC2&rNkLaHT`F9RKtK?H?v~th>)Bm;rKG9mP%g*>~a|%lCw- z0ASJ;>;ln3SAZ4zanQ{Ztq#r~Ah}htBwwx{BC{^!GhMkNiwV=q@mdMpG^yhJq-G5F9cYLaN1-VY&OwA0K*X zRddj)QxPgNjB(kDVx!PPnxJ1_w*3<8y?~XU9`vVx+J$Eq;Rr=oHA}99Hjfq}B&lEz zM809xxCt9T#*^Wo@03_2aGM+?+#6y=epy!5tSpZ~tLB^ZQ?qdGk&|xl)~m->N!LVc zs5_ndk^`uE8^2LB8N(ip*~QtVomvoi@!~y1Mlx@~noPXCjvc^R_QIHa-hZi9{tB1L zxH(-3c7^L)hs6@egOXIt^oQ@m{s<-U{mKi4n*Y4xd_k^&ATnQhh@XrQ%?NEkRWggr zK6fj4h~&6ciQ=_OqqNf)!ToIN?1>SKq{UGkME%Z8ml|5$uUc>={q5Ggv5Pi`TtNlY}5tRVmNS>%l4o1p&VY>u_7(b{78 zV|f3Zn@R2vl>dIY{p$@X%D#v)#F0py)QYZCNPM=4{mrr5xNAinGSHzc07CiN^|kNb z(j=Ro^gTK)L^LL_l1O+&W5R{u^Ez_`W#F`3WvY6K{S)${mZWj_u*(|lA0jE>#{UO0buUPI+{%-m~29jU~)=r2K=!+qvuhb3KyIh;0 zIlEh9CIg7Eyt~QJ@osZmXPcYjDr<^LQj#zviQM$$D5ZJx=E>nZ6~K8ecJM}t&g^r)*Y0- z>ps6VA>eFcWS+x98{(BD--tlr>&r7caUABB2V~e^YAiA;=uq~s$mW4?^K23wKlpVwuVcPX%_X8&@6r@f6P{;)E9)M9Yqx$&0i z0LwDPi}fdCCZ`2{SlyKhlc98CfKYSaKRJN5S;iPXF8^|22o>{Qjh7%VGJXYB|2sbw zlNmE0?!&4kK1wU;`+C)4A}mE(BD3rm&-rrS;9HsAZEC2{36|+XpHQMcDOdzZ;!ok$ zO9&n_90);jO5oo);e`^foH8?n5e(E-RO^isN52Z`6}m^S@bdGm<37Q?cFXJ_cXR@r1J+=US07iYD@j$Rygk?MBm=H7h8po zC{_=dBW9=c^p<=`V+uCTbwv0>^>Y6m=QbN-h<8!p)|tA&6mK#=g;xg77v}P4XZ`o@ zzo+2h!{83vls4-ohUByG(Gn$BsikJ?=-8TA2lzLrzVdqq+@Vjtum0&@bkhF(yW}a; z1xb-$1v;-w9Ug6twE%*X!xLSZ4c)BU=f2LY0ydH)1-Tj*C-Dk-OR!uXhzNi8mc32R zjP%GO&U4W7!h$19;ch|u9 z;XICpe8e%XRSIZRbv>udfR)>7j}&$5ZHdqR+O@x2l!F>ddCNHGgqrN>=rK-BP$^Vn z3nx))69_5stQbDdVQ}C*OL3@ttMmzxTuq44h7TvZ5~M-x>`0He^Yc_Ds%>C;5NAkp zf>tzZEu ze7;Okb3sfXDG(B+_FE}k`~WqyF^{#s;udx6Ewn{ zNFfu(7M1ip%0B1vXLC-S3=EV&kAqXr4PV)i2!OJOD@qp>4<9--XzlEC-C5+c!Nt%k z!EGEmf^h5xQ{xIEM@flt^QAh*TB<38awS4nqLye?zP^`pSlPx;l}bVL ztVJmxkbD0elUZ?6EXy;%WTgXxhP3U^`+pMGl<@0kJr|=4c_`UUO068c=NMne}`Q4p@f^#r#)H? zyUovLGA5gDINZBo+*LQ{dljXn7d{)VY*#B;{gg%wY*#Lt<#Y=0fR>`g%WAKUOg*BW z2`wG?kV8WfkSTO2Jn8mBT`%4G&!DKKrL~<|R-{9|+7n8-BN#LRvFRIXl}#zSFi(5X zodmNM)E1BMF{?Rd)zRwZ`X1*|`4GhRPTgbOH3oJ6)@CUu<{%~(Xn||2QPo$iUfe2d zSHNo&)RQTfy59)gF}qG7(qGC&p0wa)&{5;_R>y4j@@h(zEpBae-97{TFIA5{@8a== zOyS8e?S)FK?uh1l$M`c@ZBz`GFI(1#0~P97OG%|fk@VXm@*Mm7miIAB7z+~+Dr%~qY{my%_X`f+2Y79MV+C(hkawz$}t z77O7-*(R%oSntKmS~R3tR&(AeI=#I4mCI|MUG(zktdPS=GCim(TSKzmFwmZ`=TiC8 zXbrvw6?%&P-U*rMN&2+!-NtS{=AxW*7xAm1-?_HgGO$5if8#y)p|ZFATJfhUUccUr zYCGPcP{DOGtLgXM*S1GT52^hb+RJT$tI|@SLYe)-CQ6pLi`TF3(Q)YAfBw81Fpg{0 zOQlLJHr(!SFg%Cm!0#y`|=s-UKpcoSu zF})_firN|ZdmAhV_SqGnO_>k8e}?uAHC*^v#eQ|{z)t&Q?JFJ>T(7G+x@56;qF^S^B@Vv(q2`_?BML)zrFg z(ou7;F`;#7;-(WZj+%7$?o63wcr`t)@kvG}-@5~oH* zZrY}H^Z4bBMQ@k2LzjYX04^hc=IE9l6J;I^?*;TlGVK}elbAQ$Wn9i5@0TDHDGSDj zCX;K6hLkUew(*$!Hp?>>?kXZC!eG7I>?=sL_V5*SQdJ8uVM-9T%CEtF`WThPAc&$f zcb_rH|0-2O-sju4VkcRV?8nm&}f> zKYT6qR)}dv;ouXWzo!}-_%Cij`lds)8gmydy7<={;3n-Q5x!f_g;88i zH#L27FX&2>j z_ue^a^5iSTN1FMWdEzA=Gs`reh1iXwSnx`l6 znmA^b2~W+x&$_mS3wUzgjk>zBqQslo-}4I3qbPn)t-OrGYPmwC;QGg!_=4!O17hM# zknKJFFFX{X$7LRR|Djt!X9f@$SzRv!wFI}P)p*c-?B@AvZw^gW-R_pNI;y|o$no+^ z`@%oe0Ic+nw4EK-!S-U7L+(@ejVwa0h!p&pDX3Hb;s4HAtKUykb0|kt$dAxeiY%3i zf6;4czl{itT(M>K?ZLzCTdXAwM;|d%OJ(I{^g|XWqCP$0L{85P$u+S_>~_gzO3XSFk5>3n-@z=it;NT z9lmlQ|MaBZ?PiC9<6YsBXtMpoi`%ES0Ek?q7pbkw$gf{uaulR-sG`-@w_)G^u_un$ zo~-+)BrgS9T(-ZJh1yV4rG;o38{U!BRjLrev6pjnFZ+K8nc@K9>wc!RP42|9XqDeQixZB0qG0bQAyP+hGca z!TYDG+Wvp#IFkyT{TIyp@ZmGxy?^AkLWg{=;*Bt3DK#e?7P+_;et2qjG`}DP3z>Pb8A z*e`W{a6x$Vmy2~nQ7ZgH`BUNW?!=qNMceEnR^6`K9CJ1I--Y#C!e-5Og;~qs=1fDd zau1^IQe{B$w8~ESa^A<5}E$3 zVwYSU6!XH*b8L=%T=lsD;dLvW^E|;#iBk%-8#ip&;Vpz{jw?coDhS%KPI30z*v0){la2H{7t!cwzneFF=7+#5(aWFw%quJmr1SD1&wnUY zFVFp5R0KN<^pc&m*cU1b342|K(7Zz5R?EW@9c0MO)0Hf=iu{-e^M`QYbD=IdRTp5} zx7{DjQy+$&>PSViGetG|75QeGb1LS$=rgb7!lJZ(4!@sx`P9knhdxd? ze|GSW;W=H?A0GQOcAc}&gZTTy{ zz=;k>)P3}DAgn&@>;?*~Nf&h&59riCCP((i+nkx>=3IOvl{7?E$Vq{gi1bA)LgJAx z-9s@%ouT3hZlq!ccW9<%qde_mq$O9Qej_rT5b3WSOW zxPX?z)zh?xKB!wAn+!Cl7*jM)?fZ?k=pSUl#lREW zIBBQd_T%kSSM7bl0kfCF`V8!fB-YZ)o*t$7{&2oU-k5aP^BecG8E^{#w>sK} zo#T6&eg7q-Xtb?Y{5>JIK18apDFG$I*>2EP}Xc;RZ3In;pQKD;2~tB%!c!y&!?`uVHwYojLW+_>3eWY{yOU3ZPZByTUSsqaNx!~5g z$WHk5gqr}%h)--4J}@G;MfCjVAKz`Q|1gpcNF>u6)>*uku|A?SXU}wZEA8bKSGnKY zzvjz+KYH_aJ$h`*G5Jua6Ochxx*_Qqaf`3&j~ZGX`)hCRzKql3dZ3YXEj{Z6P;|34 zzsHuES#ef=@mCl2UHtOGQo!$6So8dRV zH=iPxYEO`VP60mm%RCKOPCX;G1P11BCvuu7aV4mO~FYDf-k@ zz7YAp_}|OSE_Byq_9CfGB{6wc8@>&7R>|#RuqoR=!f(L!Wv?1vit0|J`y&QkjMq~M z_wpd-T3^4Q?>o0Y!XsvAc8Ht3tK4c(fGbm<#T~*%jQ_XLzd!PIG57rZ`Q`TE)*eBw zGedK3ymwR>uX}c{r2e+LE3asxL!t&zL8dd>tOD?7!0R)B`@TN5iNh_bFR-=tkq5m(n`GUa-eK)c#>iC>@GoeO(}Kj7f54{5y5IcmPvvf- z4mgcU_(blc1pNr)hj1?o>F1y&(wfce`|OB{C6`l}%|wwR~|OBUgmUN+63g8MkfWF=&ff1CxX}&<$Y$Y$)R7g<>ae$tlo| zOmD>8gU1i@Kit~8nWy!E!-sd#oc=!75hIePV%)PW;`PttWOVl{j3#&C5n2alJ&klQ zb9wUk@$1Z0!_S(PW-lDM>Q&+{tWsxioN-h2Q*ZHRDFv^L1eI|};HoztxAY+Xkf-7Y zel40zPGE!lQ{YFW#z?Au$+vf>)4-eDuNj07Bt9ER$}6^P+P0b7j5@4sDjF>@daT3u zk$u*zbtlr+xq8_$3SbZc=*tecom@014KdVZ=0~9RNj>Y(2IILPte{<`F9LRz*1CE1 z*hA)y-K!ACnS3{1UK#}`5o%h`%kBMT{)qQ-{A^!WcjVE07r(mN2ITYv$eq%B}S|QW{ASK;* z3UjUH;G938Q?|8p*BDDisJb>}l1MMBh&;9$|901y5pHWYy0=Zga@jJn^@|%5+!HLk z=wz+sr((n~FuUskYbokWS$Hx;Rpy(lxO&`azKe&osvvdrD}7HneRw}SW*$SCBIi!m zJ89)@v3SJ^*DzD&n2O|#iA*L-lou@`QeFIW?jLV76?qXf+RJPG|I9;m$~)~jX3R+^ zEe8@Ri;-m9Me#k=E4%+6N2b|~wA8IO4{YD5lPA?xXZf2P)@AFok{HyxgM}o4n66Bl zhz7{gQfa}reTrb~jCoj9X|Ug+)**|bW3XE!W7wGDl^vn#Gnq-H9geRJF|Z1sjy*#R zqY{KXBEZLKlu8@f!t6si)@7xl86TYzy$e7xi7h$BYyCp(WHO-mY+ePQaP@)t7R!x0 z&zrTFj>eNpCV`QAy5G!CBE^v9CoGAGnZ{5UNmTCOP)!j*%6LlR=FS=37zhzV4=y>< z9P1tDAN9DuEZ$+uhf_xG36B?dp%jHrNArHtDkkYjygLISWHbpNQoD{FJy2YVH5FXz zUBZG1Mx^R@mg*d6ol-_5X3)M;&VjvCn`U;!A~iuv#fGC(#LCn} z+)LGasC0-$pgzdV&)-WkX~Q#+tS72cAA0T@QaBu)7mreQkgaY7#p5d(z|}9d&5Kf z!r#w7+V|AgsX^Xx0kxD8B1Gj(63m)OX#q}C{_23@D-GSTq+(tkAmbz?4w>sh^vG;% zQF5RVa-Qyv*5dlRQ||F^EPY1+8VXpB!?~CG-q}OdeD3KtW)&9>8a=uT+K>?<)&Y~P z{d#|pMP+Z&xp;0wg{UZ&jtG#66Cy$tfEhA?%Sgrr+OTtZMe2e8Ucdb2YH_R28{b%FQUL8kO1&W<5-1zYFKf^>f{i2x^(X_VoIC z4X&M~(eout4cpzAnoL86IX`lUT7VfB)Tqv>)F6q6aB0oQpto;VkTrg|^)5}TY^9nN zfNWn+|N7QLms7%0%)}QFh)m^Mg@qOy|B_i=y#+inf?j zvvcoG`(!Y!6rLg(M&T_?k#pF*O}NG+(TaSYMQi)A$kAdxU$q#cG9|F_h7H3QWl)g# zaKj@5FDd4^DFBLuk{Rd5YWCcaNs ztrb*Kia}mc#Kt+7>W_373f)Ix)>c9rF3#=GQ!V#>Z|DsKIDrHYvX)=G{fw@SOUIBL za}*~-;KoD{&fU6H_3inJEdW81KciSzV5zszAbqJ$+ZXLiW}G;2;^Xy~4?m`!Ex~rc zMKTy3b&4h+S10IFpBnBKhMHevV8wUXP>c-bD&8o>K-d zc%iR@vs6;J%qXGLm62633!K-U?tF@&Q*vdHj~BaO(xbF{={khT95l=i+85Cb_)kV( zT_#fxP-eT+sJ~inDhu&H`Tbmvm3}V{iZH)hw|^qq?L-yOd(a@?dH3_|bc2`@2j5{( z`1p3`c{lznoMDcXL+qOHcRm5*&T2_n>J*;b`0{}CebeS_yQiZZb!gDbr`-qpyQbI- z`C-`S4kbB_%1)|9oHx%to>ZOW94ARJiEc-nR2SR4@S9fHC302a`W087S@&~Z?>$fZ z$i&c`(dTBBufVr>$JWmvwc|gb7f$J7ZR4yz+&XyrR>u20r${-Mysm|A^~RI;m;L$l zmd&8*@87@wnd_)EwENbt*0Q37-zUexRIgijXNEA}<^HE3>~7ICz(Khne$PWQPbAldaAe1osQg=BlKEqELBbpCE(jVjde_;7+e8G z&Sy}o%YEUSxnj%cz;|z&(woU&ogCZ_KK1-;g@vC~I42!vy+8+W;LxFoddfw%3p#b$ z7m{3i{f{)q_4bEdckSGnnVI?WfM=L~`hy3OYb@FKz-T+1Mp+C#Oo}Xcr(UkFa81tf z5Yy!|?kYd1K5{Mp+UtsnmOhh9E~kd+LuI705vw^wt!aWxYkN5>H~9Y}tVe zR+5j8yLbKGKh8r$EXCz>F8QTFqE#C((xO4(9FwgJ1{cg?9u|>|^5gDxC0Az2(@pmH z4WvF5{+~L{SH2WO0EW2Nt>GLz?xYpxjPQ%RphiGK=M0MzEhl-0l71x42HbhQ zNEMYCa#OsFM&F=~u|*D)Sy6k=aMiBm3&fm^B&@iws!xyqyIYQ1J|bY#5!b2zc)b{! zVLWNl+3@fO2cyjbbz$G$7vAg)DAQkjF-3`X<`0wU*(wu0w?-G5`}WSC*`jVmYo`IJ z`DJea*;W_+m_KaO9$w|qZnO%E9oFIF2Cp;v4quLfH; z_B2#i56?R24-3d>qNsU%-qbuIm*cqg+Ie?2_6&xs2qLVW*1~s>cX^Xe`x%;{gpvhJ*gBsHImoNU(T&H3M@C9(4U03?>(7Ni zJj{ziJfW%H;<5d3Cp~p;s&0if-mQO3uK)T~Y__d$*N4b}T`>mDhq92h0SuHmr`#eG zPFJR$qN)--4g#$LjSpzgO1SEb5W*om6GWv z`?NV&YUY=BDJ-mclU+MbDZkp?n!z$N3E7h<7K8M^%5@{>O2nsFo3ndf<~?3Wa*^RHF$NwQg3*9nAu5byQ`ro9@VwC4kItG6MU(8Kc~!A%gqu zwEjJbvzHhVibs8m+BEx^SNNwTrv&Nl!9$03vUXoopQ$7JUPrk^#oJ>ymS;pNdMRVy z5iLPn$HCSOsoSO8t2LX22a6Bf&<}TEOh^)# z@g6Q!?}BgiAkCR@g^+=k-!8_|(IXKn0qh}?;@q!s;|c3>fy1Ft&%jUpWF-4wr*&lmHq+Q`hxj&jZ1RxKaI%drLB23Qke*ug{x73Y3H zeU!*kX3XewYrNMr9w~iysMd+QUPYI(?2Me9hxdq0DcbTX1~r+^@fm!Avl~23W%>y$ z^LX+rwJ&K({KP=IUl2_nbRJp-%)v6t)p@x_Wvqmx0rEQNMkG%4( z`F<$*u!q`-!oMl+_1?6MSuTUQE(C5tg)ai4Zev^zI89N>^+Y>D$tYo)dMY;mtQaOb z^}~bKZMi+5tYaBluo>1p!|cZEybc`QYwoCI4+XlRdF31}ahQ6+nNHpxCa>ZDbamxXp;^;Cxi13KC1 zss+8VcNo!?>d1ATOHjdE*80jGbDw$G?p*u6e}@&D1 zTEm$$M;h1a1e$sYdWZd9w2~;Oxr%OF|1YS;>B7#VSNqcz!IDMk52bR~JnUWi+>wpI z>GsWa{C?Z^QHu=?8#4S12vyRgjE7IJZ3{ZZ`Ng^48suscZy!kFhL)!_*TL810xAi32w#hCfrX_9e+Tct) z$hZxZ5J{1#bXjG+lvUbsRKpKXqOFdKJTK8;%t)}h?RcoWjV!5&XJ2mUlJT*?^zkgv zbbbsga{`411PFkSx_XmbAFR!S%*x1d)K_<~)2;tnWu0w3YY@3Ml7B+~Xcsjun*0my zG?rUiu+tPgvW{*Kd1~vKFM^l$al2kFEz+;B_7hCwnI;L$(C?@dr()LAr+>dY*Yb>4 z=XuV%GgcVV*~HyF(RzaZxU0`3s8Ghver4eNe*6Yj1r5)BHIAHXc-E}vh!L?FX$y`r z)c*CMPycH<3u}Hw&h1Y|{>}RVBphk-d5SI_&a%^`Sh-bJ|53{_vJ(#s8Oi3s7hiqt zUfF|^Qk+RhY1Mor>owC(_gr$&M}cDK<|Ubskvo!GB3*{d&Q_CZ`y8Lqg!lOOn@=Np z#NAeXhn|jxPVCO89(RLHH@tq!t}M&A$D6$ao}S+J_Ma|%3h{JP3(852<3Q&6B9p#r z6Fus6g}IhWLjFECjjPX;F@FxVke@p@#E6+c0-9m+%Ly48qUD79p?vnh)!Q4%#& zh`1KQPcqNlHeWcte8K$4xmKEm4CJB$={*)FL%%C~-gUoE2pxt5NN-k=$1bte8u#)^`?rUz78Brb$krDjX$-ze+( zbLB)UKXU%P;udq!d0OweR@myR{^QO4DCe|2jQkj#U<4y0Y)Zb=WDr9B#RBvG%oV9M>@ox96 zdWLki80+-&p1VeH76Vf>xkwqi*n8Bdr+;`Iy|7L6MUv@H;mgX;iqCw!cooNwW#rp8 za>GPW~`e^_;L^!SQ7Gqj5Gms$xR|ruMpZbcC+% z8MYa3A@R-dgfE&_`bU?aH4i&urgi7a08VahqABi4rhAt!5L6SwZs~$fziOBK@?dUz z(WjN7JsIV2baGmbiE(zNV{ z_ZL4)DnJWuYh5)NmIJBiKWf^=kwaCLh0B#u+RPPVDC3cjEzj#+{IAe?^WpEQ)Ua6{ zw!Wt5jgX-S!^xJK!DIWe()h7Is z1k3w{K8y6Li&*GqZ`|m@8Ol{bZ;7Hf*f86)R2VEF2y)7*p4$2qhlQRh_i@Rv7|F4N zPihi(<6!L)ECJ2Q_Tz67X=h}6rSk;>++3zKxHkAqi#Ba4tEVm9oprCEyQlRT&YA4& z2AogcMoE2NS-CZR(*N0-5#k<{xfN`U{Sc`lqYjzf(xNL3J`iBS)Bf(9w53jZgl66a z>fm!5wRoUAV#LIVT)o%ldL3Opi+x0qfE0e-sQddhi+nH7A7IB4oE*F(#b$?vcF2Zg z(^Q~WI;1q%TiiNp|#Ih z#vv-Y4gDu_u8gTI=vw!7V-u5v#aa3JE#Tb1H^?-VOJmtky_02qc$wT4_Xa+21NNpp zm~i;=zS&wTnPpB!>1|Ju49ks<5SebGbzsSI)h6^#JnM?;+ICc#;FCb{hQK3x{B%dD znk2YT#_|@akyrpa$_=T|S$Xr~cWtnw@)o7it#5C;f|}US|GR!K3w5vW*1@?YcQBX{ znH);VI=rdH+D}>gtTCDG#@Ry!i(ik#5jf~(ys{6z$9|xnAxl7sN$`6Z;$SDq8AZ5M7BHNP>R_9Q>?qho-s!R&h}Ew*J@ts8|k z%wMko1NLtmYxk;e@`|f5T~4i7(COpHkM!L9bFD>(Hh3c?4ex(S9+_)1rtYcjB|VEL ztB=pn6ygA8vVOji(LIw0_nCou9^l$y3L+lKCa&AFv?~LCR{L!e(pz{M0rtNkaaJ8-hlLpQF(?Dx$NSk6<3w6 zk6nVtP^?M$!`>=+TCd~c+l(|(+-Hmhpbhmvc9s2Mh3Wp~3$T9^9ic@13%_y)A8j;f zgus!oIR@PuChG_tC?QY;Z99J3LLEkx`0?PYZfr7+SIxuCS$aFWf45z!Yl&G<<2z&j8V~Ph88xLM5KpE%^0rnk-IQIxbI4n=)Ug z^{>&GrX?;4BbJGOhq38bG#I@fub2MM2Z}x0qHh?C9>77J{miHKx>xi=nZd| z{`~h_;Ml{Kp*f&pva<@~=g6rZ8{3I5U0htOTfDKGNkZb0TzikZOJ90M&~ow3jd~Y* zMkFRAls=Dc$WbhLH-eJ0b9+IqK-L*|-?ZB`rBC?^el5R34jDPt^tv6Jp(*|*S7uDC zy^(T%&4{>Xf6QW3HU~^;X{qDF=jU?D%$6)^b98yT?%hqj{?hl;w3=r-^tkNQoU-dF z8h2_xIng&_X1M0{z9)|eGtV7y!_J-CghE59VUwlz_Ow&gbJ9xuqxXA8n=GUMR}ILsF6X~CH58;ce}N!BJWoneF=@rEz??8dN#(Z^ACUop*hpno_FW2w0LxR z@W=Qee-v!X<&VPB69#=hF{EEZXCInEU}QwCKD@o;WkcmH@O!W0xq?_V@@k@AOv3aI zl1H;T{-eG;#sqm((D6vbE&zo<3t<-d#T8Ttj<^4WS)_(6`@ZuOr`;RZ0qIHn zR6E^2{kpoR<0h==d-LYa4TH5U(l`jkPKXO&BF=PG&mC0B%uU(T%g}QvMg*q{V|_Nc zBmmI3z)B>`VL-0RjDQi5vwuBWaa9T?$~8o6T$>@meSIOVQ^qMLL-MZo>)K&h`W4O- zs(FX@SNYM4mv8FIc?FOp;iPnm6s7+UV+~#O^1R!^nJ$wWHCkQTMyho-SBLUC;#v-x%O{51u630 zo$T9wYQXC?+g@~Jg0_g2rH&`w=S$*Va(KIeO!4nX_BKMGw5 z$s5dpOX;Vh=A%$>ogqpfJZ4YPx=(4%zaKv17TMK3Aud@*+5cF^iec0!yr%)3(g#NM zJ2>UKS3tnRD7{brFyxLibL5=W)CzLVN_z3XAJ%RwiH(BFrmx(PocnOpvMuQIa3~*u zCxcB!2q(cIb}{)QZpZOFO_QtI{#a!;=+UiX6{aZ@<{y3ImcdJ;_Tqnc+UL=K)TgwH zqGM-%eO(uOB$yC$@vK4RXT2?njEodgof;n-_zt=z1@RdZQ5jNrv}KImv17+fBV(P3 zf_U?|UIL+fKz3^wZr8uf>b#;#%}Jfq?ayE6o^)k^|FI7SrCob`_)%7P>==ySJ)89b zUjkP-K4c00kG9sUnf5%=)O`R;+VX)3lt_6jY=)544U$?L~ zOPK6+;*ao901QXF_+SHrh};K#S8*@~XZ;y{`^l(wuU1`Hk0`OOn}|mA}?MR8x$6o^fSBUMz`3-Q&KyxF{bk_`ljZ`=BVR zFp9qoevC5-qb+9YVmc@|mO>*I$PR+6iY2&;W_(O2BjHfED61rfi75i*6v@~aI4zLi zn1*8t28jek!e}HAnDVhOfQz__8m!7fzi0V3hQF9y_I>ZZ_uliIbDncEz3}(6KJkVl z2@lU?>apbL)1Ur+Q1j`%@26nR%LGo$;anYvV{L3~Y}tLVlO^UZP6n;))jq1n)GnR~ z<iZppIXQ3bz6bE3C2peR)hzmwaVj}*xS|6H9%5N2m%Wx~Q zRkNK}<3vkZ<{M&A^X0e`#^Q3(Hc+$ww%_iq9OEY>pN&qqI`4z$5tlRxx08D)i1?-N zl6=?eH9q+u7G@xTrigRwBO}!m9i^rH1K_U}u2bc(Z?rjB=0K(g8%1%_z*gx!RnO=F zJ+gF_S^m#`q12zU&1|n|HN@|0BhlgraHI=j#8N-hDO)C<6*T8N#@-Fp^~RWtymR+% zm|`Ji?nex^S!esjg!H_b(gs8|A8IdM{Cv}nZEw87K?QQ$gfbfZY_NnIpbR6;b|p+t zSXh`?QRzqow}IAASM91BYysmTiFk6Zo+1wO<_0vY^5{op13nWD8e6kF{?rW3nlO1r zqpA8Hy$KW_fFB^cN^4k_{Ge&d}zAiMh(Y(~{ zoo^HhUVE2<93uiNE>9cMBqpc6hXyEETn&bXUZzIjU>4F6EK{QOsmdFplB&D0|C%j0 z=nCG%neik|AV{aN7vnqgH1st(UNm&+&ujiVaXp57_-N9Rtaa~?NNPp zM$|+CLOVm4mwenNdHBee2KPlB&zeI@9K9!=NLrAwa}pQ}pj~>VYlMZ_?k8~2+mf!3 z9-%ZR-)0~|lH-*41ZM?8CjhrFjTVyDuLz8%Ov4q_wf7oMm35~>*PUtF{L5ZLT69C~ z67rkwKWbj-?HC!M)g62LTd%ljmp;7JnK*v!NGyGdf7I3nP%*Af3utYd)O+iT5S^;Y z0iBHo`=GRhW+<2V%h?&7FWWD2JK6)w5@KcKg$KW#vVzGn@*@6$LeQIj9e;Dno$T<9 zOY*Jh_CJU1xH~|r@-%3(d9cO)_Q8BaK(3e;J$~-T7%?5`!0b`vn3sM$&;9t2RMnI< z1yy&&FIDI}@zzFM!MbC0$(`wL(%O)PwE!WnF1xNE$3dQf%f4g5l<@Yl1xO$l8pM~5 z2m8j!1?MSZXT-cRU%j$Wawl-FVn-=hVe~m5*XSPMH@ju5+jFjZP1@P_E*xIy7v$|^ zfA7dPYSld0ZhH3c zX!@wQam!R0H=U$-q@v$VXTsNn_}Kzo1vF#7m-=d&4OcIpF;Vjx0F&ojhB8@i-PS z9FgnuOB>7_zBVm2c8RvO8pPC{S~GF diff --git a/examples/Makefile.am b/examples/Makefile.am deleted file mode 100644 index fa47e5e..0000000 --- a/examples/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2006, 2007 Collabora Ltd. -# (C) 2006, 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. - -include $(top_srcdir)/common.mk - -AM_CFLAGS = \ - -I $(top_srcdir) \ - -I $(top_srcdir)/agent \ - -I $(top_srcdir)/random \ - -I $(top_srcdir)/socket \ - -I $(top_srcdir)/stun \ - $(LIBNICE_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(GUPNP_CFLAGS) - -noinst_PROGRAMS = simple-example threaded-example sdp-example - -simple_example_SOURCES = simple-example.c -simple_example_LDADD = $(top_builddir)/agent/libagent.la \ - $(GLIB_LIBS) $(GUPNP_LIBS) - -threaded_example_SOURCES = threaded-example.c -threaded_example_LDADD = $(top_builddir)/agent/libagent.la \ - $(GLIB_LIBS) $(GUPNP_LIBS) - -sdp_example_SOURCES = sdp-example.c -sdp_example_LDADD = $(top_builddir)/agent/libagent.la \ - $(GLIB_LIBS) $(GUPNP_LIBS) - -EXTRA_DIST = meson.build diff --git a/examples/meson.build b/examples/meson.build deleted file mode 100644 index e0d0a00..0000000 --- a/examples/meson.build +++ /dev/null @@ -1,8 +0,0 @@ -examples = ['simple-example', 'threaded-example', 'sdp-example'] - -foreach ex : examples - executable(ex, '@0@.c'.format(ex), - include_directories: nice_incs, - dependencies: gio_deps + [libnice_dep, gupnp_igd_dep], - install: false) -endforeach diff --git a/examples/sdp-example.c b/examples/sdp-example.c deleted file mode 100644 index b6dd80a..0000000 --- a/examples/sdp-example.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright 2013 University of Chicago - * Contact: Bryce Allen - * Copyright 2013 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * Example using libnice to negotiate a UDP connection between two clients, - * possibly on the same network or behind different NATs and/or stateful - * firewalls. - * - * Build: - * gcc -o sdp-example sdp-example.c `pkg-config --cflags --libs nice` - * - * Run two clients, one controlling and one controlled: - * sdp-example 0 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }') - * sdp-example 1 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }') - */ -#include -#include -#include -#include - -#include - -#include - -static GMainLoop *gloop; -static gchar *stun_addr = NULL; -static guint stun_port; -static gboolean controlling; -static gboolean exit_thread, candidate_gathering_done, negotiation_done; -static GMutex gather_mutex, negotiate_mutex; -static GCond gather_cond, negotiate_cond; - -static const gchar *state_name[] = {"disconnected", "gathering", "connecting", - "connected", "ready", "failed"}; - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, - gpointer data); -static void cb_component_state_changed(NiceAgent *agent, guint stream_id, - guint component_id, guint state, - gpointer data); -static void cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id, - guint len, gchar *buf, gpointer data); - -static void * example_thread(void *data); - -int -main(int argc, char *argv[]) -{ - GThread *gexamplethread; - - // Parse arguments - if (argc > 4 || argc < 2 || argv[1][1] != '\0') { - fprintf(stderr, "Usage: %s 0|1 stun_addr [stun_port]\n", argv[0]); - return EXIT_FAILURE; - } - controlling = argv[1][0] - '0'; - if (controlling != 0 && controlling != 1) { - fprintf(stderr, "Usage: %s 0|1 stun_addr [stun_port]\n", argv[0]); - return EXIT_FAILURE; - } - - if (argc > 2) { - stun_addr = argv[2]; - if (argc > 3) - stun_port = atoi(argv[3]); - else - stun_port = 3478; - - g_debug("Using stun server '[%s]:%u'\n", stun_addr, stun_port); - } - - g_networking_init(); - - gloop = g_main_loop_new(NULL, FALSE); - - // Run the mainloop and the example thread - exit_thread = FALSE; - gexamplethread = g_thread_new("example thread", &example_thread, NULL); - g_main_loop_run (gloop); - exit_thread = TRUE; - - g_thread_join (gexamplethread); - g_main_loop_unref(gloop); - - return EXIT_SUCCESS; -} - -static void * -example_thread(void *data) -{ - NiceAgent *agent; - GIOChannel* io_stdin; - guint stream_id; - gchar *line = NULL; - gchar *sdp, *sdp64; - -#ifdef G_OS_WIN32 - io_stdin = g_io_channel_win32_new_fd(_fileno(stdin)); -#else - io_stdin = g_io_channel_unix_new(fileno(stdin)); -#endif - g_io_channel_set_flags(io_stdin, G_IO_FLAG_NONBLOCK, NULL); - - // Create the nice agent - agent = nice_agent_new(g_main_loop_get_context (gloop), - NICE_COMPATIBILITY_RFC5245); - if (agent == NULL) - g_error("Failed to create agent"); - - // Set the STUN settings and controlling mode - if (stun_addr) { - g_object_set(agent, "stun-server", stun_addr, NULL); - g_object_set(agent, "stun-server-port", stun_port, NULL); - } - g_object_set(agent, "controlling-mode", controlling, NULL); - - // Connect to the signals - g_signal_connect(agent, "candidate-gathering-done", - G_CALLBACK(cb_candidate_gathering_done), NULL); - g_signal_connect(agent, "component-state-changed", - G_CALLBACK(cb_component_state_changed), NULL); - - // Create a new stream with one component - stream_id = nice_agent_add_stream(agent, 1); - if (stream_id == 0) - g_error("Failed to add stream"); - nice_agent_set_stream_name (agent, stream_id, "text"); - - // Attach to the component to receive the data - // Without this call, candidates cannot be gathered - nice_agent_attach_recv(agent, stream_id, 1, - g_main_loop_get_context (gloop), cb_nice_recv, NULL); - - // Start gathering local candidates - if (!nice_agent_gather_candidates(agent, stream_id)) - g_error("Failed to start candidate gathering"); - - g_debug("waiting for candidate-gathering-done signal..."); - - g_mutex_lock(&gather_mutex); - while (!exit_thread && !candidate_gathering_done) - g_cond_wait(&gather_cond, &gather_mutex); - g_mutex_unlock(&gather_mutex); - if (exit_thread) - goto end; - - // Candidate gathering is done. Send our local candidates on stdout - sdp = nice_agent_generate_local_sdp (agent); - printf("Generated SDP from agent :\n%s\n\n", sdp); - printf("Copy the following line to remote client:\n"); - sdp64 = g_base64_encode ((const guchar *)sdp, strlen (sdp)); - printf("\n %s\n", sdp64); - g_free (sdp); - g_free (sdp64); - - // Listen on stdin for the remote candidate list - printf("Enter remote data (single line, no wrapping):\n"); - printf("> "); - fflush (stdout); - while (!exit_thread) { - GIOStatus s = g_io_channel_read_line (io_stdin, &line, NULL, NULL, NULL); - if (s == G_IO_STATUS_NORMAL) { - gsize sdp_len; - - sdp = (gchar *) g_base64_decode (line, &sdp_len); - // Parse remote candidate list and set it on the agent - if (sdp && nice_agent_parse_remote_sdp (agent, sdp) > 0) { - g_free (sdp); - g_free (line); - break; - } else { - fprintf(stderr, "ERROR: failed to parse remote data\n"); - printf("Enter remote data (single line, no wrapping):\n"); - printf("> "); - fflush (stdout); - } - g_free (sdp); - g_free (line); - } else if (s == G_IO_STATUS_AGAIN) { - g_usleep (100000); - } - } - - g_debug("waiting for state READY or FAILED signal..."); - g_mutex_lock(&negotiate_mutex); - while (!exit_thread && !negotiation_done) - g_cond_wait(&negotiate_cond, &negotiate_mutex); - g_mutex_unlock(&negotiate_mutex); - if (exit_thread) - goto end; - - // Listen to stdin and send data written to it - printf("\nSend lines to remote (Ctrl-D to quit):\n"); - printf("> "); - fflush (stdout); - while (!exit_thread) { - GIOStatus s = g_io_channel_read_line (io_stdin, &line, NULL, NULL, NULL); - - if (s == G_IO_STATUS_NORMAL) { - nice_agent_send(agent, stream_id, 1, strlen(line), line); - g_free (line); - printf("> "); - fflush (stdout); - } else if (s == G_IO_STATUS_AGAIN) { - g_usleep (100000); - } else { - // Ctrl-D was pressed. - nice_agent_send(agent, stream_id, 1, 1, "\0"); - break; - } - } - -end: - g_object_unref(agent); - g_io_channel_unref (io_stdin); - g_main_loop_quit (gloop); - - return NULL; -} - -static void -cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, - gpointer data) -{ - g_debug("SIGNAL candidate gathering done\n"); - - g_mutex_lock(&gather_mutex); - candidate_gathering_done = TRUE; - g_cond_signal(&gather_cond); - g_mutex_unlock(&gather_mutex); -} - -static void -cb_component_state_changed(NiceAgent *agent, guint stream_id, - guint component_id, guint state, - gpointer data) -{ - g_debug("SIGNAL: state changed %d %d %s[%d]\n", - stream_id, component_id, state_name[state], state); - - if (state == NICE_COMPONENT_STATE_READY) { - g_mutex_lock(&negotiate_mutex); - negotiation_done = TRUE; - g_cond_signal(&negotiate_cond); - g_mutex_unlock(&negotiate_mutex); - } else if (state == NICE_COMPONENT_STATE_FAILED) { - g_main_loop_quit (gloop); - } -} - -static void -cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id, - guint len, gchar *buf, gpointer data) -{ - if (len == 1 && buf[0] == '\0') - g_main_loop_quit (gloop); - - printf("%.*s", len, buf); - fflush(stdout); -} diff --git a/examples/simple-example.c b/examples/simple-example.c deleted file mode 100644 index b4da1e2..0000000 --- a/examples/simple-example.c +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright 2013 University of Chicago - * Contact: Bryce Allen - * Copyright 2013 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * Example using libnice to negotiate a UDP connection between two clients, - * possibly on the same network or behind different NATs and/or stateful - * firewalls. - * - * Build: - * gcc -o simple-example simple-example.c `pkg-config --cflags --libs nice` - * - * Run two clients, one controlling and one controlled: - * simple-example 0 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }') - * simple-example 1 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }') - */ -#include -#include -#include -#include - -#include - -#include - -static GMainLoop *gloop; -static GIOChannel* io_stdin; -static guint stream_id; - -static const gchar *candidate_type_name[] = {"host", "srflx", "prflx", "relay"}; - -static const gchar *state_name[] = {"disconnected", "gathering", "connecting", - "connected", "ready", "failed"}; - -static int print_local_data(NiceAgent *agent, guint stream_id, - guint component_id); -static int parse_remote_data(NiceAgent *agent, guint stream_id, - guint component_id, char *line); -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, - gpointer data); -static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, - guint component_id, gchar *lfoundation, - gchar *rfoundation, gpointer data); -static void cb_component_state_changed(NiceAgent *agent, guint stream_id, - guint component_id, guint state, - gpointer data); -static void cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id, - guint len, gchar *buf, gpointer data); -static gboolean stdin_remote_info_cb (GIOChannel *source, GIOCondition cond, - gpointer data); -static gboolean stdin_send_data_cb (GIOChannel *source, GIOCondition cond, - gpointer data); - -int -main(int argc, char *argv[]) -{ - NiceAgent *agent; - gchar *stun_addr = NULL; - guint stun_port = 0; - gboolean controlling; - - // Parse arguments - if (argc > 4 || argc < 2 || argv[1][1] != '\0') { - fprintf(stderr, "Usage: %s 0|1 stun_addr [stun_port]\n", argv[0]); - return EXIT_FAILURE; - } - controlling = argv[1][0] - '0'; - if (controlling != 0 && controlling != 1) { - fprintf(stderr, "Usage: %s 0|1 stun_addr [stun_port]\n", argv[0]); - return EXIT_FAILURE; - } - - if (argc > 2) { - stun_addr = argv[2]; - if (argc > 3) - stun_port = atoi(argv[3]); - else - stun_port = 3478; - - g_debug("Using stun server '[%s]:%u'\n", stun_addr, stun_port); - } - - g_networking_init(); - - gloop = g_main_loop_new(NULL, FALSE); -#ifdef G_OS_WIN32 - io_stdin = g_io_channel_win32_new_fd(_fileno(stdin)); -#else - io_stdin = g_io_channel_unix_new(fileno(stdin)); -#endif - - // Create the nice agent - agent = nice_agent_new(g_main_loop_get_context (gloop), - NICE_COMPATIBILITY_RFC5245); - if (agent == NULL) - g_error("Failed to create agent"); - - // Set the STUN settings and controlling mode - if (stun_addr) { - g_object_set(agent, "stun-server", stun_addr, NULL); - g_object_set(agent, "stun-server-port", stun_port, NULL); - } - g_object_set(agent, "controlling-mode", controlling, NULL); - - // Connect to the signals - g_signal_connect(agent, "candidate-gathering-done", - G_CALLBACK(cb_candidate_gathering_done), NULL); - g_signal_connect(agent, "new-selected-pair", - G_CALLBACK(cb_new_selected_pair), NULL); - g_signal_connect(agent, "component-state-changed", - G_CALLBACK(cb_component_state_changed), NULL); - - // Create a new stream with one component - stream_id = nice_agent_add_stream(agent, 1); - if (stream_id == 0) - g_error("Failed to add stream"); - - // Attach to the component to receive the data - // Without this call, candidates cannot be gathered - nice_agent_attach_recv(agent, stream_id, 1, - g_main_loop_get_context (gloop), cb_nice_recv, NULL); - - // Start gathering local candidates - if (!nice_agent_gather_candidates(agent, stream_id)) - g_error("Failed to start candidate gathering"); - - g_debug("waiting for candidate-gathering-done signal..."); - - // Run the mainloop. Everything else will happen asynchronously - // when the candidates are done gathering. - g_main_loop_run (gloop); - - g_main_loop_unref(gloop); - g_object_unref(agent); - g_io_channel_unref (io_stdin); - - return EXIT_SUCCESS; -} - -static void -cb_candidate_gathering_done(NiceAgent *agent, guint _stream_id, - gpointer data) -{ - - g_debug("SIGNAL candidate gathering done\n"); - - // Candidate gathering is done. Send our local candidates on stdout - printf("Copy this line to remote client:\n"); - printf("\n "); - print_local_data(agent, _stream_id, 1); - printf("\n"); - - // Listen on stdin for the remote candidate list - printf("Enter remote data (single line, no wrapping):\n"); - g_io_add_watch(io_stdin, G_IO_IN, stdin_remote_info_cb, agent); - printf("> "); - fflush (stdout); -} - -static gboolean -stdin_remote_info_cb (GIOChannel *source, GIOCondition cond, - gpointer data) -{ - NiceAgent *agent = data; - gchar *line = NULL; - int rval; - gboolean ret = TRUE; - - if (g_io_channel_read_line (source, &line, NULL, NULL, NULL) == - G_IO_STATUS_NORMAL) { - - // Parse remote candidate list and set it on the agent - rval = parse_remote_data(agent, stream_id, 1, line); - if (rval == EXIT_SUCCESS) { - // Return FALSE so we stop listening to stdin since we parsed the - // candidates correctly - ret = FALSE; - g_debug("waiting for state READY or FAILED signal..."); - } else { - fprintf(stderr, "ERROR: failed to parse remote data\n"); - printf("Enter remote data (single line, no wrapping):\n"); - printf("> "); - fflush (stdout); - } - g_free (line); - } - - return ret; -} - -static void -cb_component_state_changed(NiceAgent *agent, guint _stream_id, - guint component_id, guint state, - gpointer data) -{ - - g_debug("SIGNAL: state changed %d %d %s[%d]\n", - _stream_id, component_id, state_name[state], state); - - if (state == NICE_COMPONENT_STATE_CONNECTED) { - NiceCandidate *local, *remote; - - // Get current selected candidate pair and print IP address used - if (nice_agent_get_selected_pair (agent, _stream_id, component_id, - &local, &remote)) { - gchar ipaddr[INET6_ADDRSTRLEN]; - - nice_address_to_string(&local->addr, ipaddr); - printf("\nNegotiation complete: ([%s]:%d,", - ipaddr, nice_address_get_port(&local->addr)); - nice_address_to_string(&remote->addr, ipaddr); - printf(" [%s]:%d)\n", ipaddr, nice_address_get_port(&remote->addr)); - } - - // Listen to stdin and send data written to it - printf("\nSend lines to remote (Ctrl-D to quit):\n"); - g_io_add_watch(io_stdin, G_IO_IN, stdin_send_data_cb, agent); - printf("> "); - fflush (stdout); - } else if (state == NICE_COMPONENT_STATE_FAILED) { - g_main_loop_quit (gloop); - } -} - -static gboolean -stdin_send_data_cb (GIOChannel *source, GIOCondition cond, - gpointer data) -{ - NiceAgent *agent = data; - gchar *line = NULL; - - if (g_io_channel_read_line (source, &line, NULL, NULL, NULL) == - G_IO_STATUS_NORMAL) { - nice_agent_send(agent, stream_id, 1, strlen(line), line); - g_free (line); - printf("> "); - fflush (stdout); - } else { - nice_agent_send(agent, stream_id, 1, 1, "\0"); - // Ctrl-D was pressed. - g_main_loop_quit (gloop); - } - - return TRUE; -} - -static void -cb_new_selected_pair(NiceAgent *agent, guint _stream_id, - guint component_id, gchar *lfoundation, - gchar *rfoundation, gpointer data) -{ - g_debug("SIGNAL: selected pair %s %s", lfoundation, rfoundation); -} - -static void -cb_nice_recv(NiceAgent *agent, guint _stream_id, guint component_id, - guint len, gchar *buf, gpointer data) -{ - if (len == 1 && buf[0] == '\0') - g_main_loop_quit (gloop); - printf("%.*s", len, buf); - fflush(stdout); -} - -static NiceCandidate * -parse_candidate(char *scand, guint _stream_id) -{ - NiceCandidate *cand = NULL; - NiceCandidateType ntype = NICE_CANDIDATE_TYPE_HOST; - gchar **tokens = NULL; - guint i; - - tokens = g_strsplit (scand, ",", 5); - for (i = 0; tokens[i]; i++); - if (i != 5) - goto end; - - for (i = 0; i < G_N_ELEMENTS (candidate_type_name); i++) { - if (strcmp(tokens[4], candidate_type_name[i]) == 0) { - ntype = i; - break; - } - } - if (i == G_N_ELEMENTS (candidate_type_name)) - goto end; - - cand = nice_candidate_new(ntype); - cand->component_id = 1; - cand->stream_id = _stream_id; - cand->transport = NICE_CANDIDATE_TRANSPORT_UDP; - strncpy(cand->foundation, tokens[0], NICE_CANDIDATE_MAX_FOUNDATION - 1); - cand->foundation[NICE_CANDIDATE_MAX_FOUNDATION - 1] = 0; - cand->priority = atoi (tokens[1]); - - if (!nice_address_set_from_string(&cand->addr, tokens[2])) { - g_message("failed to parse addr: %s", tokens[2]); - nice_candidate_free(cand); - cand = NULL; - goto end; - } - - nice_address_set_port(&cand->addr, atoi (tokens[3])); - - end: - g_strfreev(tokens); - - return cand; -} - - -static int -print_local_data (NiceAgent *agent, guint _stream_id, guint component_id) -{ - int result = EXIT_FAILURE; - gchar *local_ufrag = NULL; - gchar *local_password = NULL; - gchar ipaddr[INET6_ADDRSTRLEN]; - GSList *cands = NULL, *item; - - if (!nice_agent_get_local_credentials(agent, _stream_id, - &local_ufrag, &local_password)) - goto end; - - cands = nice_agent_get_local_candidates(agent, _stream_id, component_id); - if (cands == NULL) - goto end; - - printf("%s %s", local_ufrag, local_password); - - for (item = cands; item; item = item->next) { - NiceCandidate *c = (NiceCandidate *)item->data; - - nice_address_to_string(&c->addr, ipaddr); - - // (foundation),(prio),(addr),(port),(type) - printf(" %s,%u,%s,%u,%s", - c->foundation, - c->priority, - ipaddr, - nice_address_get_port(&c->addr), - candidate_type_name[c->type]); - } - printf("\n"); - result = EXIT_SUCCESS; - - end: - if (local_ufrag) - g_free(local_ufrag); - if (local_password) - g_free(local_password); - if (cands) - g_slist_free_full(cands, (GDestroyNotify)&nice_candidate_free); - - return result; -} - - -static int -parse_remote_data(NiceAgent *agent, guint _stream_id, - guint component_id, char *line) -{ - GSList *remote_candidates = NULL; - gchar **line_argv = NULL; - const gchar *ufrag = NULL; - const gchar *passwd = NULL; - int result = EXIT_FAILURE; - int i; - - line_argv = g_strsplit_set (line, " \t\n", 0); - for (i = 0; line_argv && line_argv[i]; i++) { - if (strlen (line_argv[i]) == 0) - continue; - - // first two args are remote ufrag and password - if (!ufrag) { - ufrag = line_argv[i]; - } else if (!passwd) { - passwd = line_argv[i]; - } else { - // Remaining args are serialized canidates (at least one is required) - NiceCandidate *c = parse_candidate(line_argv[i], _stream_id); - - if (c == NULL) { - g_message("failed to parse candidate: %s", line_argv[i]); - goto end; - } - remote_candidates = g_slist_prepend(remote_candidates, c); - } - } - if (ufrag == NULL || passwd == NULL || remote_candidates == NULL) { - g_message("line must have at least ufrag, password, and one candidate"); - goto end; - } - - if (!nice_agent_set_remote_credentials(agent, _stream_id, ufrag, passwd)) { - g_message("failed to set remote credentials"); - goto end; - } - - // Note: this will trigger the start of negotiation. - if (nice_agent_set_remote_candidates(agent, _stream_id, component_id, - remote_candidates) < 1) { - g_message("failed to set remote candidates"); - goto end; - } - - result = EXIT_SUCCESS; - - end: - if (line_argv != NULL) - g_strfreev(line_argv); - if (remote_candidates != NULL) - g_slist_free_full(remote_candidates, (GDestroyNotify)&nice_candidate_free); - - return result; -} diff --git a/examples/threaded-example.c b/examples/threaded-example.c deleted file mode 100644 index 6df6ac2..0000000 --- a/examples/threaded-example.c +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright 2013 University of Chicago - * Contact: Bryce Allen - * Copyright 2013 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * Example using libnice to negotiate a UDP connection between two clients, - * possibly on the same network or behind different NATs and/or stateful - * firewalls. - * - * Build: - * gcc -o threaded-example threaded-example.c `pkg-config --cflags --libs nice` - * - * Run two clients, one controlling and one controlled: - * threaded-example 0 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }') - * threaded-example 1 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }') - */ -#include -#include -#include -#include - -#include - -#include - -static GMainLoop *gloop; -static gchar *stun_addr = NULL; -static guint stun_port; -static gboolean controlling; -static gboolean exit_thread, candidate_gathering_done, negotiation_done; -static GMutex gather_mutex, negotiate_mutex; -static GCond gather_cond, negotiate_cond; - -static const gchar *candidate_type_name[] = {"host", "srflx", "prflx", "relay"}; - -static const gchar *state_name[] = {"disconnected", "gathering", "connecting", - "connected", "ready", "failed"}; - -static int print_local_data(NiceAgent *agent, guint stream_id, - guint component_id); -static int parse_remote_data(NiceAgent *agent, guint stream_id, - guint component_id, char *line); -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, - gpointer data); -static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, - guint component_id, gchar *lfoundation, - gchar *rfoundation, gpointer data); -static void cb_component_state_changed(NiceAgent *agent, guint stream_id, - guint component_id, guint state, - gpointer data); -static void cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id, - guint len, gchar *buf, gpointer data); - -static void * example_thread(void *data); - -int -main(int argc, char *argv[]) -{ - GThread *gexamplethread; - - // Parse arguments - if (argc > 4 || argc < 2 || argv[1][1] != '\0') { - fprintf(stderr, "Usage: %s 0|1 stun_addr [stun_port]\n", argv[0]); - return EXIT_FAILURE; - } - controlling = argv[1][0] - '0'; - if (controlling != 0 && controlling != 1) { - fprintf(stderr, "Usage: %s 0|1 stun_addr [stun_port]\n", argv[0]); - return EXIT_FAILURE; - } - - if (argc > 2) { - stun_addr = argv[2]; - if (argc > 3) - stun_port = atoi(argv[3]); - else - stun_port = 3478; - - g_debug("Using stun server '[%s]:%u'\n", stun_addr, stun_port); - } - - g_networking_init(); - - gloop = g_main_loop_new(NULL, FALSE); - - // Run the mainloop and the example thread - exit_thread = FALSE; - gexamplethread = g_thread_new("example thread", &example_thread, NULL); - g_main_loop_run (gloop); - exit_thread = TRUE; - - g_thread_join (gexamplethread); - g_main_loop_unref(gloop); - - return EXIT_SUCCESS; -} - -static void * -example_thread(void *data) -{ - NiceAgent *agent; - NiceCandidate *local, *remote; - GIOChannel* io_stdin; - guint stream_id; - gchar *line = NULL; - int rval; - -#ifdef G_OS_WIN32 - io_stdin = g_io_channel_win32_new_fd(_fileno(stdin)); -#else - io_stdin = g_io_channel_unix_new(fileno(stdin)); -#endif - g_io_channel_set_flags (io_stdin, G_IO_FLAG_NONBLOCK, NULL); - - // Create the nice agent - agent = nice_agent_new(g_main_loop_get_context (gloop), - NICE_COMPATIBILITY_RFC5245); - if (agent == NULL) - g_error("Failed to create agent"); - - // Set the STUN settings and controlling mode - if (stun_addr) { - g_object_set(agent, "stun-server", stun_addr, NULL); - g_object_set(agent, "stun-server-port", stun_port, NULL); - } - g_object_set(agent, "controlling-mode", controlling, NULL); - - // Connect to the signals - g_signal_connect(agent, "candidate-gathering-done", - G_CALLBACK(cb_candidate_gathering_done), NULL); - g_signal_connect(agent, "new-selected-pair", - G_CALLBACK(cb_new_selected_pair), NULL); - g_signal_connect(agent, "component-state-changed", - G_CALLBACK(cb_component_state_changed), NULL); - - // Create a new stream with one component - stream_id = nice_agent_add_stream(agent, 1); - if (stream_id == 0) - g_error("Failed to add stream"); - - // Attach to the component to receive the data - // Without this call, candidates cannot be gathered - nice_agent_attach_recv(agent, stream_id, 1, - g_main_loop_get_context (gloop), cb_nice_recv, NULL); - - // Start gathering local candidates - if (!nice_agent_gather_candidates(agent, stream_id)) - g_error("Failed to start candidate gathering"); - - g_debug("waiting for candidate-gathering-done signal..."); - - g_mutex_lock(&gather_mutex); - while (!exit_thread && !candidate_gathering_done) - g_cond_wait(&gather_cond, &gather_mutex); - g_mutex_unlock(&gather_mutex); - if (exit_thread) - goto end; - - // Candidate gathering is done. Send our local candidates on stdout - printf("Copy this line to remote client:\n"); - printf("\n "); - print_local_data(agent, stream_id, 1); - printf("\n"); - - // Listen on stdin for the remote candidate list - printf("Enter remote data (single line, no wrapping):\n"); - printf("> "); - fflush (stdout); - while (!exit_thread) { - GIOStatus s = g_io_channel_read_line (io_stdin, &line, NULL, NULL, NULL); - if (s == G_IO_STATUS_NORMAL) { - // Parse remote candidate list and set it on the agent - rval = parse_remote_data(agent, stream_id, 1, line); - if (rval == EXIT_SUCCESS) { - g_free (line); - break; - } else { - fprintf(stderr, "ERROR: failed to parse remote data\n"); - printf("Enter remote data (single line, no wrapping):\n"); - printf("> "); - fflush (stdout); - } - g_free (line); - } else if (s == G_IO_STATUS_AGAIN) { - g_usleep (100000); - } - } - - g_debug("waiting for state READY or FAILED signal..."); - g_mutex_lock(&negotiate_mutex); - while (!exit_thread && !negotiation_done) - g_cond_wait(&negotiate_cond, &negotiate_mutex); - g_mutex_unlock(&negotiate_mutex); - if (exit_thread) - goto end; - - // Get current selected candidate pair and print IP address used - if (nice_agent_get_selected_pair (agent, stream_id, 1, - &local, &remote)) { - gchar ipaddr[INET6_ADDRSTRLEN]; - - nice_address_to_string(&local->addr, ipaddr); - printf("\nNegotiation complete: ([%s]:%d,", - ipaddr, nice_address_get_port(&local->addr)); - nice_address_to_string(&remote->addr, ipaddr); - printf(" [%s]:%d)\n", ipaddr, nice_address_get_port(&remote->addr)); - } - - // Listen to stdin and send data written to it - printf("\nSend lines to remote (Ctrl-D to quit):\n"); - printf("> "); - fflush (stdout); - while (!exit_thread) { - GIOStatus s = g_io_channel_read_line (io_stdin, &line, NULL, NULL, NULL); - if (s == G_IO_STATUS_NORMAL) { - nice_agent_send(agent, stream_id, 1, strlen(line), line); - g_free (line); - printf("> "); - fflush (stdout); - } else if (s == G_IO_STATUS_AGAIN) { - g_usleep (100000); - } else { - // Ctrl-D was pressed. - nice_agent_send(agent, stream_id, 1, 1, "\0"); - break; - } - } - -end: - g_io_channel_unref (io_stdin); - g_object_unref(agent); - g_main_loop_quit (gloop); - - return NULL; -} - -static void -cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, - gpointer data) -{ - g_debug("SIGNAL candidate gathering done\n"); - - g_mutex_lock(&gather_mutex); - candidate_gathering_done = TRUE; - g_cond_signal(&gather_cond); - g_mutex_unlock(&gather_mutex); -} - -static void -cb_component_state_changed(NiceAgent *agent, guint stream_id, - guint component_id, guint state, - gpointer data) -{ - g_debug("SIGNAL: state changed %d %d %s[%d]\n", - stream_id, component_id, state_name[state], state); - - if (state == NICE_COMPONENT_STATE_READY) { - g_mutex_lock(&negotiate_mutex); - negotiation_done = TRUE; - g_cond_signal(&negotiate_cond); - g_mutex_unlock(&negotiate_mutex); - } else if (state == NICE_COMPONENT_STATE_FAILED) { - g_main_loop_quit (gloop); - } -} - - -static void -cb_new_selected_pair(NiceAgent *agent, guint stream_id, - guint component_id, gchar *lfoundation, - gchar *rfoundation, gpointer data) -{ - g_debug("SIGNAL: selected pair %s %s", lfoundation, rfoundation); -} - -static void -cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id, - guint len, gchar *buf, gpointer data) -{ - if (len == 1 && buf[0] == '\0') - g_main_loop_quit (gloop); - - printf("%.*s", len, buf); - fflush(stdout); -} - -static NiceCandidate * -parse_candidate(char *scand, guint stream_id) -{ - NiceCandidate *cand = NULL; - NiceCandidateType ntype = NICE_CANDIDATE_TYPE_HOST; - gchar **tokens = NULL; - guint i; - - tokens = g_strsplit (scand, ",", 5); - for (i = 0; tokens[i]; i++); - if (i != 5) - goto end; - - for (i = 0; i < G_N_ELEMENTS (candidate_type_name); i++) { - if (strcmp(tokens[4], candidate_type_name[i]) == 0) { - ntype = i; - break; - } - } - if (i == G_N_ELEMENTS (candidate_type_name)) - goto end; - - cand = nice_candidate_new(ntype); - cand->component_id = 1; - cand->stream_id = stream_id; - cand->transport = NICE_CANDIDATE_TRANSPORT_UDP; - strncpy(cand->foundation, tokens[0], NICE_CANDIDATE_MAX_FOUNDATION - 1); - cand->foundation[NICE_CANDIDATE_MAX_FOUNDATION - 1] = 0; - cand->priority = atoi (tokens[1]); - - if (!nice_address_set_from_string(&cand->addr, tokens[2])) { - g_message("failed to parse addr: %s", tokens[2]); - nice_candidate_free(cand); - cand = NULL; - goto end; - } - - nice_address_set_port(&cand->addr, atoi (tokens[3])); - - end: - g_strfreev(tokens); - - return cand; -} - - -static int -print_local_data (NiceAgent *agent, guint stream_id, guint component_id) -{ - int result = EXIT_FAILURE; - gchar *local_ufrag = NULL; - gchar *local_password = NULL; - gchar ipaddr[INET6_ADDRSTRLEN]; - GSList *cands = NULL, *item; - - if (!nice_agent_get_local_credentials(agent, stream_id, - &local_ufrag, &local_password)) - goto end; - - cands = nice_agent_get_local_candidates(agent, stream_id, component_id); - if (cands == NULL) - goto end; - - printf("%s %s", local_ufrag, local_password); - - for (item = cands; item; item = item->next) { - NiceCandidate *c = (NiceCandidate *)item->data; - - nice_address_to_string(&c->addr, ipaddr); - - // (foundation),(prio),(addr),(port),(type) - printf(" %s,%u,%s,%u,%s", - c->foundation, - c->priority, - ipaddr, - nice_address_get_port(&c->addr), - candidate_type_name[c->type]); - } - printf("\n"); - result = EXIT_SUCCESS; - - end: - if (local_ufrag) - g_free(local_ufrag); - if (local_password) - g_free(local_password); - if (cands) - g_slist_free_full(cands, (GDestroyNotify)&nice_candidate_free); - - return result; -} - - -static int -parse_remote_data(NiceAgent *agent, guint stream_id, - guint component_id, char *line) -{ - GSList *remote_candidates = NULL; - gchar **line_argv = NULL; - const gchar *ufrag = NULL; - const gchar *passwd = NULL; - int result = EXIT_FAILURE; - int i; - - line_argv = g_strsplit_set (line, " \t\n", 0); - for (i = 0; line_argv && line_argv[i]; i++) { - if (strlen (line_argv[i]) == 0) - continue; - - // first two args are remote ufrag and password - if (!ufrag) { - ufrag = line_argv[i]; - } else if (!passwd) { - passwd = line_argv[i]; - } else { - // Remaining args are serialized canidates (at least one is required) - NiceCandidate *c = parse_candidate(line_argv[i], stream_id); - - if (c == NULL) { - g_message("failed to parse candidate: %s", line_argv[i]); - goto end; - } - remote_candidates = g_slist_prepend(remote_candidates, c); - } - } - if (ufrag == NULL || passwd == NULL || remote_candidates == NULL) { - g_message("line must have at least ufrag, password, and one candidate"); - goto end; - } - - if (!nice_agent_set_remote_credentials(agent, stream_id, ufrag, passwd)) { - g_message("failed to set remote credentials"); - goto end; - } - - // Note: this will trigger the start of negotiation. - if (nice_agent_set_remote_candidates(agent, stream_id, component_id, - remote_candidates) < 1) { - g_message("failed to set remote candidates"); - goto end; - } - - result = EXIT_SUCCESS; - - end: - if (line_argv != NULL) - g_strfreev(line_argv); - if (remote_candidates != NULL) - g_slist_free_full(remote_candidates, (GDestroyNotify)&nice_candidate_free); - - return result; -} diff --git a/gst/Makefile.am b/gst/Makefile.am deleted file mode 100644 index 8776780..0000000 --- a/gst/Makefile.am +++ /dev/null @@ -1,58 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2006, 2007 Collabora Ltd. -# (C) 2006, 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. - -AM_CFLAGS = $(LIBNICE_CFLAGS) \ - -I $(top_srcdir) \ - -I $(top_srcdir)/socket \ - -I $(top_srcdir)/agent \ - -I $(top_srcdir)/random \ - -I $(top_srcdir)/stun - -COMMON_LIBADD = \ - $(top_builddir)/nice/libnice.la - -# libgstnice - -if WITH_GSTREAMER -gstplugin_LTLIBRARIES = libgstnice.la - -libgstnice_la_CFLAGS = $(AM_CFLAGS) $(GST_CFLAGS) -DGST_USE_UNSTABLE_API - -libgstnice_la_SOURCES = \ - gstnicesrc.h \ - gstnicesrc.c \ - gstnicesink.h \ - gstnicesink.c \ - gstnice.h \ - gstnice.c - -libgstnice_la_LIBADD = $(COMMON_LIBADD) $(GST_LIBS) - -libgstnice_la_LDFLAGS = -module -avoid-version -no-undefined -endif - - -if WITH_GSTREAMER010 -gstplugin010_LTLIBRARIES = libgstnice010.la - -libgstnice010_la_CFLAGS = $(AM_CFLAGS) $(GST010_CFLAGS) - -libgstnice010_la_SOURCES = \ - gstnicesrc.h \ - gstnicesrc.c \ - gstnicesink.h \ - gstnicesink.c \ - gstnice.h \ - gstnice.c - -libgstnice010_la_LIBADD = $(COMMON_LIBADD) $(GST010_LIBS) - -libgstnice010_la_LDFLAGS = -module -avoid-version -no-undefined -endif - -EXTRA_DIST = meson.build diff --git a/gst/gstnice.c b/gst/gstnice.c deleted file mode 100644 index 6fdb0e9..0000000 --- a/gst/gstnice.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "gstnicesrc.h" -#include "gstnicesink.h" - -static gboolean -plugin_init (GstPlugin *plugin) -{ - if (!gst_element_register (plugin, "nicesrc", - GST_RANK_NONE, GST_TYPE_NICE_SRC)) - return FALSE; - - if (!gst_element_register (plugin, "nicesink", - GST_RANK_NONE, GST_TYPE_NICE_SINK)) - return FALSE; - - return TRUE; -} - -#if GST_CHECK_VERSION (1,0,0) -#define PLUGIN_NAME nice -#else -#define PLUGIN_NAME "nice" -#endif - -GST_PLUGIN_DEFINE ( - GST_VERSION_MAJOR, - GST_VERSION_MINOR, - PLUGIN_NAME, - "Interactive UDP connectivity establishment", - plugin_init, VERSION, "LGPL", PACKAGE_NAME, - "https://nice.freedesktop.org/"); - diff --git a/gst/gstnice.h b/gst/gstnice.h deleted file mode 100644 index b90939a..0000000 --- a/gst/gstnice.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#include "gstnicesrc.h" -#include "gstnicesink.h" - diff --git a/gst/gstnicesink.c b/gst/gstnicesink.c deleted file mode 100644 index be46665..0000000 --- a/gst/gstnicesink.c +++ /dev/null @@ -1,584 +0,0 @@ - -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "gstnicesink.h" - - -GST_DEBUG_CATEGORY_STATIC (nicesink_debug); -#define GST_CAT_DEFAULT nicesink_debug - -static GstFlowReturn -gst_nice_sink_render ( - GstBaseSink *basesink, - GstBuffer *buffer); -#if GST_CHECK_VERSION (1,0,0) -static GstFlowReturn -gst_nice_sink_render_list ( - GstBaseSink *basesink, - GstBufferList *buffer_list); -#endif - -static gboolean -gst_nice_sink_unlock (GstBaseSink *basesink); - -static gboolean -gst_nice_sink_unlock_stop (GstBaseSink *basesink); - -static void -_reliable_transport_writable ( - NiceAgent *agent, - guint stream_id, - guint component_id, - GstNiceSink *sink); - -static void -gst_nice_sink_set_property ( - GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); - -static void -gst_nice_sink_get_property ( - GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - -static void -gst_nice_sink_dispose (GObject *object); -#if GST_CHECK_VERSION (1,0,0) -static void -gst_nice_sink_finalize (GObject *object); -#endif - -static GstStateChangeReturn -gst_nice_sink_change_state ( - GstElement * element, - GstStateChange transition); - -static GstStaticPadTemplate gst_nice_sink_sink_template = -GST_STATIC_PAD_TEMPLATE ( - "sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -G_DEFINE_TYPE (GstNiceSink, gst_nice_sink, GST_TYPE_BASE_SINK); - -enum -{ - PROP_AGENT = 1, - PROP_STREAM, - PROP_COMPONENT -}; - -static void -gst_nice_sink_class_init (GstNiceSinkClass *klass) -{ - GstBaseSinkClass *gstbasesink_class; - GstElementClass *gstelement_class; - GObjectClass *gobject_class; - - GST_DEBUG_CATEGORY_INIT (nicesink_debug, "nicesink", - 0, "libnice sink"); - - gstbasesink_class = (GstBaseSinkClass *) klass; - gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_nice_sink_render); -#if GST_CHECK_VERSION (1,0,0) - gstbasesink_class->render_list = GST_DEBUG_FUNCPTR (gst_nice_sink_render_list); -#endif - gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_nice_sink_unlock); - gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_nice_sink_unlock_stop); - - gobject_class = (GObjectClass *) klass; - gobject_class->set_property = gst_nice_sink_set_property; - gobject_class->get_property = gst_nice_sink_get_property; - gobject_class->dispose = gst_nice_sink_dispose; -#if GST_CHECK_VERSION (1,0,0) - gobject_class->finalize = gst_nice_sink_finalize; -#endif - - gstelement_class = (GstElementClass *) klass; - gstelement_class->change_state = gst_nice_sink_change_state; - - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&gst_nice_sink_sink_template)); -#if GST_CHECK_VERSION (1,0,0) - gst_element_class_set_metadata (gstelement_class, -#else - gst_element_class_set_details_simple (gstelement_class, -#endif - "ICE sink", - "Sink", - "Interactive UDP connectivity establishment", - "Dafydd Harries "); - - - g_object_class_install_property (gobject_class, PROP_AGENT, - g_param_spec_object ( - "agent", - "Agent", - "The NiceAgent this source is bound to", - NICE_TYPE_AGENT, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_STREAM, - g_param_spec_uint ( - "stream", - "Stream ID", - "The ID of the stream to read from", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_COMPONENT, - g_param_spec_uint ( - "component", - "Component ID", - "The ID of the component to read from", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE)); -} - -static void -gst_nice_sink_init (GstNiceSink *sink) -{ -#if GST_CHECK_VERSION (1,0,0) - guint max_mem; -#endif - - g_cond_init (&sink->writable_cond); - -#if GST_CHECK_VERSION (1,0,0) - /* pre-allocate OutputVector, MapInfo and OutputMessage arrays - * for use in the render and render_list functions */ - max_mem = gst_buffer_get_max_memory (); - - sink->n_vecs = max_mem; - sink->vecs = g_new (GOutputVector, sink->n_vecs); - - sink->n_maps = max_mem; - sink->maps = g_new (GstMapInfo, sink->n_maps); - - sink->n_messages = 1; - sink->messages = g_new (NiceOutputMessage, sink->n_messages); -#endif -} - -static void -_reliable_transport_writable (NiceAgent *agent, guint stream_id, - guint component_id, GstNiceSink *sink) -{ - GST_OBJECT_LOCK (sink); - if (stream_id == sink->stream_id && component_id == sink->component_id) { - g_cond_broadcast (&sink->writable_cond); - } - GST_OBJECT_UNLOCK (sink); -} - -#if GST_CHECK_VERSION (1,0,0) -static gsize -fill_vectors (GOutputVector * vecs, GstMapInfo * maps, guint n, GstBuffer * buf) -{ - GstMemory *mem; - gsize size = 0; - guint i; - - g_assert_cmpuint (gst_buffer_n_memory (buf), ==, n); - - for (i = 0; i < n; ++i) { - mem = gst_buffer_peek_memory (buf, i); - if (gst_memory_map (mem, &maps[i], GST_MAP_READ)) { - vecs[i].buffer = maps[i].data; - vecs[i].size = maps[i].size; - } else { - GST_WARNING ("Failed to map memory %p for reading", mem); - vecs[i].buffer = ""; - vecs[i].size = 0; - } - size += vecs[i].size; - } - - return size; -} - -/* Buffer list code written by - * Tim-Philipp Müller - * taken from - * gst-plugins-good/gst/udp/gstmultiudpsink.c - */ -static GstFlowReturn -gst_nice_sink_render_buffers (GstNiceSink * sink, GstBuffer ** buffers, - guint num_buffers, guint8 * mem_nums, guint total_mem_num) -{ - NiceOutputMessage *msgs; - GOutputVector *vecs; - GstMapInfo *map_infos; - guint i, mem; - guint written = 0; - gint ret; - GstFlowReturn flow_ret = GST_FLOW_OK; - - GST_LOG_OBJECT (sink, "%u buffers, %u memories -> to be sent", - num_buffers, total_mem_num); - - if (sink->n_vecs < total_mem_num) { - sink->n_vecs = GST_ROUND_UP_16 (total_mem_num); - g_free (sink->vecs); - sink->vecs = g_new (GOutputVector, sink->n_vecs); - } - vecs = sink->vecs; - - if (sink->n_maps < total_mem_num) { - sink->n_maps = GST_ROUND_UP_16 (total_mem_num); - g_free (sink->maps); - sink->maps = g_new (GstMapInfo, sink->n_maps); - } - map_infos = sink->maps; - - if (sink->n_messages < num_buffers) { - sink->n_messages = GST_ROUND_UP_16 (num_buffers); - g_free (sink->messages); - sink->messages = g_new (NiceOutputMessage, sink->n_messages); - } - msgs = sink->messages; - - for (i = 0, mem = 0; i < num_buffers; ++i) { - fill_vectors (&vecs[mem], &map_infos[mem], mem_nums[i], buffers[i]); - msgs[i].buffers = &vecs[mem]; - msgs[i].n_buffers = mem_nums[i]; - mem += mem_nums[i]; - } - - GST_OBJECT_LOCK (sink); - do { - ret = nice_agent_send_messages_nonblocking(sink->agent, sink->stream_id, - sink->component_id, msgs + written, num_buffers - written, NULL, NULL); - - if (ret > 0) - written += ret; - - if (sink->reliable && written < num_buffers) - g_cond_wait (&sink->writable_cond, GST_OBJECT_GET_LOCK (sink)); - - if (sink->flushing) { - flow_ret = GST_FLOW_FLUSHING; - break; - } - } while (sink->reliable && written < num_buffers); - GST_OBJECT_UNLOCK (sink); - - for (i = 0; i < mem; ++i) - gst_memory_unmap (map_infos[i].memory, &map_infos[i]); - - return flow_ret; -} -#endif - -static GstFlowReturn -gst_nice_sink_render (GstBaseSink *basesink, GstBuffer *buffer) -{ - GstNiceSink *nicesink = GST_NICE_SINK (basesink); - GstFlowReturn flow_ret = GST_FLOW_OK; -#if GST_CHECK_VERSION (1,0,0) - guint8 n_mem; - - n_mem = gst_buffer_n_memory (buffer); - - if (n_mem > 0) { - flow_ret = gst_nice_sink_render_buffers (nicesink, &buffer, 1, &n_mem, - n_mem); - } - -#else - guint written = 0; - gint ret; - gchar *data = NULL; - guint size = 0; - - data = (gchar *) GST_BUFFER_DATA (buffer); - size = GST_BUFFER_SIZE (buffer); - - GST_OBJECT_LOCK (nicesink); - do { - ret = nice_agent_send (nicesink->agent, nicesink->stream_id, - nicesink->component_id, size - written, data + written); - if (ret > 0) - written += ret; - - if (nicesink->reliable && written < size) - g_cond_wait (&nicesink->writable_cond, GST_OBJECT_GET_LOCK (nicesink)); - if (nicesink->flushing) { - flow_ret = GST_FLOW_WRONG_STATE; - break; - } - } while (nicesink->reliable && written < size); - GST_OBJECT_UNLOCK (nicesink); - -#endif - return flow_ret; -} - -#if GST_CHECK_VERSION (1,0,0) -static GstFlowReturn -gst_nice_sink_render_list (GstBaseSink *basesink, GstBufferList *buffer_list) -{ - GstNiceSink *nicesink = GST_NICE_SINK (basesink); - GstBuffer **buffers; - GstFlowReturn flow_ret = GST_FLOW_OK; - guint8 *mem_nums; - guint total_mems; - guint i, num_buffers; - - num_buffers = gst_buffer_list_length (buffer_list); - if (num_buffers == 0) - goto no_data; - - buffers = g_newa (GstBuffer *, num_buffers); - mem_nums = g_newa (guint8, num_buffers); - for (i = 0, total_mems = 0; i < num_buffers; ++i) { - buffers[i] = gst_buffer_list_get (buffer_list, i); - mem_nums[i] = gst_buffer_n_memory (buffers[i]); - total_mems += mem_nums[i]; - } - - flow_ret = gst_nice_sink_render_buffers (nicesink, buffers, num_buffers, - mem_nums, total_mems); - - return flow_ret; - -no_data: - { - GST_LOG_OBJECT (nicesink, "empty buffer"); - return GST_FLOW_OK; - } - - return flow_ret; -} -#endif - -static gboolean gst_nice_sink_unlock (GstBaseSink *basesink) -{ - GstNiceSink *nicesink = GST_NICE_SINK (basesink); - - GST_OBJECT_LOCK (nicesink); - nicesink->flushing = TRUE; - g_cond_broadcast (&nicesink->writable_cond); - GST_OBJECT_UNLOCK (nicesink); - - return TRUE; -} - -static gboolean gst_nice_sink_unlock_stop (GstBaseSink *basesink) -{ - GstNiceSink *nicesink = GST_NICE_SINK (basesink); - - GST_OBJECT_LOCK (nicesink); - nicesink->flushing = FALSE; - GST_OBJECT_UNLOCK (nicesink); - - return TRUE; -} - -static void -gst_nice_sink_dispose (GObject *object) -{ - GstNiceSink *sink = GST_NICE_SINK (object); - - if (sink->agent && sink->writable_id) - g_signal_handler_disconnect (sink->agent, sink->writable_id); - sink->writable_id = 0; - g_clear_object (&sink->agent); - - g_cond_clear (&sink->writable_cond); - - G_OBJECT_CLASS (gst_nice_sink_parent_class)->dispose (object); -} - -#if GST_CHECK_VERSION (1,0,0) -static void -gst_nice_sink_finalize (GObject *object) -{ - GstNiceSink *sink = GST_NICE_SINK (object); - - g_free (sink->vecs); - sink->vecs = NULL; - sink->n_vecs = 0; - g_free (sink->maps); - sink->maps = NULL; - sink->n_maps = 0; - g_free (sink->messages); - sink->messages = NULL; - sink->n_messages = 0; - - G_OBJECT_CLASS (gst_nice_sink_parent_class)->finalize (object); -} -#endif - -static void -gst_nice_sink_set_property ( - GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GstNiceSink *sink = GST_NICE_SINK (object); - - switch (prop_id) - { - case PROP_AGENT: - if (sink->agent) { - GST_ERROR_OBJECT (object, - "Changing the agent on a nice sink not allowed"); - } else { - sink->agent = g_value_dup_object (value); - g_object_get (sink->agent, "reliable", &sink->reliable, NULL); - if (sink->reliable) - sink->writable_id = g_signal_connect (sink->agent, - "reliable-transport-writable", - (GCallback) _reliable_transport_writable, sink); - } - break; - - case PROP_STREAM: - GST_OBJECT_LOCK (sink); - sink->stream_id = g_value_get_uint (value); - GST_OBJECT_UNLOCK (sink); - break; - - case PROP_COMPONENT: - { - guint new_component_id = g_value_get_uint (value); - GST_OBJECT_LOCK (sink); - if (sink->component_id != new_component_id) { - sink->component_id = new_component_id; - g_cond_broadcast (&sink->writable_cond); - } - GST_OBJECT_UNLOCK (sink); - } - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_nice_sink_get_property ( - GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GstNiceSink *sink = GST_NICE_SINK (object); - - switch (prop_id) - { - case PROP_AGENT: - g_value_set_object (value, sink->agent); - break; - - case PROP_STREAM: - GST_OBJECT_LOCK (sink); - g_value_set_uint (value, sink->stream_id); - GST_OBJECT_UNLOCK (sink); - break; - - case PROP_COMPONENT: - GST_OBJECT_LOCK (sink); - g_value_set_uint (value, sink->component_id); - GST_OBJECT_UNLOCK (sink); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_nice_sink_change_state (GstElement * element, GstStateChange transition) -{ - GstNiceSink *sink; - GstStateChangeReturn ret; - - sink = GST_NICE_SINK (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (sink->agent == NULL) - { - GST_ERROR_OBJECT (element, - "Trying to start Nice sink without an agent set"); - return GST_STATE_CHANGE_FAILURE; - } - else if (sink->stream_id == 0) - { - GST_ERROR_OBJECT (element, - "Trying to start Nice sink without a stream set"); - return GST_STATE_CHANGE_FAILURE; - } - else if (sink->component_id == 0) - { - GST_ERROR_OBJECT (element, - "Trying to start Nice sink without a component set"); - return GST_STATE_CHANGE_FAILURE; - } - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - case GST_STATE_CHANGE_PAUSED_TO_READY: - case GST_STATE_CHANGE_READY_TO_NULL: - default: - break; - } - - ret = GST_ELEMENT_CLASS (gst_nice_sink_parent_class)->change_state (element, - transition); - - return ret; -} diff --git a/gst/gstnicesink.h b/gst/gstnicesink.h deleted file mode 100644 index 3c8edbb..0000000 --- a/gst/gstnicesink.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _GST_NICE_SINK_H -#define _GST_NICE_SINK_H - -#include -#include - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_NICE_SINK \ - (gst_nice_sink_get_type()) -#define GST_NICE_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NICE_SINK,GstNiceSink)) -#define GST_NICE_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NICE_SINK,GstNiceSinkClass)) -#define GST_IS_NICE_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NICE_SINK)) -#define GST_IS_NICE_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NICE_SINK)) - -typedef struct _GstNiceSink GstNiceSink; - -struct _GstNiceSink -{ - GstBaseSink parent; - GstPad *sinkpad; - NiceAgent *agent; - guint stream_id; - guint component_id; - gboolean reliable; - GCond writable_cond; - gulong writable_id; - gboolean flushing; - -#if GST_CHECK_VERSION (1,0,0) - /* pre-allocated scrap space for render function */ - GOutputVector *vecs; - guint n_vecs; - GstMapInfo *maps; - guint n_maps; - NiceOutputMessage *messages; - guint n_messages; -#endif -}; - -typedef struct _GstNiceSinkClass GstNiceSinkClass; - -struct _GstNiceSinkClass -{ - GstBaseSinkClass parent_class; -}; - -GType gst_nice_sink_get_type (void); - -G_END_DECLS - -#endif diff --git a/gst/gstnicesrc.c b/gst/gstnicesrc.c deleted file mode 100644 index 424f449..0000000 --- a/gst/gstnicesrc.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "gstnicesrc.h" - -GST_DEBUG_CATEGORY_STATIC (nicesrc_debug); -#define GST_CAT_DEFAULT nicesrc_debug - - -#define BUFFER_SIZE (65536) - -static GstFlowReturn -gst_nice_src_create ( - GstPushSrc *basesrc, - GstBuffer **buffer); - -static gboolean -gst_nice_src_unlock ( - GstBaseSrc *basesrc); - -static gboolean -gst_nice_src_unlock_stop ( - GstBaseSrc *basesrc); - -static void -gst_nice_src_set_property ( - GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); - -static void -gst_nice_src_get_property ( - GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - - -static void -gst_nice_src_dispose (GObject *object); - -static GstStateChangeReturn -gst_nice_src_change_state ( - GstElement * element, - GstStateChange transition); - -static GstStaticPadTemplate gst_nice_src_src_template = -GST_STATIC_PAD_TEMPLATE ( - "src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -G_DEFINE_TYPE (GstNiceSrc, gst_nice_src, GST_TYPE_PUSH_SRC); - -enum -{ - PROP_AGENT = 1, - PROP_STREAM, - PROP_COMPONENT -}; - - -static void -gst_nice_src_class_init (GstNiceSrcClass *klass) -{ - GstPushSrcClass *gstpushsrc_class; - GstBaseSrcClass *gstbasesrc_class; - GstElementClass *gstelement_class; - GObjectClass *gobject_class; - - GST_DEBUG_CATEGORY_INIT (nicesrc_debug, "nicesrc", - 0, "libnice source"); - - gstpushsrc_class = (GstPushSrcClass *) klass; - gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_nice_src_create); - - gstbasesrc_class = (GstBaseSrcClass *) klass; - gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_nice_src_unlock); - gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_nice_src_unlock_stop); - - gobject_class = (GObjectClass *) klass; - gobject_class->set_property = gst_nice_src_set_property; - gobject_class->get_property = gst_nice_src_get_property; - gobject_class->dispose = gst_nice_src_dispose; - - gstelement_class = (GstElementClass *) klass; - gstelement_class->change_state = gst_nice_src_change_state; - - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&gst_nice_src_src_template)); -#if GST_CHECK_VERSION (1,0,0) - gst_element_class_set_metadata (gstelement_class, -#else - gst_element_class_set_details_simple (gstelement_class, -#endif - "ICE source", - "Source", - "Interactive UDP connectivity establishment", - "Dafydd Harries "); - - g_object_class_install_property (gobject_class, PROP_AGENT, - g_param_spec_object ( - "agent", - "Agent", - "The NiceAgent this source is bound to", - NICE_TYPE_AGENT, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_STREAM, - g_param_spec_uint ( - "stream", - "Stream ID", - "The ID of the stream to read from", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_COMPONENT, - g_param_spec_uint ( - "component", - "Component ID", - "The ID of the component to read from", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE)); -} - -static void -gst_nice_src_init (GstNiceSrc *src) -{ - gst_base_src_set_live (GST_BASE_SRC (src), TRUE); - gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME); - gst_base_src_set_do_timestamp (GST_BASE_SRC (src), TRUE); - src->agent = NULL; - src->stream_id = 0; - src->component_id = 0; - src->mainctx = g_main_context_new (); - src->mainloop = g_main_loop_new (src->mainctx, FALSE); - src->unlocked = FALSE; - src->idle_source = NULL; - src->outbufs = g_queue_new (); -} - -static void -gst_nice_src_read_callback (NiceAgent *agent, - guint stream_id, - guint component_id, - guint len, - gchar *buf, - gpointer data) -{ - GstBaseSrc *basesrc = GST_BASE_SRC (data); - GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc); - GstBuffer *buffer = NULL; - - GST_LOG_OBJECT (agent, "Got buffer, getting out of the main loop"); - -#if GST_CHECK_VERSION (1,0,0) - buffer = gst_buffer_new_allocate (NULL, len, NULL); - gst_buffer_fill (buffer, 0, buf, len); -#else - buffer = gst_buffer_new_and_alloc (len); - memcpy (GST_BUFFER_DATA (buffer), buf, len); -#endif - GST_OBJECT_LOCK (nicesrc); - g_queue_push_tail (nicesrc->outbufs, buffer); - g_main_loop_quit (nicesrc->mainloop); - GST_OBJECT_UNLOCK (nicesrc); -} - -static gboolean -gst_nice_src_unlock_idler (gpointer data) -{ - GstNiceSrc *nicesrc = GST_NICE_SRC (data); - - GST_OBJECT_LOCK (nicesrc); - if (nicesrc->unlocked) - g_main_loop_quit (nicesrc->mainloop); - - if (nicesrc->idle_source) { - g_source_destroy (nicesrc->idle_source); - g_source_unref (nicesrc->idle_source); - nicesrc->idle_source = NULL; - } - GST_OBJECT_UNLOCK (nicesrc); - - return FALSE; -} - -static gboolean -gst_nice_src_unlock (GstBaseSrc *src) -{ - GstNiceSrc *nicesrc = GST_NICE_SRC (src); - - GST_OBJECT_LOCK (src); - nicesrc->unlocked = TRUE; - - g_main_loop_quit (nicesrc->mainloop); - - if (!nicesrc->idle_source) { - nicesrc->idle_source = g_idle_source_new (); - g_source_set_priority (nicesrc->idle_source, G_PRIORITY_HIGH); - g_source_set_callback (nicesrc->idle_source, gst_nice_src_unlock_idler, src, NULL); - g_source_attach (nicesrc->idle_source, g_main_loop_get_context (nicesrc->mainloop)); - } - GST_OBJECT_UNLOCK (src); - - return TRUE; -} - -static gboolean -gst_nice_src_unlock_stop (GstBaseSrc *src) -{ - GstNiceSrc *nicesrc = GST_NICE_SRC (src); - - GST_OBJECT_LOCK (src); - nicesrc->unlocked = FALSE; - if (nicesrc->idle_source) { - g_source_destroy (nicesrc->idle_source); - g_source_unref(nicesrc->idle_source); - } - nicesrc->idle_source = NULL; - GST_OBJECT_UNLOCK (src); - - return TRUE; -} - -static GstFlowReturn -gst_nice_src_create ( - GstPushSrc *basesrc, - GstBuffer **buffer) -{ - GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc); - - GST_LOG_OBJECT (nicesrc, "create called"); - - GST_OBJECT_LOCK (basesrc); - if (nicesrc->unlocked) { - GST_OBJECT_UNLOCK (basesrc); -#if GST_CHECK_VERSION (1,0,0) - return GST_FLOW_FLUSHING; -#else - return GST_FLOW_WRONG_STATE; -#endif - } - if (g_queue_is_empty (nicesrc->outbufs)) { - GST_OBJECT_UNLOCK (basesrc); - g_main_loop_run (nicesrc->mainloop); - GST_OBJECT_LOCK (basesrc); - } - - *buffer = g_queue_pop_head (nicesrc->outbufs); - GST_OBJECT_UNLOCK (basesrc); - - if (*buffer != NULL) { - GST_LOG_OBJECT (nicesrc, "Got buffer, pushing"); - return GST_FLOW_OK; - } else { - GST_LOG_OBJECT (nicesrc, "Got interrupting, returning wrong-state"); -#if GST_CHECK_VERSION (1,0,0) - return GST_FLOW_FLUSHING; -#else - return GST_FLOW_WRONG_STATE; -#endif - } - -} - -static void -gst_nice_src_dispose (GObject *object) -{ - GstNiceSrc *src = GST_NICE_SRC (object); - - if (src->agent) - g_object_unref (src->agent); - src->agent = NULL; - - if (src->mainloop) - g_main_loop_unref (src->mainloop); - src->mainloop = NULL; - - if (src->mainctx) - g_main_context_unref (src->mainctx); - src->mainctx = NULL; - - if (src->outbufs) { - g_queue_free_full (src->outbufs, (GDestroyNotify) gst_buffer_unref); - } - src->outbufs = NULL; - - if (src->idle_source) { - g_source_destroy (src->idle_source); - g_source_unref(src->idle_source); - } - src->idle_source = NULL; - - G_OBJECT_CLASS (gst_nice_src_parent_class)->dispose (object); -} - -static void -gst_nice_src_set_property ( - GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GstNiceSrc *src = GST_NICE_SRC (object); - - switch (prop_id) - { - case PROP_AGENT: - if (src->agent) - GST_ERROR_OBJECT (object, - "Changing the agent on a nice src not allowed"); - else - src->agent = g_value_dup_object (value); - break; - - case PROP_STREAM: - src->stream_id = g_value_get_uint (value); - break; - - case PROP_COMPONENT: - src->component_id = g_value_get_uint (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_nice_src_get_property ( - GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GstNiceSrc *src = GST_NICE_SRC (object); - - switch (prop_id) - { - case PROP_AGENT: - g_value_set_object (value, src->agent); - break; - - case PROP_STREAM: - g_value_set_uint (value, src->stream_id); - break; - - case PROP_COMPONENT: - g_value_set_uint (value, src->component_id); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_nice_src_change_state (GstElement * element, GstStateChange transition) -{ - GstNiceSrc *src; - GstStateChangeReturn ret; - - src = GST_NICE_SRC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (src->agent == NULL) - { - GST_ERROR_OBJECT (element, - "Trying to start Nice source without an agent set"); - return GST_STATE_CHANGE_FAILURE; - } - else if (src->stream_id == 0) - { - GST_ERROR_OBJECT (element, - "Trying to start Nice source without a stream set"); - return GST_STATE_CHANGE_FAILURE; - } - else if (src->component_id == 0) - { - GST_ERROR_OBJECT (element, - "Trying to start Nice source without a component set"); - return GST_STATE_CHANGE_FAILURE; - } - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - nice_agent_attach_recv (src->agent, src->stream_id, src->component_id, - src->mainctx, NULL, NULL); - GST_OBJECT_LOCK (src); - g_list_free_full (src->outbufs->head, (GDestroyNotify) gst_buffer_unref); - g_queue_init (src->outbufs); - GST_OBJECT_UNLOCK (src); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - case GST_STATE_CHANGE_READY_TO_NULL: - default: - break; - } - - ret = GST_ELEMENT_CLASS (gst_nice_src_parent_class)->change_state (element, - transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - nice_agent_attach_recv (src->agent, src->stream_id, src->component_id, - src->mainctx, gst_nice_src_read_callback, (gpointer) src); - break; - case GST_STATE_CHANGE_NULL_TO_READY: - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - case GST_STATE_CHANGE_PAUSED_TO_READY: - case GST_STATE_CHANGE_READY_TO_NULL: - default: - break; - } - - return ret; -} - - diff --git a/gst/gstnicesrc.h b/gst/gstnicesrc.h deleted file mode 100644 index 5d3f554..0000000 --- a/gst/gstnicesrc.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _GSTNICESRC_H -#define _GSTNICESRC_H - -#include -#include - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_NICE_SRC \ - (gst_nice_src_get_type()) -#define GST_NICE_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NICE_SRC,GstNiceSrc)) -#define GST_NICE_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NICE_SRC,GstNiceSrcClass)) -#define GST_IS_NICE_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NICE_SRC)) -#define GST_IS_NICE_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NICE_SRC)) - -typedef struct _GstNiceSrc GstNiceSrc; - -struct _GstNiceSrc -{ - GstPushSrc parent; - GstPad *srcpad; - NiceAgent *agent; - guint stream_id; - guint component_id; - GMainContext *mainctx; - GMainLoop *mainloop; - GQueue *outbufs; - gboolean unlocked; - GSource *idle_source; -}; - -typedef struct _GstNiceSrcClass GstNiceSrcClass; - -struct _GstNiceSrcClass -{ - GstPushSrcClass parent_class; -}; - -GType gst_nice_src_get_type (void); - -G_END_DECLS - -#endif // _GSTNICESRC_H - diff --git a/gst/meson.build b/gst/meson.build deleted file mode 100644 index 091a37f..0000000 --- a/gst/meson.build +++ /dev/null @@ -1,23 +0,0 @@ -gst_nice_sources = [ - 'gstnicesrc.c', - 'gstnicesink.c', - 'gstnice.c', -] - -gst_nice_args = ['-DGST_USE_UNSTABLE_API'] - -gst_plugins_install_dir = join_paths(get_option('libdir'), 'gstreamer-1.0') - -libgstnice = library('gstnice', - gst_nice_sources, - c_args : gst_nice_args, - include_directories: nice_incs, - dependencies: [nice_deps, gst_dep], - link_with: libnice, - install_dir: gst_plugins_install_dir, - install: true) - -# Generate pc files for static plugins if we build static plugins -if get_option('default_library') != 'shared' - pkg.generate(libgstnice, install_dir: join_paths(gst_plugins_install_dir, 'pkgconfig')) -endif diff --git a/m4/as-compiler-flag.m4 b/m4/as-compiler-flag.m4 deleted file mode 100644 index 882a4c7..0000000 --- a/m4/as-compiler-flag.m4 +++ /dev/null @@ -1,64 +0,0 @@ -dnl as-compiler-flag.m4 0.1.0 - -dnl autostars m4 macro for detection of compiler flags - -dnl David Schleef -dnl Tim-Philipp Müller - -dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) -dnl Tries to compile with the given CFLAGS. -dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, -dnl and ACTION-IF-NOT-ACCEPTED otherwise. - -AC_DEFUN([AS_COMPILER_FLAG], -[ - AC_MSG_CHECKING([to see if compiler understands $1]) - - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $1" - - AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) - CFLAGS="$save_CFLAGS" - - if test "X$flag_ok" = Xyes ; then - $2 - true - else - $3 - true - fi - AC_MSG_RESULT([$flag_ok]) -]) - -dnl AS_CXX_COMPILER_FLAG(CPPFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) -dnl Tries to compile with the given CPPFLAGS. -dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, -dnl and ACTION-IF-NOT-ACCEPTED otherwise. - -AC_DEFUN([AS_CXX_COMPILER_FLAG], -[ - AC_REQUIRE([AC_PROG_CXX]) - - AC_MSG_CHECKING([to see if c++ compiler understands $1]) - - save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $1" - - AC_LANG_PUSH(C++) - - AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) - CPPFLAGS="$save_CPPFLAGS" - - if test "X$flag_ok" = Xyes ; then - $2 - true - else - $3 - true - fi - - AC_LANG_POP(C++) - - AC_MSG_RESULT([$flag_ok]) -]) - diff --git a/m4/ax_check_openssl.m4 b/m4/ax_check_openssl.m4 deleted file mode 100644 index 28e48cb..0000000 --- a/m4/ax_check_openssl.m4 +++ /dev/null @@ -1,124 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_check_openssl.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]]) -# -# DESCRIPTION -# -# Look for OpenSSL in a number of default spots, or in a user-selected -# spot (via --with-openssl). Sets -# -# OPENSSL_INCLUDES to the include directives required -# OPENSSL_LIBS to the -l directives required -# OPENSSL_LDFLAGS to the -L or -R flags required -# -# and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately -# -# This macro sets OPENSSL_INCLUDES such that source files should use the -# openssl/ directory in include directives: -# -# #include -# -# LICENSE -# -# Copyright (c) 2009,2010 Zmanda Inc. -# Copyright (c) 2009,2010 Dustin J. Mitchell -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 10 - -AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL]) -AC_DEFUN([AX_CHECK_OPENSSL], [ - found=false - AC_ARG_WITH([openssl], - [AS_HELP_STRING([--with-openssl=DIR], - [root of the OpenSSL directory])], - [ - case "$withval" in - "" | y | ye | yes | n | no) - AC_MSG_ERROR([Invalid --with-openssl value]) - ;; - *) ssldirs="$withval" - ;; - esac - ], [ - # if pkg-config is installed and openssl has installed a .pc file, - # then use that information and don't search ssldirs - AC_CHECK_TOOL([PKG_CONFIG], [pkg-config]) - if test x"$PKG_CONFIG" != x""; then - OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` - if test $? = 0; then - OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` - OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` - found=true - fi - fi - - # no such luck; use some default ssldirs - if ! $found; then - ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" - fi - ] - ) - - - # note that we #include , so the OpenSSL headers have to be in - # an 'openssl' subdirectory - - if ! $found; then - OPENSSL_INCLUDES= - for ssldir in $ssldirs; do - AC_MSG_CHECKING([for openssl/ssl.h in $ssldir]) - if test -f "$ssldir/include/openssl/ssl.h"; then - OPENSSL_INCLUDES="-I$ssldir/include" - OPENSSL_LDFLAGS="-L$ssldir/lib" - OPENSSL_LIBS="-lssl -lcrypto" - found=true - AC_MSG_RESULT([yes]) - break - else - AC_MSG_RESULT([no]) - fi - done - - # if the file wasn't found, well, go ahead and try the link anyway -- maybe - # it will just work! - fi - - # try the preprocessor and linker with our new flags, - # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS - - AC_MSG_CHECKING([whether compiling and linking against OpenSSL works]) - echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ - "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&AS_MESSAGE_LOG_FD - - save_LIBS="$LIBS" - save_LDFLAGS="$LDFLAGS" - save_CPPFLAGS="$CPPFLAGS" - LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" - LIBS="$OPENSSL_LIBS $LIBS" - CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" - AC_LINK_IFELSE( - [AC_LANG_PROGRAM([#include ], [SSL_new(NULL)])], - [ - AC_MSG_RESULT([yes]) - $1 - ], [ - AC_MSG_RESULT([no]) - $2 - ]) - CPPFLAGS="$save_CPPFLAGS" - LDFLAGS="$save_LDFLAGS" - LIBS="$save_LIBS" - - AC_SUBST([OPENSSL_INCLUDES]) - AC_SUBST([OPENSSL_LIBS]) - AC_SUBST([OPENSSL_LDFLAGS]) -]) diff --git a/m4/introspection.m4 b/m4/introspection.m4 deleted file mode 100644 index d89c3d9..0000000 --- a/m4/introspection.m4 +++ /dev/null @@ -1,96 +0,0 @@ -dnl -*- mode: autoconf -*- -dnl Copyright 2009 Johan Dahlin -dnl -dnl This file is free software; the author(s) gives unlimited -dnl permission to copy and/or distribute it, with or without -dnl modifications, as long as this notice is preserved. -dnl - -# serial 1 - -m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL], -[ - AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first - AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first - AC_BEFORE([LT_INIT],[$0])dnl setup libtool first - - dnl enable/disable introspection - m4_if([$2], [require], - [dnl - enable_introspection=yes - ],[dnl - AC_ARG_ENABLE(introspection, - AS_HELP_STRING([--enable-introspection[=@<:@no/auto/yes@:>@]], - [Enable introspection for this build]),, - [enable_introspection=auto]) - ])dnl - - AC_MSG_CHECKING([for gobject-introspection]) - - dnl presence/version checking - AS_CASE([$enable_introspection], - [no], [dnl - found_introspection="no (disabled, use --enable-introspection to enable)" - ],dnl - [yes],[dnl - PKG_CHECK_EXISTS([gobject-introspection-1.0],, - AC_MSG_ERROR([gobject-introspection-1.0 is not installed])) - PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], - found_introspection=yes, - AC_MSG_ERROR([You need to have gobject-introspection >= $1 installed to build AC_PACKAGE_NAME])) - ],dnl - [auto],[dnl - PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, found_introspection=no) - dnl Canonicalize enable_introspection - enable_introspection=$found_introspection - ],dnl - [dnl - AC_MSG_ERROR([invalid argument passed to --enable-introspection, should be one of @<:@no/auto/yes@:>@]) - ])dnl - - AC_MSG_RESULT([$found_introspection]) - - INTROSPECTION_SCANNER= - INTROSPECTION_COMPILER= - INTROSPECTION_GENERATE= - INTROSPECTION_GIRDIR= - INTROSPECTION_TYPELIBDIR= - if test "x$found_introspection" = "xyes"; then - INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` - INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` - INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` - INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0` - INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)" - INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0` - INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0` - INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection - fi - AC_SUBST(INTROSPECTION_SCANNER) - AC_SUBST(INTROSPECTION_COMPILER) - AC_SUBST(INTROSPECTION_GENERATE) - AC_SUBST(INTROSPECTION_GIRDIR) - AC_SUBST(INTROSPECTION_TYPELIBDIR) - AC_SUBST(INTROSPECTION_CFLAGS) - AC_SUBST(INTROSPECTION_LIBS) - AC_SUBST(INTROSPECTION_MAKEFILE) - - AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes") -]) - - -dnl Usage: -dnl GOBJECT_INTROSPECTION_CHECK([minimum-g-i-version]) - -AC_DEFUN([GOBJECT_INTROSPECTION_CHECK], -[ - _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1]) -]) - -dnl Usage: -dnl GOBJECT_INTROSPECTION_REQUIRE([minimum-g-i-version]) - - -AC_DEFUN([GOBJECT_INTROSPECTION_REQUIRE], -[ - _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1], [require]) -]) diff --git a/meson.build b/meson.build deleted file mode 100644 index 0004d91..0000000 --- a/meson.build +++ /dev/null @@ -1,320 +0,0 @@ -project('libnice', 'c', - version: '0.1.17', - meson_version : '>= 0.52', - default_options : ['warning_level=1', 'buildtype=debugoptimized']) - -nice_version = meson.project_version() -version_arr = nice_version.split('.') -version_major = version_arr[0] -version_minor = version_arr[1] -version_micro = version_arr[2] -if version_arr.length() == 4 - version_nano = version_arr[3] -else - version_nano = 0 -endif - -# maintain compatibility with the previous libtool versioning -# libversion has 3 parts A.B.C -# A is the ABI version, change it if the ABI is broken, changing it resets B and C to 0. It matches soversion -# B is the ABI age, change it on new APIs that don't break existing ones, changing it resets C to 0 -# C is the revision, change on new updates that don't change APIs -soversion = 10 -libversion = '10.10.0' - -glib_req = '>= 2.54' -gnutls_req = '>= 2.12.0' -gupnp_igd_req = '>= 0.2.4' -gst_req = '>= 1.0.0' - -nice_datadir = join_paths(get_option('prefix'), get_option('datadir')) - -cc = meson.get_compiler('c') - -syslibs = [] - -if cc.get_id() == 'msvc' - add_project_arguments( - cc.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8 - language : 'c') -endif - -if host_machine.system() == 'windows' - syslibs += [cc.find_library('iphlpapi')] - syslibs += [cc.find_library('ws2_32')] -elif host_machine.system() == 'sunos' - add_project_arguments('-D_XOPEN_SOURCE=600', language: 'c') - add_project_arguments('-D__EXTENSIONS__=1', language: 'c') - # inet_pton() is only used by the tests - syslibs += [cc.find_library('nsl')] - if not cc.has_function('inet_pton') - libnsl = cc.find_library('nsl', required: false) - if libnsl.found() and cc.has_function('inet_pton', dependencies: libnsl) - syslibs += [libnsl] - endif - endif - if not cc.has_function('socket') - libsocket = cc.find_library('socket', required: false) - libinet = cc.find_library('inet', required: false) - if cc.has_function('socket', dependencies: libsocket) - syslibs += [libsocket] - elif cc.has_function('socket', dependencies: libinet) - syslibs += [libinet] - else - error('Could not find right library for socket() on Solaris') - endif - endif -endif - -if not cc.has_function('clock_gettime') - librt = cc.find_library('rt', required: false) - if cc.has_function('clock_gettime', dependencies: librt) - syslibs += [librt] - endif -endif - -glib_req_minmax_str = glib_req.split().get(1).underscorify() -add_project_arguments('-D_GNU_SOURCE', - '-DHAVE_CONFIG_H', - '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_' + glib_req_minmax_str, - '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_' + glib_req_minmax_str, - language: 'c') - -cdata = configuration_data() - -cdata.set_quoted('PACKAGE_STRING', meson.project_name()) -cdata.set_quoted('PACKAGE_NAME', meson.project_name()) -cdata.set_quoted('PACKAGE', meson.project_name()) -cdata.set_quoted('VERSION', meson.project_version()) - -cdata.set('NICEAPI_EXPORT', true, - description: 'Public library function implementation') - -# headers -foreach h : ['arpa/inet.h', 'net/in.h', 'netdb.h', 'ifaddrs.h', 'unistd.h'] - if cc.has_header(h) - define = 'HAVE_' + h.underscorify().to_upper() - cdata.set(define, 1) - endif -endforeach - -# functions -foreach f : ['poll', 'getifaddrs'] - if cc.has_function(f) - define = 'HAVE_' + f.underscorify().to_upper() - cdata.set(define, 1) - endif -endforeach - -if cc.has_argument('-fno-strict-aliasing') - add_project_arguments('-fno-strict-aliasing', language: 'c') -endif - -# Extra compiler warnings (FIXME: not sure this makes sense to keep like this) -warning_level = get_option('warning_level').to_int() -werror = get_option('werror') - -warnings = [] - -message('warning level: @0@'.format(warning_level)) -message('werror enabled: @0@'.format(werror)) - -if warning_level >= 2 - warnings += [ - '-Wundef', - '-Wnested-externs', - '-Wwrite-strings', - '-Wpointer-arith', - '-Wmissing-declarations', - '-Wmissing-prototypes', - '-Wstrict-prototypes', - '-Wredundant-decls', - '-Wno-unused-parameter', - '-Wno-missing-field-initializers', - '-Wdeclaration-after-statement', - '-Wformat=2', - '-Wold-style-definition', - '-Wcast-align', - '-Wformat-nonliteral', - '-Wformat-security', - ] -endif -if warning_level >= 3 - warnings += [ - '-Wsign-compare', - '-Wstrict-aliasing', - '-Wshadow', - '-Winline', - '-Wpacked', - '-Wmissing-format-attribute', - '-Winit-self', - '-Wredundant-decls', - '-Wmissing-include-dirs', - '-Wunused-but-set-variable', - '-Warray-bounds', - ] - warnings += [ - '-Wswitch-default', - '-Waggregate-return', - ] -endif -if werror - warnings += [ - '-Wno-suggest-attribute=format', - '-Wno-cast-function-type', - ] -endif - -foreach w : warnings - if cc.has_argument(w) - add_project_arguments(w, language: 'c') - endif -endforeach - -# Dependencies -gio_dep = dependency('gio-2.0', version: glib_req, - fallback: ['glib', 'libgio_dep']) -gio_deps = [gio_dep] -if gio_dep.type_name() == 'internal' - # A workaround for libgio_dep not having its dependencies correctly declared. - # Should be fixed in GLib 2.60. - gio_deps += [ - dependency('', fallback: ['glib', 'libglib_dep']), - dependency('', fallback: ['glib', 'libgmodule_dep']), - dependency('', fallback: ['glib', 'libgobject_dep']) - ] -endif -gthread_dep = dependency('gthread-2.0', - fallback: ['glib', 'libgthread_dep']) - -# Cryto library -opt_cryptolib = get_option('crypto-library') -message('Crypto librar requested: ' + opt_cryptolib) -if opt_cryptolib != 'openssl' - crypto_dep = dependency('gnutls', version: gnutls_req, required: false) - cdata.set('HAVE_GNUTLS', crypto_dep.found()) - if not crypto_dep.found() and opt_cryptolib == 'auto' - crypto_dep = dependency('openssl', required: false, - fallback: ['openssl', 'openssl_dep']) - cdata.set('HAVE_OPENSSL', crypto_dep.found()) - endif -else - crypto_dep = dependency('openssl', required: false) - cdata.set('HAVE_OPENSSL', crypto_dep.found()) - if not crypto_dep.found() and openssl == 'auto' - crypto_dep = dependency('gnutls', version: gnutls_req, required: false) - cdata.set('HAVE_GNUTLS', crypto_dep.found()) - endif -endif - -if not crypto_dep.found() and opt_cryptolib != 'gnutls' - # MSVC builds of OpenSSL does not generate pkg-config files, - # so we check for it manually here in this case, if we can't find those files - # Based on the CMake check for OpenSSL in CURL's CMakeLists.txt, - # on which headers we should check for - openssl_headers = [] - foreach h : ['crypto.h', 'engine.h', 'err.h', 'pem.h', - 'rsa.h', 'ssl.h', 'x509.h', 'rand.h', 'tls1.h'] - openssl_headers += 'openssl/' + h - endforeach - - # OpenSSL 1.1.x and 1.0.x (or earlier) have different .lib names, - # so we need to look for the correct pair - - # Find either libcrypto.lib (1.1.x) or libeay32.lib (1.0.x or earlier) first - libcrypto_dep = cc.find_library('crypto', required: false) - if libcrypto_dep.found() - libssl = 'ssl' - else - libcrypto_dep = cc.find_library('eay32', required: false) - libssl = 'ssleay32' - endif - - if libcrypto_dep.found() - # Find the corresponding SSL library depending on which crypto .lib we found - libssl_dep = cc.find_library(libssl, required: false, has_headers: openssl_headers) - endif - - if libcrypto_dep.found() and libssl_dep.found() - crypto_dep = [libcrypto_dep, libssl_dep] - endif -endif - -if not crypto_dep.found() - if opt_cryptolib == 'gnutls' - error('GnuTLS requested as crypto library, but not found') - elif opt_cryptolib == 'gnutls' - error('OpenSSL requested as crypto library, but not found') - else - error('Either GnuTLS or OpenSSL is required as crypto library, but neither was found') - endif -endif - -# GStreamer -gst_dep = dependency('gstreamer-base-1.0', version: gst_req, - required: get_option('gstreamer'), - fallback : ['gstreamer', 'gst_base_dep']) - -cdata.set('HAVE_GSTREAMER', gst_dep.found(), description: 'Build GStreamer plugin') - -# GUPnP IGD -gupnp_igd_dep = dependency('gupnp-igd-1.0', version: gupnp_igd_req, required: get_option('gupnp')) -cdata.set('HAVE_GUPNP', gupnp_igd_dep.found(), description: 'Use the GUPnP IGD library') - -libm = cc.find_library('m', required: false) - -nice_incs = include_directories('.', 'agent', 'random', 'socket', 'stun') - -nice_deps = gio_deps + [gthread_dep, crypto_dep, gupnp_igd_dep] + syslibs - -ignored_iface_prefix = get_option('ignored-network-interface-prefix') -if ignored_iface_prefix != [] - ignored_iface_prefix_quoted = [] - foreach i : ignored_iface_prefix - ignored_iface_prefix_quoted += '"' + i + '"' - endforeach - cdata.set('IGNORED_IFACE_PREFIX', ','.join(ignored_iface_prefix_quoted)) -endif - -gir = find_program('g-ir-scanner', required : get_option('introspection')) - -subdir('agent') -subdir('stun') -subdir('socket') -subdir('random') -subdir('nice') - -if gst_dep.found() - subdir('gst') -endif - -if build_machine.system() == 'windows' - message('Disabling gtk-doc while building on Windows') -else - if find_program('gtkdoc-scan', required: get_option('gtk_doc')).found() - subdir('docs/reference/libnice') - else - message('Not building documentation as gtk-doc was not found or disabled') - endif -endif - -if not get_option('tests').disabled() - subdir('tests') -endif - -if not get_option('examples').disabled() - subdir('examples') -endif - -add_test_setup('valgrind', - exe_wrapper: ['valgrind', - '--leak-check=full', - '--show-reachable=no', - '--error-exitcode=1', - '--suppressions='+meson.current_source_dir()+'/tests/libnice.supp', - '--num-callers=10'], - timeout_multiplier: 10, - env: ['CK_FORK=no'] - ) - -configure_file(output : 'config.h', configuration : cdata) diff --git a/meson_options.txt b/meson_options.txt deleted file mode 100644 index cd980cb..0000000 --- a/meson_options.txt +++ /dev/null @@ -1,17 +0,0 @@ -option('gupnp', type: 'feature', value: 'auto', - description: 'Enable or disable GUPnP IGD support') -option('gstreamer', type: 'feature', value: 'auto', - description: 'Enable or disable build of GStreamer plugins') -option('ignored-network-interface-prefix', type: 'array', value: ['docker', 'veth', 'virbr', 'vnet'], - description: 'Ignore network interfaces whose name starts with a string from this list in the ICE connection check algorithm. For example, "virbr" to ignore virtual bridge interfaces added by virtd, which do not help in finding connectivity.') -option('crypto-library', type: 'combo', choices : ['auto', 'gnutls', 'openssl'], value : 'auto') - -# Common feature options -option('examples', type : 'feature', value : 'auto', yield : true, - description: 'Build examples') -option('tests', type : 'feature', value : 'auto', yield : true, - description: 'Enable or disable unit tests') -option('gtk_doc', type : 'feature', value : 'disabled', yield : true, - description: 'Generate API documentation with gtk-doc') -option('introspection', type : 'feature', value : 'auto', yield : true, - description : 'Generate gobject-introspection bindings') diff --git a/nice/Makefile.am b/nice/Makefile.am deleted file mode 100644 index 089050d..0000000 --- a/nice/Makefile.am +++ /dev/null @@ -1,66 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2006, 2007 Collabora Ltd. -# (C) 2006, 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. - -include $(top_srcdir)/common.mk - -lib_LTLIBRARIES = libnice.la - -libnice_la_SOURCES = -libnice_la_DEPENDENCIES = \ - $(top_builddir)/agent/libagent.la \ - libnice.sym - -libnice_la_LIBADD = \ - $(GLIB_LIBS) \ - $(GUPNP_LIBS) \ - $(top_builddir)/agent/libagent.la - -libnice_la_LDFLAGS = \ - -export-symbols $(srcdir)/libnice.sym \ - $(LIBNICE_LT_LDFLAGS) - - -AM_CFLAGS = \ - $(LIBNICE_CFLAGS) \ - $(GLIB_CFLAGS) \ - -I $(top_srcdir) \ - -I $(top_srcdir)/agent \ - -I $(top_srcdir)/random \ - -I $(top_srcdir)/socket \ - -I $(top_srcdir)/stun - -test-symbols.sh:: - chmod +x $(srcdir)/$@ - -libnice-symbols-test.c: libnice.sym - rm -f $@ - while read s; do echo "void $$s(void) { }" ; done < $? > $@ - -libnice-symbols-test.o: libnice-symbols-test.c - $(CC) $(CFLAGS) -c -o $@ $? - -libnice.symbols: libnice-symbols-test.o - rm -f $@ - $(top_srcdir)/scripts/make-symbol-list.sh $? > $@ - -CLEANFILES += libnice.symbols libnice-symbols-test.c libnice-symbols-test.o - -check_SCRIPTS = test-symbols.sh -check_DATA = libnice.symbols - -TESTS = $(check_SCRIPTS) - -EXTRA_DIST = $(check_SCRIPTS) \ - libnice.sym libnice.ver \ - meson.build gen-map.py gen-def.py - -pkginclude_HEADERS = nice.h - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = nice.pc - diff --git a/nice/gen-def.py b/nice/gen-def.py deleted file mode 100644 index fb6116c..0000000 --- a/nice/gen-def.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -# -# gen-def.py LIBNICE.SYM -import os -import sys - -try: - sym_file = sys.argv[1] -except: - print('Usage: gen-def.py SYM-FILE') - exit(-1) - -f = open(os.path.join(sym_file), 'r') - -print('EXPORTS') -for line in f: - print(' ' + line.strip()) - -f.close() diff --git a/nice/gen-map.py b/nice/gen-map.py deleted file mode 100644 index da49e75..0000000 --- a/nice/gen-map.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 -# -# gen-map.py LIBNICE.SYM -import os -import sys - -try: - sym_file = sys.argv[1] -except: - print('Usage: gen-map.py SYM-FILE') - exit(-1) - -f = open(os.path.join(sym_file), 'r') - -print('''{ -global:''') - -for line in f: - print('\t' + line.strip() + ';') - -print('''local: - *; -};''') - -f.close() diff --git a/nice/libnice.sym b/nice/libnice.sym deleted file mode 100644 index 007be55..0000000 --- a/nice/libnice.sym +++ /dev/null @@ -1,164 +0,0 @@ -nice_address_copy_to_sockaddr -nice_address_dup -nice_address_equal -nice_address_equal_no_port -nice_address_free -nice_address_get_port -nice_address_init -nice_address_ip_version -nice_address_is_private -nice_address_is_valid -nice_address_new -nice_address_set_from_sockaddr -nice_address_set_from_string -nice_address_set_ipv4 -nice_address_set_ipv6 -nice_address_set_port -nice_address_to_string -nice_agent_add_local_address -nice_agent_add_stream -nice_agent_close_async -nice_agent_recv -nice_agent_recv_messages -nice_agent_recv_nonblocking -nice_agent_recv_messages_nonblocking -nice_agent_attach_recv -nice_agent_forget_relays -nice_agent_gather_candidates -nice_agent_generate_local_candidate_sdp -nice_agent_generate_local_sdp -nice_agent_generate_local_stream_sdp -nice_agent_get_component_state -nice_agent_get_default_local_candidate -nice_agent_get_io_stream -nice_agent_get_local_candidates -nice_agent_get_local_credentials -nice_agent_get_remote_candidates -nice_agent_get_selected_pair -nice_agent_get_selected_socket -nice_agent_get_sockets -nice_agent_get_stream_name -nice_agent_get_type -nice_agent_new -nice_agent_new_full -nice_agent_new_reliable -nice_agent_option_get_type -nice_agent_parse_remote_candidate_sdp -nice_agent_parse_remote_sdp -nice_agent_parse_remote_stream_sdp -nice_agent_peer_candidate_gathering_done -nice_agent_remove_stream -nice_agent_restart -nice_agent_restart_stream -nice_agent_send -nice_agent_send_messages_nonblocking -nice_agent_set_port_range -nice_agent_set_relay_info -nice_agent_set_remote_candidates -nice_agent_set_remote_credentials -nice_agent_set_local_credentials -nice_agent_set_selected_pair -nice_agent_set_selected_remote_candidate -nice_agent_set_software -nice_agent_set_stream_name -nice_agent_set_stream_tos -nice_candidate_copy -nice_candidate_equal_target -nice_candidate_free -nice_candidate_get_type -nice_candidate_new -nice_candidate_transport_get_type -nice_candidate_type_get_type -nice_compatibility_get_type -nice_component_state_get_type -nice_component_state_to_string -nice_component_type_get_type -nice_debug_disable -nice_debug_enable -nice_interfaces_get_ip_for_interface -nice_interfaces_get_local_interfaces -nice_interfaces_get_local_ips -nice_io_stream_new -nice_input_stream_new -nice_nomination_mode_get_type -nice_output_stream_new -nice_proxy_type_get_type -nice_relay_type_get_type -pseudo_tcp_debug_level_get_type -pseudo_tcp_set_debug_level -pseudo_tcp_shutdown_get_type -pseudo_tcp_socket_close -pseudo_tcp_socket_connect -pseudo_tcp_socket_get_error -pseudo_tcp_socket_get_next_clock -pseudo_tcp_socket_get_type -pseudo_tcp_socket_is_closed -pseudo_tcp_socket_is_closed_remotely -pseudo_tcp_socket_new -pseudo_tcp_socket_notify_clock -pseudo_tcp_socket_notify_mtu -pseudo_tcp_socket_notify_packet -pseudo_tcp_socket_recv -pseudo_tcp_socket_send -pseudo_tcp_socket_shutdown -pseudo_tcp_state_get_type -pseudo_tcp_write_result_get_type -stun_agent_build_unknown_attributes_error -stun_agent_default_validater -stun_agent_finish_message -stun_agent_forget_transaction -stun_agent_init -stun_agent_init_error -stun_agent_init_indication -stun_agent_init_request -stun_agent_init_response -stun_agent_set_software -stun_agent_validate -stun_debug_disable -stun_debug_enable -stun_message_append -stun_message_append32 -stun_message_append64 -stun_message_append_addr -stun_message_append_bytes -stun_message_append_error -stun_message_append_flag -stun_message_append_string -stun_message_append_xor_addr -stun_message_append_xor_addr_full -stun_message_find -stun_message_find32 -stun_message_find64 -stun_message_find_addr -stun_message_find_error -stun_message_find_flag -stun_message_find_string -stun_message_find_xor_addr -stun_message_find_xor_addr_full -stun_message_get_class -stun_message_get_method -stun_message_has_attribute -stun_message_has_cookie -stun_message_id -stun_message_init -stun_message_length -stun_message_validate_buffer_length -stun_optional -stun_strerror -stun_timer_refresh -stun_timer_remainder -stun_timer_start -stun_timer_start_reliable -stun_usage_bind_create -stun_usage_bind_keepalive -stun_usage_bind_process -stun_usage_bind_run -stun_usage_ice_conncheck_create -stun_usage_ice_conncheck_create_reply -stun_usage_ice_conncheck_priority -stun_usage_ice_conncheck_process -stun_usage_ice_conncheck_use_candidate -stun_usage_turn_create -stun_usage_turn_create_refresh -stun_usage_turn_process -stun_usage_turn_refresh_process diff --git a/nice/libnice.ver b/nice/libnice.ver deleted file mode 100644 index 1006e52..0000000 --- a/nice/libnice.ver +++ /dev/null @@ -1,11 +0,0 @@ - -libnice { -global: - nice_*; -}; - -HIDDEN { -local: - *; -}; - diff --git a/nice/meson.build b/nice/meson.build deleted file mode 100644 index 9c0cdd4..0000000 --- a/nice/meson.build +++ /dev/null @@ -1,67 +0,0 @@ -nice_gen_sources = [] -nice_link_args = [] - -# libnice.def -libnice_def = custom_target('libnice.def', - command: [find_program('gen-def.py'), '@INPUT@'], - input: 'libnice.sym', - output: 'libnice.def', - capture: true) - -# map file -mapfile = custom_target('libnice.map', - command: [find_program('gen-map.py'), '@INPUT@'], - input: 'libnice.sym', - output: 'libnice.map', - capture: true) -# We need to check with a file that exists at configure time! -if cc.has_link_argument('-Wl,--version-script,@0@/libnice.ver'.format(meson.current_source_dir())) - nice_link_args += ['-Wl,--version-script,@0@'.format(mapfile.full_path())] -endif - -libnice = library('nice', - link_whole: [libagent, libsocket, libstun, librandom], - dependencies: nice_deps, - version : libversion, - soversion : soversion, - vs_module_defs: libnice_def, - link_args: nice_link_args, - link_depends: mapfile, - install: true) - -install_headers('nice.h', subdir: 'nice') -nice_include = include_directories('.') - -# introspection -build_gir = gir.found() and not get_option('introspection').disabled() -if build_gir - nice_gen_sources += [ - gnome.generate_gir(libnice, - sources : [agent_headers, agent_sources], - namespace : 'Nice', - nsversion : '0.1', - identifier_prefix : 'Nice', - symbol_prefix: 'nice', - export_packages: 'nice', - includes: ['GObject-2.0', 'Gio-2.0'], - extra_args: ['--accept-unprefixed'], - install: true) - ] -endif - -libnice_dep = declare_dependency(link_with : libnice, - include_directories : [agent_include, nice_include], - # Everything that uses libnice needs this built to compile - sources : nice_gen_sources, - dependencies: nice_deps) - -# pkg-config file -pkg = import('pkgconfig') -upnp_enabled_string = gupnp_igd_dep.found() ? 'true' : 'false' -pkg.generate(libnice, - name: 'libnice', - filebase: 'nice', - subdirs: 'nice', - description: 'ICE library', - libraries: gio_dep, - variables: ['upnp_enabled=@0@'.format(upnp_enabled_string)]) diff --git a/nice/nice.h b/nice/nice.h deleted file mode 100644 index 5587ec4..0000000 --- a/nice/nice.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _NICE_H -#define _NICE_H - -#include "agent.h" -#include "interfaces.h" - -#endif /* _NICE_H */ - diff --git a/nice/nice.pc.in b/nice/nice.pc.in deleted file mode 100644 index 8805f0d..0000000 --- a/nice/nice.pc.in +++ /dev/null @@ -1,13 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -upnp_enabled=@UPNP_ENABLED@ - -Name: libnice -Description: ICE library -Version: @VERSION@ -Requires: @NICE_PACKAGES_PUBLIC@ @GUPNP_PACKAGES_PUBLIC@ -Requires.private: @NICE_PACKAGES_PRIVATE@ @GUPNP_PACKAGES_PRIVATE@ -Libs: -L${libdir} -lnice -Cflags: -I${includedir}/nice -I${includedir} diff --git a/nice/test-symbols.sh b/nice/test-symbols.sh deleted file mode 100755 index 621e0ea..0000000 --- a/nice/test-symbols.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -set -e - -if test -z "$srcdir"; then - srcdir=$(dirname $0) -fi - -check_symbols=$srcdir/../scripts/check-symbols.sh - -if ! test -f $check_symbols; then - echo "cannot find check-symbols.sh" - exit 1 -fi - -if ! test -f .libs/libnice.so; then - echo "no shared object found" >&2 - exit 77 -fi - -sh $check_symbols .libs/libnice.so libnice.symbols diff --git a/random/Makefile.am b/random/Makefile.am deleted file mode 100644 index b6f5d74..0000000 --- a/random/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2006, 2007 Collabora Ltd. -# (C) 2006, 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. - -include $(top_srcdir)/common.mk - -AM_CFLAGS = $(LIBNICE_CFLAGS) $(GLIB_CFLAGS) - -noinst_LTLIBRARIES = libnice-random.la - -libnice_random_la_SOURCES = \ - random.h \ - random.c \ - random-glib.h \ - random-glib.c - -check_PROGRAMS = test - -test_LDADD = libnice-random.la $(GLIB_LIBS) - -TESTS = $(check_PROGRAMS) - -EXTRA_DIST = meson.build diff --git a/random/meson.build b/random/meson.build deleted file mode 100644 index e3c3fa3..0000000 --- a/random/meson.build +++ /dev/null @@ -1,15 +0,0 @@ -librandom = static_library('nice-random', - 'random.c', 'random-glib.c', - c_args: ['-DG_LOG_DOMAIN="libnice-random"'], - include_directories: nice_incs, - dependencies: gio_deps + [gthread_dep], - install: false) - -if not get_option('tests').disabled() - test_exe = executable('nice-random-test', 'test.c', - include_directories: nice_incs, - dependencies: gio_deps + [gthread_dep], - link_with: librandom) - - test('nice-random', test_exe) -endif diff --git a/random/random-glib.c b/random/random-glib.c deleted file mode 100644 index 86da1a2..0000000 --- a/random/random-glib.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2008 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006-2008 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "random-glib.h" - -static void -rng_seed ( - G_GNUC_UNUSED - NiceRNG *rng, guint32 seed) -{ - (void)rng; - g_random_set_seed (seed); -} - -static void -rng_generate_bytes ( - G_GNUC_UNUSED - NiceRNG *rng, - guint len, - gchar *buf) -{ - guint i; - - (void)rng; - - for (i = 0; i < len; i++) - buf[i] = g_random_int_range (0, 256); -} - -static guint -rng_generate_int ( - G_GNUC_UNUSED - NiceRNG *rng, - guint low, - guint high) -{ - (void)rng; - return g_random_int_range (low, high); -} - -static void -rng_free (NiceRNG *rng) -{ - g_slice_free (NiceRNG, rng); -} - -NiceRNG * -nice_rng_glib_new (void) -{ - NiceRNG *ret; - - ret = g_slice_new0 (NiceRNG); - ret->seed = rng_seed; - ret->generate_bytes = rng_generate_bytes; - ret->generate_int = rng_generate_int; - ret->free = rng_free; - return ret; -} - -NiceRNG * -nice_rng_glib_new_predictable (void) -{ - NiceRNG *rng; - - rng = nice_rng_glib_new (); - rng->seed (rng, 0); - return rng; -} - diff --git a/random/random-glib.h b/random/random-glib.h deleted file mode 100644 index f8efc00..0000000 --- a/random/random-glib.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006-2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _RANDOM_GLIB_H -#define _RANDOM_GLIB_H - -#include - -#include "random.h" - -G_BEGIN_DECLS - -NiceRNG * -nice_rng_glib_new (void); - -NiceRNG * -nice_rng_glib_new_predictable (void); - -G_END_DECLS - -#endif /* _RANDOM_GLIB_H */ - diff --git a/random/random.c b/random/random.c deleted file mode 100644 index c818d75..0000000 --- a/random/random.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2008 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006-2008 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "random.h" -#include "random-glib.h" - -static NiceRNG * (*nice_rng_new_func) (void) = NULL; - -/* - * Creates a new random number generator instance. - */ -NiceRNG * -nice_rng_new (void) -{ - if (nice_rng_new_func == NULL) - return nice_rng_glib_new (); - else - return nice_rng_new_func (); -} - -/* - * Sets a new generator function. - */ -void -nice_rng_set_new_func (NiceRNG * (*func) (void)) -{ - nice_rng_new_func = func; -} - -/* - * Frees the random number generator instance. - * - * @param rng context - */ -void -nice_rng_free (NiceRNG *rng) -{ - rng->free (rng); -} - -/* - * Generates random octets. - * - * @param rng context - * @param len number of octets to product - * @param buf buffer to store the results - */ -void -nice_rng_generate_bytes (NiceRNG *rng, guint len, gchar *buf) -{ - rng->generate_bytes (rng, len, buf); -} - -/* - * Generates a random unsigned integer. - * - * @param rng context - * @param low closed lower bound - * @param high open upper bound - */ -guint -nice_rng_generate_int (NiceRNG *rng, guint low, guint high) -{ - return rng->generate_int (rng, low, high); -} - -/* - * Generates a stream of octets containing only characters - * with ASCII codecs of 0x41-5A (A-Z), 0x61-7A (a-z), - * 0x30-39 (0-9), 0x2b (+) and 0x2f (/). This matches - * the definition of 'ice-char' in ICE Ispecification, - * section 15.1 (ID-16). - * - * @param rng context - * @param len number of octets to product - * @param buf buffer to store the results - */ -void -nice_rng_generate_bytes_print (NiceRNG *rng, guint len, gchar *buf) -{ - guint i; - const gchar *chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789" - "+/"; - - for (i = 0; i < len; i++) - buf[i] = chars[nice_rng_generate_int (rng, 0, strlen (chars))]; -} - diff --git a/random/random.h b/random/random.h deleted file mode 100644 index 05bee51..0000000 --- a/random/random.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006-2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _RANDOM_H -#define _RANDOM_H - -#include - -G_BEGIN_DECLS - -typedef struct _NiceRNG NiceRNG; - -struct _NiceRNG { - void (*seed) (NiceRNG *src, guint32 seed); - void (*generate_bytes) (NiceRNG *src, guint len, gchar *buf); - guint (*generate_int) (NiceRNG *src, guint low, guint high); - void (*free) (NiceRNG *src); - gpointer priv; -}; - -NiceRNG * -nice_rng_new (void); - -void -nice_rng_set_new_func (NiceRNG * (*func) (void)); - -void -nice_rng_seed (NiceRNG *rng, guint32 seed); - -void -nice_rng_generate_bytes (NiceRNG *rng, guint len, gchar *buf); - -void -nice_rng_generate_bytes_print (NiceRNG *rng, guint len, gchar *buf); - -guint -nice_rng_generate_int (NiceRNG *rng, guint low, guint high); - -void -nice_rng_free (NiceRNG *rng); - -G_END_DECLS - -#endif // _RANDOM_H - diff --git a/random/test.c b/random/test.c deleted file mode 100644 index 6f657b4..0000000 --- a/random/test.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006-2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "random-glib.h" - -#define TEST_RNGSIZE 256 - -int -main (void) -{ - NiceRNG *rng; - gchar buf[TEST_RNGSIZE]; - - buf[TEST_RNGSIZE - 1] = '\0'; - - nice_rng_set_new_func (nice_rng_glib_new_predictable); - rng = nice_rng_new (); - - nice_rng_generate_bytes_print (rng, TEST_RNGSIZE - 1, buf); - /* g_debug ("%s", buf); */ - g_assert_cmpstr (buf, ==, "sv1AD7DnJTVykXGYYM6BmnXuYRlZNIJUzQzF+PvASjYxzdTTOngBJ5/gfK0Xj+Ly3ciAAk1Fmo0RPEpq6f4BBnp5jm3LuSbAOj1M5qULEGEv/0DMk0oOPUj6XPN1VwxFpjAfFeAxykiwdDiqNwnVJ/AKyr6/X7C5i+je7DSujURybOp6BkKWroLCzQg2AmTuqz48oNeY9CDeirNwoITfIaC40Ds9OgEDtL8WN5tL4QYdVuZQ85219Thogk775GV"); - - nice_rng_generate_bytes (rng, 4, buf); - buf[4] = 0; - g_assert_cmpstr (buf, ==, "\x1f\x0d\x47\xb8"); - - nice_rng_free (rng); - return 0; -} - diff --git a/scripts/check-symbols.sh b/scripts/check-symbols.sh deleted file mode 100755 index de5c18f..0000000 --- a/scripts/check-symbols.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh - -usage() -{ - echo "usage: $0 library symbol-file" - exit 1 -} - -test -n "$1" || usage -lib="$1" -test -n "$2" || usage -symbol_file="$2" - -make_symbol_list=`dirname $0`/make-symbol-list.sh -test -f "$make_symbol_list" || exit 1 - -if ! test -f "$symbol_file"; then - echo "$symbol_file doesn't exist" - exit 1 -fi - -diff=`sh $make_symbol_list "$lib" | \ - diff -uB "$symbol_file" - | tail -n +3` - -# stop if there are no differences -test -z "$diff" && exit 0 - -echo "symbols for $lib changed" - -if echo "$diff" | grep -q '^-'; then - echo " missing:" - echo "$diff" | grep '^-' | cut -b 2- | \ - xargs -i echo " " "{}" -fi - -if echo "$diff" | grep -q '^+'; then - echo " extra:" - echo "$diff" | grep '^+' | cut -b 2- | \ - xargs -i echo " " "{}" -fi - -exit 1 - diff --git a/scripts/lcov.mk b/scripts/lcov.mk deleted file mode 100644 index d6b64c7..0000000 --- a/scripts/lcov.mk +++ /dev/null @@ -1,28 +0,0 @@ - -# ccache breaks -fprofile-arcs -export CCACHE_DISABLE=1 - -OUT=lcov - -lcov-clean: - $(MAKE) clean - find -name "*.gcno" -o -name "*.gcda" -exec rm '{}' ';' - rm -rf $(OUT) - -lcov-build: - $(MAKE) CFLAGS="-O0 -fprofile-arcs -ftest-coverage" LDFLAGS="-lgcov" check - -lcov-report: - # hack: move gcov file from libraries back to source directory - for dir in `find -name .libs`; do \ - (cd `dirname $$dir`; mv .libs/*.gc?? . || true) 2>/dev/null; \ - done - - mkdir -p $(OUT) - lcov -d . -c >$(OUT)/lcov.info 2>/dev/null - lcov -l $(OUT)/lcov.info 2>/dev/null |\ - egrep '(^/usr|/test.*\.c)' |\ - cut -d: -f1 >$(OUT)/lcov.remove - lcov -r $(OUT)/lcov.info `cat $(OUT)/lcov.remove` 2>/dev/null >$(OUT)/lcov.info.clean - genhtml -o lcov $(OUT)/lcov.info.clean - diff --git a/scripts/lcov.sh b/scripts/lcov.sh deleted file mode 100755 index 4b56fbc..0000000 --- a/scripts/lcov.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -make -f scripts/lcov.mk lcov-clean && \ -make -f scripts/lcov.mk lcov-build && \ -make -f scripts/lcov.mk lcov-report diff --git a/scripts/make-symbol-list.sh b/scripts/make-symbol-list.sh deleted file mode 100755 index ab68a7a..0000000 --- a/scripts/make-symbol-list.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -test -n "$1" || exit 1 -nm --print-file-name --defined-only --extern-only "$1" | \ - cut -d ' ' -f 2,3 | \ - grep -v '^[rA]' | \ - sort diff --git a/scripts/valgrind-test-driver b/scripts/valgrind-test-driver deleted file mode 100755 index 5b660ee..0000000 --- a/scripts/valgrind-test-driver +++ /dev/null @@ -1,162 +0,0 @@ -#! /bin/sh -# test-driver - basic testsuite driver script. - -scriptversion=2017-04-04.22; # UTC - -# Copyright (C) 2011-2014 Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# This file is maintained in Automake, please report -# bugs to or send patches to -# . - -# Make unconditional expansion of undefined variables an error. This -# helps a lot in preventing typo-related bugs. -set -u - -usage_error () -{ - echo "$0: $*" >&2 - print_usage >&2 - exit 2 -} - -print_usage () -{ - cat <$log_file 2>&1 -else - "$@" >$log_file 2>&1 -fi -estatus=$? - -if test $enable_hard_errors = no && test $estatus -eq 99; then - tweaked_estatus=1 -else - tweaked_estatus=$estatus -fi - -case $tweaked_estatus:$expect_failure in - 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; - 0:*) col=$grn res=PASS recheck=no gcopy=no;; - 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; - 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; - *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; - *:*) col=$red res=FAIL recheck=yes gcopy=yes;; -esac - -# Report the test outcome and exit status in the logs, so that one can -# know whether the test passed or failed simply by looking at the '.log' -# file, without the need of also peaking into the corresponding '.trs' -# file (automake bug#11814). -echo "$res $test_name (exit status: $estatus)" >>$log_file - -# Report outcome to console. -echo "${col}${res}${std}: $test_name" - -# Register the test result, and other relevant metadata. -echo ":test-result: $res" > $trs_file -echo ":global-test-result: $res" >> $trs_file -echo ":recheck: $recheck" >> $trs_file -echo ":copy-in-global-log: $gcopy" >> $trs_file - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" -# time-stamp-end: "; # UTC" -# End: diff --git a/socket/Makefile.am b/socket/Makefile.am deleted file mode 100644 index 2560f17..0000000 --- a/socket/Makefile.am +++ /dev/null @@ -1,45 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2006, 2007 Collabora Ltd. -# (C) 2006, 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. - -include $(top_srcdir)/common.mk - -AM_CFLAGS = \ - -DG_LOG_DOMAIN=\"libnice-socket\" \ - $(LIBNICE_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(GUPNP_CFLAGS) \ - -I $(top_srcdir)/random \ - -I $(top_srcdir)/agent \ - -I $(top_srcdir)/ - -noinst_LTLIBRARIES = libsocket.la - -libsocket_la_SOURCES = \ - socket.h \ - socket-priv.h \ - socket.c \ - udp-bsd.h \ - udp-bsd.c \ - tcp-bsd.h \ - tcp-bsd.c \ - tcp-active.h \ - tcp-active.c \ - tcp-passive.h \ - tcp-passive.c \ - pseudossl.h \ - pseudossl.c \ - socks5.h \ - socks5.c \ - http.h \ - http.c \ - udp-turn.h \ - udp-turn.c \ - udp-turn-over-tcp.h \ - udp-turn-over-tcp.c - -EXTRA_DIST = meson.build diff --git a/socket/http.c b/socket/http.c deleted file mode 100644 index 23277f3..0000000 --- a/socket/http.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See - * http://en.wikipedia.org/wiki/Berkeley_sockets.) - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "http.h" -#include "agent-priv.h" -#include "socket-priv.h" - -#include -#include - - -#ifndef G_OS_WIN32 -#include -#endif - - -#define HTTP_USER_AGENT "libnice" - -typedef enum { - HTTP_STATE_INIT, - HTTP_STATE_HEADERS, - HTTP_STATE_BODY, - HTTP_STATE_CONNECTED, - HTTP_STATE_ERROR -} HttpState; - -typedef struct { - HttpState state; - NiceSocket *base_socket; - NiceAddress addr; - gchar *username; - gchar *password; - GQueue send_queue; - - /* Ring buffer for receiving HTTP headers into before they’re parsed. */ - guint8 *recv_buf; - gsize recv_buf_length; /* allocation size of @recv_buf */ - gsize recv_buf_pos; /* offset from @recv_buf of the 0th byte in the buffer */ - gsize recv_buf_fill; /* number of bytes occupied in the buffer */ - - /* Parsed from the Content-Length header provided by the other endpoint. */ - gsize content_length; -} HttpPriv; - - -static void socket_close (NiceSocket *sock); -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages); -static gboolean socket_is_reliable (NiceSocket *sock); -static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr); -static void socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); -static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other); - -NiceSocket * -nice_http_socket_new (NiceSocket *base_socket, - NiceAddress *addr, gchar *username, gchar *password) -{ - HttpPriv *priv; - NiceSocket *sock = NULL; - - if (addr) { - sock = g_slice_new0 (NiceSocket); - sock->priv = priv = g_slice_new0 (HttpPriv); - - priv->base_socket = base_socket; - priv->addr = *addr; - priv->username = g_strdup (username); - priv->password = g_strdup (password); - priv->recv_buf = NULL; - priv->recv_buf_length = 0; - priv->recv_buf_pos = 0; - priv->recv_buf_fill = 0; - priv->content_length = 0; - - sock->type = NICE_SOCKET_TYPE_HTTP; - sock->fileno = priv->base_socket->fileno; - sock->addr = priv->base_socket->addr; - sock->send_messages = socket_send_messages; - sock->send_messages_reliable = socket_send_messages_reliable; - sock->recv_messages = socket_recv_messages; - sock->is_reliable = socket_is_reliable; - sock->can_send = socket_can_send; - sock->set_writable_callback = socket_set_writable_callback; - sock->is_based_on = socket_is_based_on; - sock->close = socket_close; - - /* Send HTTP CONNECT */ - { - gchar *msg = NULL; - gchar *credential = NULL; - gchar host[INET6_ADDRSTRLEN]; - gint port = nice_address_get_port (&priv->addr); - GOutputVector local_bufs; - NiceOutputMessage local_messages; - - nice_address_to_string (&priv->addr, host); - - if (username) { - gchar * userpass = g_strdup_printf ("%s:%s", username, - password ? password : ""); - gchar * auth = g_base64_encode ((guchar *)userpass, strlen (userpass)); - credential = g_strdup_printf ("Proxy-Authorization: Basic %s\r\n", auth); - g_free (auth); - g_free (userpass); - } - msg = g_strdup_printf ("CONNECT %s:%d HTTP/1.0\r\n" - "Host: %s\r\n" - "User-Agent: %s\r\n" - "Content-Length: 0\r\n" - "Proxy-Connection: Keep-Alive\r\n" - "Connection: Keep-Alive\r\n" - "Cache-Control: no-cache\r\n" - "Pragma: no-cache\r\n" - "%s\r\n", host, port, host, HTTP_USER_AGENT, - credential? credential : "" ); - g_free (credential); - - local_bufs.buffer = msg; - local_bufs.size = strlen (msg); - local_messages.buffers = &local_bufs; - local_messages.n_buffers = 1; - - nice_socket_send_messages_reliable (priv->base_socket, NULL, - &local_messages, 1); - priv->state = HTTP_STATE_INIT; - g_free (msg); - } - } - - return sock; -} - - -static void -socket_close (NiceSocket *sock) -{ - HttpPriv *priv = sock->priv; - - if (priv->base_socket) - nice_socket_free (priv->base_socket); - - if (priv->username) - g_free (priv->username); - - if (priv->password) - g_free (priv->password); - - if (priv->recv_buf) - g_free (priv->recv_buf); - - nice_socket_free_send_queue (&priv->send_queue); - - g_slice_free(HttpPriv, sock->priv); - sock->priv = NULL; -} - -static void -assert_ring_buffer_valid (HttpPriv *priv) -{ - g_assert_cmpint (priv->recv_buf_fill, <=, priv->recv_buf_length); - g_assert (priv->recv_buf_pos == 0 || - priv->recv_buf_pos < priv->recv_buf_length); - g_assert (priv->recv_buf_length == 0 || priv->recv_buf != NULL); -} - -/* Pops up to @buffer_length bytes off the ring buffer and copies them into - * @buffer. Returns the number of bytes copied. */ -static gsize -memcpy_ring_buffer_to_buffer (HttpPriv *priv, - guint8 *buffer, gsize buffer_length) -{ - gsize len, consumed = 0; - gboolean has_wrapped; - - has_wrapped = - (priv->recv_buf_pos + priv->recv_buf_fill) > priv->recv_buf_length; - - if (has_wrapped) { - len = MIN (priv->recv_buf_length - priv->recv_buf_pos, buffer_length); - memcpy (buffer, priv->recv_buf + priv->recv_buf_pos, len); - consumed += len; - - buffer += len; - buffer_length -= len; - - len = MIN (priv->recv_buf_fill - len, buffer_length); - memcpy (buffer, priv->recv_buf, len); - consumed += len; - } else { - len = MIN (priv->recv_buf_fill, buffer_length); - memcpy (buffer, priv->recv_buf + priv->recv_buf_pos, len); - consumed += len; - } - - priv->recv_buf_pos = - (priv->recv_buf_pos + consumed) % priv->recv_buf_length; - priv->recv_buf_fill -= consumed; - - return consumed; -} - -/* Returns the number of messages touched. Silently drops any data from @buffer - * which doesn’t fit in @messages. Updates the ring buffer to pop the copied - * data off it. Treats all #GInputVectors in @messages the same; there is no - * differentiation between different #NiceInputMessages. */ -static gint -memcpy_ring_buffer_to_input_messages (HttpPriv *priv, - NiceInputMessage *messages, guint n_messages) -{ - guint i, j; - - for (i = 0; priv->recv_buf_fill > 0 && i < n_messages; i++) { - NiceInputMessage *message = &messages[i]; - - for (j = 0; - priv->recv_buf_fill > 0 && - ((message->n_buffers >= 0 && j < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[j].buffer != NULL)); - j++) { - message->buffers[j].size = - memcpy_ring_buffer_to_buffer (priv, - message->buffers[j].buffer, message->buffers[j].size); - } - } - - return i; -} - -/* FIXME: The current implementation of socket_recv_message() is a fast - * pass-through to nice_socket_recv_message() if the HTTP socket is connected, - * but is a slow state machine otherwise, using multiple memcpy()s. Spruce it up - * to better to use the recv_messages to avoid the memcpy()s. */ -static gint -socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages) -{ - HttpPriv *priv = sock->priv; - gint ret = -1; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - if (priv->state == HTTP_STATE_CONNECTED) { - guint i; - - /* Fast path: pass through to the base socket once we’re connected. */ - if (priv->base_socket) { - ret = nice_socket_recv_messages (priv->base_socket, - recv_messages, n_recv_messages); - } - - if (ret <= 0) - return ret; - - /* After successfully receiving into at least one NiceInputMessage, - * update the from address in each valid NiceInputMessage. */ - for (i = 0; i < (guint) ret; i++) { - if (recv_messages[i].from != NULL) - *recv_messages[i].from = priv->addr; - } - - return ret; - } else { - /* Slow path: read into a local ring buffer until we’re parsed enough of the - * headers. Double the buffer in size every time it fills up. */ - gboolean has_wrapped; - GInputVector local_recv_bufs[2]; - NiceInputMessage local_recv_message = { local_recv_bufs, 2, NULL, 0 }; - - /* Has the buffer filled up? Start with an initial buffer of 1KB, which - * should cover the average size of HTTP response headers. Source: - * http://dev.chromium.org/spdy/spdy-whitepaper */ - if (priv->recv_buf_fill == priv->recv_buf_length) { - priv->recv_buf_length = MAX (priv->recv_buf_length * 2, 1024); - priv->recv_buf = g_realloc (priv->recv_buf, priv->recv_buf_length); - } - - assert_ring_buffer_valid (priv); - - /* Read some data into the buffer. Use two GInputVectors: one for the tail - * of the buffer and one for the head. */ - has_wrapped = - (priv->recv_buf_pos + priv->recv_buf_fill) > priv->recv_buf_length; - - if (has_wrapped) { - local_recv_bufs[0].buffer = - priv->recv_buf + (priv->recv_buf_pos + priv->recv_buf_fill) % - priv->recv_buf_length; - local_recv_bufs[0].size = priv->recv_buf_length - priv->recv_buf_fill; - local_recv_bufs[1].buffer = NULL; - local_recv_bufs[1].size = 0; - } else { - local_recv_bufs[0].buffer = - priv->recv_buf + priv->recv_buf_pos + priv->recv_buf_fill; - local_recv_bufs[0].size = - priv->recv_buf_length - (priv->recv_buf_pos + priv->recv_buf_fill); - local_recv_bufs[1].buffer = priv->recv_buf; - local_recv_bufs[1].size = priv->recv_buf_pos; - } - - if (priv->base_socket) { - ret = nice_socket_recv_messages (priv->base_socket, - &local_recv_message, 1); - } - - if (ret <= 0) - return ret; - - /* Update the buffer’s metadata. */ - priv->recv_buf_fill += local_recv_message.length; - assert_ring_buffer_valid (priv); - - /* Fall through and try parsing the newly received data. */ - } - -#define GET_BYTE(pos) \ - priv->recv_buf[(pos + priv->recv_buf_pos) % priv->recv_buf_length] -#define EAT_WHITESPACE(pos) \ - while (pos < priv->recv_buf_fill && GET_BYTE(pos) == ' ') \ - pos++; \ - if (pos >= priv->recv_buf_fill) \ - goto not_enough_data; - -retry: - nice_debug ("Receiving from HTTP proxy (state %d) : %" G_GSSIZE_FORMAT " \n" - "'%s'", priv->state, priv->recv_buf_fill, - priv->recv_buf + priv->recv_buf_pos); - - switch (priv->state) { - case HTTP_STATE_INIT: - { - /* This is a logical position in the recv_buf; add - * (priv->recv_buf + priv->recv_buf_pos) to get the actual byte in - * memory. */ - guint pos = 0; - - /* Eat leading whitespace and check we have enough data. */ - EAT_WHITESPACE (pos); - - if (pos + 7 > priv->recv_buf_fill) - goto not_enough_data; - if (GET_BYTE (pos + 0) != 'H' || - GET_BYTE (pos + 1) != 'T' || - GET_BYTE (pos + 2) != 'T' || - GET_BYTE (pos + 3) != 'P' || - GET_BYTE (pos + 4) != '/' || - GET_BYTE (pos + 5) != '1' || - GET_BYTE (pos + 6) != '.') - goto error; - pos += 7; - - if (pos >= priv->recv_buf_fill) - goto not_enough_data; - if (GET_BYTE (pos) != '0' && GET_BYTE (pos) != '1') - goto error; - pos++; - - /* Make sure we have a space after the HTTP version */ - if (pos >= priv->recv_buf_fill) - goto not_enough_data; - if (GET_BYTE (pos) != ' ') - goto error; - - EAT_WHITESPACE (pos); - - /* Check for a successful 2xx code */ - if (pos + 3 > priv->recv_buf_fill) - goto not_enough_data; - if (GET_BYTE (pos) != '2' || - GET_BYTE (pos + 1) < '0' || GET_BYTE (pos + 1) > '9' || - GET_BYTE (pos + 2) < '0' || GET_BYTE (pos + 2) > '9') - goto error; - - /* Clear any trailing chars */ - while (pos + 1 < priv->recv_buf_fill && - GET_BYTE (pos) != '\r' && GET_BYTE (pos + 1) != '\n') - pos++; - if (pos + 1 >= priv->recv_buf_fill) - goto not_enough_data; - pos += 2; - - /* Consume the data we just parsed. */ - priv->recv_buf_pos = (priv->recv_buf_pos + pos) % priv->recv_buf_length; - priv->recv_buf_fill -= pos; - - priv->content_length = 0; - priv->state = HTTP_STATE_HEADERS; - - goto retry; - } - break; - case HTTP_STATE_HEADERS: - { - guint pos = 0; - - if (pos + 15 < priv->recv_buf_fill && - (GET_BYTE (pos + 0) == 'C' || GET_BYTE (pos + 0) == 'c') && - (GET_BYTE (pos + 1) == 'o' || GET_BYTE (pos + 1) == 'O') && - (GET_BYTE (pos + 2) == 'n' || GET_BYTE (pos + 2) == 'N') && - (GET_BYTE (pos + 3) == 't' || GET_BYTE (pos + 3) == 'T') && - (GET_BYTE (pos + 4) == 'e' || GET_BYTE (pos + 4) == 'E') && - (GET_BYTE (pos + 5) == 'n' || GET_BYTE (pos + 5) == 'N') && - (GET_BYTE (pos + 6) == 't' || GET_BYTE (pos + 6) == 'T') && - GET_BYTE (pos + 7) == '-' && - (GET_BYTE (pos + 8) == 'L' || GET_BYTE (pos + 8) == 'l') && - (GET_BYTE (pos + 9) == 'e' || GET_BYTE (pos + 9) == 'E') && - (GET_BYTE (pos + 10) == 'n' || GET_BYTE (pos + 10) == 'N') && - (GET_BYTE (pos + 11) == 'g' || GET_BYTE (pos + 11) == 'G') && - (GET_BYTE (pos + 12) == 't' || GET_BYTE (pos + 12) == 'T') && - (GET_BYTE (pos + 13) == 'h' || GET_BYTE (pos + 13) == 'H') && - GET_BYTE (pos + 14) == ':') { - /* Found a Content-Length header. Parse and store the value. Note that - * the HTTP standard allows for arbitrarily-big content lengths. We - * limit it to G_MAXSIZE for sanity’s sake. - * - * The code below is equivalent to strtoul(input, NULL, 10), but - * operates on a ring buffer. */ - pos += 15; - EAT_WHITESPACE (pos); - priv->content_length = 0; - - while (TRUE) { - guint8 byte = GET_BYTE (pos); - gint val = g_ascii_digit_value (byte); - - if (byte == '\r') { - /* Reached the end of the value; fall out to the code below which - * will grab the \n. */ - break; - } else if (val == -1) { - priv->content_length = 0; - goto error; - } - - /* Check for overflow. Don’t flag it as an error; just fall through - * to the code below which will skip to the \r\n. */ - if (priv->content_length > G_MAXSIZE / 10 || - priv->content_length * 10 > G_MAXSIZE - val) { - priv->content_length = 0; - break; - } - - priv->content_length = (priv->content_length * 10) + val; - - if (pos + 1 > priv->recv_buf_fill) - goto not_enough_data; - pos++; - } - } - - /* Skip over the header. */ - while (pos + 1 < priv->recv_buf_fill && - GET_BYTE (pos) != '\r' && GET_BYTE (pos + 1) != '\n') - pos++; - - nice_debug ("pos = %u, fill = %" G_GSSIZE_FORMAT, - pos, priv->recv_buf_fill); - - if (pos + 1 >= priv->recv_buf_fill) - goto not_enough_data; - pos += 2; - - /* Consume the data we just parsed. */ - priv->recv_buf_pos = (priv->recv_buf_pos + pos) % priv->recv_buf_length; - priv->recv_buf_fill -= pos; - - if (pos == 2) - priv->state = HTTP_STATE_BODY; - - goto retry; - } - break; - case HTTP_STATE_BODY: - { - gsize consumed; - - if (priv->content_length == 0) { - priv->state = HTTP_STATE_CONNECTED; - goto retry; - } - - if (priv->recv_buf_fill == 0) - goto not_enough_data; - - consumed = MIN (priv->content_length, priv->recv_buf_fill); - - priv->recv_buf_pos = - (priv->recv_buf_pos + consumed) % priv->recv_buf_length; - priv->recv_buf_fill -= consumed; - priv->content_length -= consumed; - - goto retry; - } - break; - case HTTP_STATE_CONNECTED: - { - gsize len; - - len = memcpy_ring_buffer_to_input_messages (priv, - recv_messages, n_recv_messages); - - /* Send the pending data */ - nice_socket_flush_send_queue (priv->base_socket, - &priv->send_queue); - - return len; - } - break; - case HTTP_STATE_ERROR: - default: - /* Unknown status */ - goto error; - } - - not_enough_data: - return 0; - - error: - nice_debug ("http error"); - if (priv->base_socket) - nice_socket_free (priv->base_socket); - priv->base_socket = NULL; - priv->state = HTTP_STATE_ERROR; - - return -1; -} - -static gint -socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - HttpPriv *priv = sock->priv; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - if (priv->state == HTTP_STATE_CONNECTED) { - /* Fast path. */ - if (!priv->base_socket) - return -1; - - return nice_socket_send_messages (priv->base_socket, to, messages, - n_messages); - } else if (priv->state == HTTP_STATE_ERROR) { - return -1; - } else { - return 0; - } - - return n_messages; -} - -static gint -socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - HttpPriv *priv = sock->priv; - - if (priv->state == HTTP_STATE_CONNECTED) { - /* Fast path. */ - if (!priv->base_socket) - return -1; - - return nice_socket_send_messages_reliable (priv->base_socket, to, messages, - n_messages); - } else if (priv->state == HTTP_STATE_ERROR) { - return -1; - } else { - nice_socket_queue_send (&priv->send_queue, to, messages, n_messages); - } - - return n_messages; -} - -static gboolean -socket_is_reliable (NiceSocket *sock) -{ - HttpPriv *priv = sock->priv; - - return nice_socket_is_reliable (priv->base_socket); -} - -static gboolean -socket_can_send (NiceSocket *sock, NiceAddress *addr) -{ - HttpPriv *priv = sock->priv; - - return nice_socket_can_send (priv->base_socket, addr); -} - -static void -socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data) -{ - HttpPriv *priv = sock->priv; - - nice_socket_set_writable_callback (priv->base_socket, callback, user_data); -} - -static gboolean -socket_is_based_on (NiceSocket *sock, NiceSocket *other) -{ - HttpPriv *priv = sock->priv; - - return (sock == other) || - (priv && nice_socket_is_based_on (priv->base_socket, other)); -} diff --git a/socket/http.h b/socket/http.h deleted file mode 100644 index 7f095a0..0000000 --- a/socket/http.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _HTTP_H -#define _HTTP_H - -#include "socket.h" -#include "agent.h" - -G_BEGIN_DECLS - - -NiceSocket * -nice_http_socket_new (NiceSocket *base_socket, - NiceAddress *addr, gchar *username, gchar *password); - - -G_END_DECLS - -#endif /* _HTTP_H */ - diff --git a/socket/meson.build b/socket/meson.build deleted file mode 100644 index e6da31d..0000000 --- a/socket/meson.build +++ /dev/null @@ -1,18 +0,0 @@ -socket_sources = [ - 'socket.c', - 'udp-bsd.c', - 'tcp-bsd.c', - 'tcp-active.c', - 'tcp-passive.c', - 'pseudossl.c', - 'socks5.c', - 'http.c', - 'udp-turn.c', - 'udp-turn-over-tcp.c', -] - -libsocket = static_library('socket', socket_sources, - c_args: ['-DG_LOG_DOMAIN="libnice-socket"'], - include_directories: nice_incs, - dependencies: nice_deps, - install: false) diff --git a/socket/pseudossl.c b/socket/pseudossl.c deleted file mode 100644 index 052725c..0000000 --- a/socket/pseudossl.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See - * http://en.wikipedia.org/wiki/Berkeley_sockets.) - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "pseudossl.h" -#include "agent-priv.h" -#include "socket-priv.h" - -#include - -#ifndef G_OS_WIN32 -#include -#endif - -typedef struct { - gboolean handshaken; - NiceSocket *base_socket; - GQueue send_queue; - NicePseudoSSLSocketCompatibility compatibility; -} PseudoSSLPriv; - - -static const gchar SSL_SERVER_GOOGLE_HANDSHAKE[] = { - 0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00, - 0x46, 0x03, 0x01, 0x42, 0x85, 0x45, 0xa7, 0x27, - 0xa9, 0x5d, 0xa0, 0xb3, 0xc5, 0xe7, 0x53, 0xda, - 0x48, 0x2b, 0x3f, 0xc6, 0x5a, 0xca, 0x89, 0xc1, - 0x58, 0x52, 0xa1, 0x78, 0x3c, 0x5b, 0x17, 0x46, - 0x00, 0x85, 0x3f, 0x20, 0x0e, 0xd3, 0x06, 0x72, - 0x5b, 0x5b, 0x1b, 0x5f, 0x15, 0xac, 0x13, 0xf9, - 0x88, 0x53, 0x9d, 0x9b, 0xe8, 0x3d, 0x7b, 0x0c, - 0x30, 0x32, 0x6e, 0x38, 0x4d, 0xa2, 0x75, 0x57, - 0x41, 0x6c, 0x34, 0x5c, 0x00, 0x04, 0x00}; - -static const gchar SSL_CLIENT_GOOGLE_HANDSHAKE[] = { - 0x80, 0x46, 0x01, 0x03, 0x01, 0x00, 0x2d, 0x00, - 0x00, 0x00, 0x10, 0x01, 0x00, 0x80, 0x03, 0x00, - 0x80, 0x07, 0x00, 0xc0, 0x06, 0x00, 0x40, 0x02, - 0x00, 0x80, 0x04, 0x00, 0x80, 0x00, 0x00, 0x04, - 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, 0x00, 0xfe, - 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, 0x00, - 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, - 0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc, - 0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea}; - -static const gchar SSL_SERVER_MSOC_HANDSHAKE[] = { - 0x16, 0x03, 0x01, 0x00, 0x4e, 0x02, 0x00, 0x00, - 0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0e, - 0x00, 0x00, 0x00}; - -static const gchar SSL_CLIENT_MSOC_HANDSHAKE[] = { - 0x16, 0x03, 0x01, 0x00, 0x2d, 0x01, 0x00, 0x00, - 0x29, 0x03, 0x01, 0xc1, 0xfc, 0xd5, 0xa3, 0x6d, - 0x93, 0xdd, 0x7e, 0x0b, 0x45, 0x67, 0x3f, 0xec, - 0x79, 0x85, 0xfb, 0xbc, 0x3f, 0xd6, 0x60, 0xc2, - 0xce, 0x84, 0x85, 0x08, 0x1b, 0x81, 0x21, 0xbc, - 0xaa, 0x10, 0xfb, 0x00, 0x00, 0x02, 0x00, 0x18, - 0x01, 0x00}; - -static void socket_close (NiceSocket *sock); -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages); -static gboolean socket_is_reliable (NiceSocket *sock); -static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr); -static void socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); -static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other); - -NiceSocket * -nice_pseudossl_socket_new (NiceSocket *base_socket, - NicePseudoSSLSocketCompatibility compatibility) -{ - PseudoSSLPriv *priv; - NiceSocket *sock; - const gchar *buf; - guint len; - - if (compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC) { - buf = SSL_CLIENT_MSOC_HANDSHAKE; - len = sizeof(SSL_CLIENT_MSOC_HANDSHAKE); - } else if (compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE) { - buf = SSL_CLIENT_GOOGLE_HANDSHAKE; - len = sizeof(SSL_CLIENT_GOOGLE_HANDSHAKE); - } else { - return NULL; - } - - sock = g_slice_new0 (NiceSocket); - sock->priv = priv = g_slice_new0 (PseudoSSLPriv); - - priv->handshaken = FALSE; - priv->base_socket = base_socket; - priv->compatibility = compatibility; - - sock->type = NICE_SOCKET_TYPE_PSEUDOSSL; - sock->fileno = priv->base_socket->fileno; - sock->addr = priv->base_socket->addr; - sock->send_messages = socket_send_messages; - sock->send_messages_reliable = socket_send_messages_reliable; - sock->recv_messages = socket_recv_messages; - sock->is_reliable = socket_is_reliable; - sock->can_send = socket_can_send; - sock->set_writable_callback = socket_set_writable_callback; - sock->is_based_on = socket_is_based_on; - sock->close = socket_close; - - /* We send 'to' NULL because it will always be to an already connected - * TCP base socket, which ignores the destination */ - nice_socket_send_reliable (priv->base_socket, NULL, len, buf); - - return sock; -} - - -static void -socket_close (NiceSocket *sock) -{ - PseudoSSLPriv *priv = sock->priv; - - if (priv->base_socket) - nice_socket_free (priv->base_socket); - - nice_socket_free_send_queue (&priv->send_queue); - - g_slice_free(PseudoSSLPriv, sock->priv); - sock->priv = NULL; -} - -static gboolean -server_handshake_valid(NiceSocket *sock, GInputVector *data, guint length) -{ - PseudoSSLPriv *priv = sock->priv; - - if (priv->compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC) { - if (length == sizeof(SSL_SERVER_MSOC_HANDSHAKE)) { - guint8 *buf = data->buffer; - - memset(buf + 11, 0, 32); - memset(buf + 44, 0, 32); - return memcmp(SSL_SERVER_MSOC_HANDSHAKE, data->buffer, - sizeof(SSL_SERVER_MSOC_HANDSHAKE)) == 0; - } - return FALSE; - } else { - return length == sizeof(SSL_SERVER_GOOGLE_HANDSHAKE) && - memcmp(SSL_SERVER_GOOGLE_HANDSHAKE, data->buffer, - sizeof(SSL_SERVER_GOOGLE_HANDSHAKE)) == 0; - } -} - -static gint -socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages) -{ - PseudoSSLPriv *priv = sock->priv; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - if (priv->handshaken) { - if (priv->base_socket) { - /* Fast path: once we’ve done the handshake, pass straight through to the - * base socket. */ - return nice_socket_recv_messages (priv->base_socket, - recv_messages, n_recv_messages); - } - } else { - guint8 data[MAX(sizeof(SSL_SERVER_GOOGLE_HANDSHAKE), - sizeof(SSL_SERVER_MSOC_HANDSHAKE))]; - gint ret = -1; - GInputVector local_recv_buf = { data, sizeof(data) }; - NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 }; - - - if (priv->compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC) { - local_recv_buf.size = sizeof(SSL_SERVER_MSOC_HANDSHAKE); - } else { - local_recv_buf.size = sizeof(SSL_SERVER_GOOGLE_HANDSHAKE); - } - if (priv->base_socket) { - ret = nice_socket_recv_messages (priv->base_socket, - &local_recv_message, 1); - } - - if (ret <= 0) { - return ret; - } else if (ret == 1 && server_handshake_valid(sock, &local_recv_buf, - local_recv_message.length)) { - priv->handshaken = TRUE; - nice_socket_flush_send_queue (priv->base_socket, &priv->send_queue); - } else { - if (priv->base_socket) - nice_socket_free (priv->base_socket); - priv->base_socket = NULL; - - return -1; - } - } - return 0; -} - -static gint -socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - PseudoSSLPriv *priv = sock->priv; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - if (priv->handshaken) { - /* Fast path: pass directly through to the base socket once the handshake is - * complete. */ - if (priv->base_socket == NULL) - return -1; - - return nice_socket_send_messages (priv->base_socket, to, messages, - n_messages); - } else { - return 0; - } - return n_messages; -} - - -static gint -socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - PseudoSSLPriv *priv = sock->priv; - - if (priv->handshaken) { - /* Fast path: pass directly through to the base socket once the handshake is - * complete. */ - if (priv->base_socket == NULL) - return -1; - - return nice_socket_send_messages_reliable (priv->base_socket, to, messages, - n_messages); - } else { - nice_socket_queue_send (&priv->send_queue, to, messages, n_messages); - } - return n_messages; -} - -static gboolean -socket_is_reliable (NiceSocket *sock) -{ - PseudoSSLPriv *priv = sock->priv; - - return nice_socket_is_reliable (priv->base_socket); -} - -static gboolean -socket_can_send (NiceSocket *sock, NiceAddress *addr) -{ - PseudoSSLPriv *priv = sock->priv; - - return nice_socket_can_send (priv->base_socket, addr); -} - -static void -socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data) -{ - PseudoSSLPriv *priv = sock->priv; - - nice_socket_set_writable_callback (priv->base_socket, callback, user_data); -} - -static gboolean -socket_is_based_on (NiceSocket *sock, NiceSocket *other) -{ - PseudoSSLPriv *priv = sock->priv; - - return (sock == other) || - (priv && nice_socket_is_based_on (priv->base_socket, other)); -} diff --git a/socket/pseudossl.h b/socket/pseudossl.h deleted file mode 100644 index e4cd879..0000000 --- a/socket/pseudossl.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _PSEUDOSSL_H -#define _PSEUDOSSL_H - -#include "socket.h" - -G_BEGIN_DECLS - -/** - * PseudosslCompatibility: - * @NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE: Use google compatible pseudossl - * @NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC: Use compatibility for Microsoft - * Office Communicator and Lync servers - * - * An enum to specify which pseudo SSL compatibility mode the #NiceSocket should - * use. - */ -typedef enum -{ - NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE = 0, - NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC, -} NicePseudoSSLSocketCompatibility; - -NiceSocket * -nice_pseudossl_socket_new (NiceSocket *base_socket, - NicePseudoSSLSocketCompatibility compatibility); - - -G_END_DECLS - -#endif /* _PSEUDOSSL_H */ - diff --git a/socket/socket-priv.h b/socket/socket-priv.h deleted file mode 100644 index 6e9f3f5..0000000 --- a/socket/socket-priv.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _SOCKET_PRIV_H -#define _SOCKET_PRIV_H - -#include "socket.h" - -G_BEGIN_DECLS - -/** - * nice_socket_queue_send: - * @send_queue: The queue to add to - * @to : Destination - * @messages: Messages to queue - * @n_messages: Number of messages to queue - * - * Queue messages to be sent later into the GQueue - */ -void nice_socket_queue_send (GQueue *send_queue, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); - -/** - * nice_socket_queue_send_with_callback: - * @send_queue: The queue to add to - * @message: The message to queue - * @message_offset: Number of bytes to skip in the message - * @message_len: Total length of the message - * @head: Whether to add the message to the head of the queue or the tail - * @gsock: The #GSocket to create the callback on - * @io_source: Pointer to #GSource pointer to store the created source - * @context: #GMainContext to attach the @io_source to - * @cb: Callback function to call when the @gsock is writable - * @user_data: User data for @cb - * - * Queue (partial) message to be sent later and create a source to call @cb - * when the @gsock becomes writable. - * The @message_offset can be used if a partial write happened and some bytes - * were already written, in which case @head should be set to TRUE to add the - * message to the head of the queue. - */ -void nice_socket_queue_send_with_callback (GQueue *send_queue, - const NiceOutputMessage *message, gsize message_offset, gsize message_len, - gboolean head, GSocket *gsock, GSource **io_source, GMainContext *context, - GSocketSourceFunc cb, gpointer user_data); - -/** - * nice_socket_flush_send_queue: - * @base_socket: Base socket to send on - * @send_queue: Queue to flush - * - * Send all the queued messages reliably to the base socket. We assume only - * reliable messages were queued and the underlying socket will handle the - * send. - */ -void nice_socket_flush_send_queue (NiceSocket *base_socket, GQueue *send_queue); - -/** - * nice_socket_flush_send_queue_to_socket: - * @gsock: GSocket to send on - * @send_queue: Queue to flush - * - * Send all the queued messages to the socket. If any message fails to be sent - * it will be readded to the queue and #FALSE will be returned, in which case - * the IO source must be kept to allow flushing the next time the socket - * is writable. - * If the queue gets flushed, #TRUE will be returned, in which case, the IO - * source should be destroyed. - * - * Returns: #TRUE if the queue was emptied, #FALSE if the socket would block. - */ -gboolean nice_socket_flush_send_queue_to_socket (GSocket *gsock, - GQueue *send_queue); - -/** - * nice_socket_free_send_queue: - * @send_queue: The send queue - * - * Frees every item in the send queue without sending them and empties the queue - */ -void nice_socket_free_send_queue (GQueue *send_queue); - -G_END_DECLS - -#endif /* _SOCKET_PRIV_H */ - diff --git a/socket/socket.c b/socket/socket.c deleted file mode 100644 index 860feea..0000000 --- a/socket/socket.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - - -#include - -#include "socket.h" -#include "socket-priv.h" -#include "agent-priv.h" - -#include - -#ifndef G_OS_WIN32 -#include -#endif - -typedef struct _NiceSocketQueuedSend NiceSocketQueuedSend; - -struct _NiceSocketQueuedSend { - guint8 *buf; /* owned */ - gsize length; - NiceAddress to; -}; - -/** - * nice_socket_recv_messages: - * @sock: a #NiceSocket - * @recv_messages: (array length=n_recv_messages) (out caller-allocates): - * array of #NiceInputMessages to return received messages in - * @n_recv_messages: number of elements in the @recv_messages array - * - * Receive up to @n_recv_messages message on the socket, in a non-reliable, - * non-blocking fashion. The total size of the buffers in each #NiceInputMessage - * must be big enough to contain an entire message (65536 bytes), or excess - * bytes will be silently dropped. - * - * On success, the number of messages received into @recv_messages is returned, - * which may be less than @n_recv_messages if the call would have blocked - * part-way through. If the socket would have blocked to begin with, or if - * @n_recv_messages is zero, zero is returned. On failure, a negative value is - * returned, but no further error information is available. Calling this - * function on a socket which has closed is an error, and a negative value is - * returned. - * - * If a positive N is returned, the first N messages in @recv_messages are - * valid. Each valid message is guaranteed to have a non-zero - * #NiceInputMessage::length, and its buffers are guaranteed to be filled - * sequentially up to that number of bytes If #NiceInputMessage::from was - * non-%NULL for a valid message, it may be set to the address of the sender of - * that received message. - * - * If the return value is zero or negative, the from return address and length - * in every #NiceInputMessage in @recv_messages are guaranteed to be unmodified. - * The buffers may have been modified. - * - * The base addresses and sizes of the buffers in a #NiceInputMessage are never - * modified. Neither is the base address of #NiceInputMessage::from, nor the - * base address and length of the #NiceInputMessage::buffers array. - * - * Returns: number of valid messages returned in @recv_messages, or a negative - * value on error - * - * Since: 0.1.5 - */ -gint -nice_socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages) -{ - g_return_val_if_fail (sock != NULL, -1); - g_return_val_if_fail (n_recv_messages == 0 || recv_messages != NULL, -1); - - return sock->recv_messages (sock, recv_messages, n_recv_messages); -} - -/** - * nice_socket_send_messages: - * @sock: a #NiceSocket - * @messages: (array length=n_messages) (in caller-allocates): - * array of #NiceOutputMessages containing the messages to send - * @n_messages: number of elements in the @messages array - * - * Send up to @n_messages on the socket, in a non-reliable, non-blocking - * fashion. The total size of the buffers in each #NiceOutputMessage - * must be at most the maximum UDP payload size (65535 bytes), or excess - * bytes will be silently dropped. - * - * On success, the number of messages transmitted from @messages is returned, - * which may be less than @n_messages if the call would have blocked - * part-way through. If the socket would have blocked to begin with, or if - * @n_messages is zero, zero is returned. On failure, a negative value is - * returned, but no further error information is available. Calling this - * function on a socket which has closed is an error, and a negative value is - * returned. - * - * If a positive N is returned, the first N messages in @messages have been - * sent in full, and the remaining messages have not been sent at all. - * - * If #NiceOutputMessage::to is specified for a message, that will be used as - * the destination address for the message. Otherwise, if %NULL, the default - * destination for @sock will be used. - * - * Every field of every #NiceOutputMessage is guaranteed to be unmodified when - * this function returns. - * - * Returns: number of messages successfully sent from @messages, or a negative - * value on error - * - * Since: 0.1.5 - */ -gint -nice_socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - g_return_val_if_fail (sock != NULL, -1); - g_return_val_if_fail (n_messages == 0 || messages != NULL, -1); - - return sock->send_messages (sock, to, messages, n_messages); -} - -/** - * nice_socket_send_messages_reliable: - * @sock: a #NiceSocket - * @messages: (array length=n_messages) (in caller-allocates): - * array of #NiceOutputMessages containing the messages to send - * @n_messages: number of elements in the @messages array - * - * Send @n_messages on the socket, in a reliable, non-blocking fashion. - * The total size of the buffers in each #NiceOutputMessage - * must be at most the maximum UDP payload size (65535 bytes), or excess - * bytes will be silently dropped. - * - * On success, the number of messages transmitted from @messages is returned, - * which will be equal to @n_messages. If the call would have blocked part-way - * though, the remaining bytes will be queued for sending later. - * On failure, a negative value is returned, but no further error information - * is available. Calling this function on a socket which has closed is an error, - * and a negative value is returned. Calling this function on a socket which - * is not TCP or does not have a TCP base socket, will result in an error. - * - * If #NiceOutputMessage::to is specified for a message, that will be used as - * the destination address for the message. Otherwise, if %NULL, the default - * destination for @sock will be used. - * - * Every field of every #NiceOutputMessage is guaranteed to be unmodified when - * this function returns. - * - * Returns: number of messages successfully sent from @messages, or a negative - * value on error - * - * Since: 0.1.5 - */ -gint -nice_socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - g_return_val_if_fail (sock != NULL, -1); - g_return_val_if_fail (n_messages == 0 || messages != NULL, -1); - - return sock->send_messages_reliable (sock, to, messages, n_messages); -} - -/* Convenience wrapper around nice_socket_recv_messages(). Returns the number of - * bytes received on success (which will be @len), zero if sending would block, or - * -1 on error. */ -gssize -nice_socket_recv (NiceSocket *sock, NiceAddress *from, gsize len, - gchar *buf) -{ - GInputVector local_buf = { buf, len }; - NiceInputMessage local_message = { &local_buf, 1, from, 0}; - gint ret; - - ret = sock->recv_messages (sock, &local_message, 1); - if (ret == 1) - return local_message.length; - return ret; -} - -/* Convenience wrapper around nice_socket_send_messages(). Returns the number of - * bytes sent on success (which will be @len), zero if sending would block, or - * -1 on error. */ -gssize -nice_socket_send (NiceSocket *sock, const NiceAddress *to, gsize len, - const gchar *buf) -{ - GOutputVector local_buf = { buf, len }; - NiceOutputMessage local_message = { &local_buf, 1}; - gint ret; - - ret = sock->send_messages (sock, to, &local_message, 1); - if (ret == 1) - return len; - return ret; -} - -gssize -nice_socket_send_reliable (NiceSocket *sock, const NiceAddress *to, gsize len, - const gchar *buf) -{ - GOutputVector local_buf = { buf, len }; - NiceOutputMessage local_message = { &local_buf, 1}; - gint ret; - - ret = sock->send_messages_reliable (sock, to, &local_message, 1); - if (ret == 1) - return len; - return ret; -} - -gboolean -nice_socket_is_reliable (NiceSocket *sock) -{ - return sock->is_reliable (sock); -} - -gboolean -nice_socket_can_send (NiceSocket *sock, NiceAddress *addr) -{ - if (sock->can_send) - return sock->can_send (sock, addr); - return TRUE; -} - -void -nice_socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data) -{ - if (sock->set_writable_callback) - sock->set_writable_callback (sock, callback, user_data); -} - -gboolean -nice_socket_is_based_on (NiceSocket *sock, NiceSocket *other) -{ - if (sock->is_based_on) - return sock->is_based_on (sock, other); - return (sock == other); -} - -void -nice_socket_free (NiceSocket *sock) -{ - if (sock) { - sock->close (sock); - g_slice_free (NiceSocket,sock); - } -} - -static void -nice_socket_free_queued_send (NiceSocketQueuedSend *tbs) -{ - g_free (tbs->buf); - g_slice_free (NiceSocketQueuedSend, tbs); -} - -void -nice_socket_queue_send (GQueue *send_queue, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - guint i; - - if (n_messages == 0) - return; - - /* Compact the message’s buffers before queueing. */ - for (i = 0; i < n_messages; i++) { - NiceSocketQueuedSend *tbs; - const NiceOutputMessage *message = &messages[i]; - gsize message_len_remaining = output_message_get_size (message); - guint j; - gsize offset = 0; - - if (message_len_remaining == 0) - continue; - - /* Compact the buffer. */ - tbs = g_slice_new0 (NiceSocketQueuedSend); - tbs->buf = g_malloc (message_len_remaining); - tbs->length = message_len_remaining; - - if (to) - tbs->to = *to; - else - memset (&tbs->to, 0, sizeof(NiceAddress)); - g_queue_push_tail (send_queue, tbs); - - for (j = 0; - (message->n_buffers >= 0 && j < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[j].buffer != NULL); - j++) { - const GOutputVector *buffer = &message->buffers[j]; - gsize len; - - len = MIN (buffer->size, message_len_remaining); - memcpy (tbs->buf + offset, buffer->buffer, len); - message_len_remaining -= len; - offset += len; - } - - g_assert_cmpint (offset, ==, tbs->length); - } -} - -void nice_socket_queue_send_with_callback (GQueue *send_queue, - const NiceOutputMessage *message, gsize message_offset, gsize message_len, - gboolean head, GSocket *gsock, GSource **io_source, GMainContext *context, - GSocketSourceFunc cb, gpointer user_data) -{ - NiceSocketQueuedSend *tbs; - guint j; - gsize offset = 0; - - if (message_offset >= message_len) - return; - - tbs = g_slice_new0 (NiceSocketQueuedSend); - tbs->length = message_len - message_offset; - tbs->buf = g_malloc (tbs->length); - - if (head) - g_queue_push_head (send_queue, tbs); - else - g_queue_push_tail (send_queue, tbs); - - /* Move the data into the buffer. */ - for (j = 0; - (message->n_buffers >= 0 && j < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[j].buffer != NULL); - j++) { - const GOutputVector *buffer = &message->buffers[j]; - gsize len; - - /* Skip this buffer if it’s within @message_offset. */ - if (buffer->size <= message_offset) { - message_offset -= buffer->size; - continue; - } - - len = MIN (tbs->length - offset, buffer->size - message_offset); - memcpy (tbs->buf + offset, (guint8 *) buffer->buffer + message_offset, len); - offset += len; - if (message_offset >= len) - message_offset -= len; - else - message_offset = 0; - } - - if (io_source && gsock && context && cb && *io_source == NULL) { - *io_source = g_socket_create_source(gsock, G_IO_OUT, NULL); - g_source_set_callback (*io_source, (GSourceFunc) G_CALLBACK (cb), user_data, NULL); - g_source_attach (*io_source, context); - } -} - -void nice_socket_flush_send_queue (NiceSocket *base_socket, GQueue *send_queue) -{ - NiceSocketQueuedSend *tbs; - - while ((tbs = g_queue_pop_head (send_queue))) { - NiceAddress *to = &tbs->to; - - if (!nice_address_is_valid (to)) - to = NULL; - - /* We only queue reliable data */ - nice_socket_send_reliable (base_socket, to, - tbs->length, (const gchar *) tbs->buf); - nice_socket_free_queued_send (tbs); - } -} - -gboolean nice_socket_flush_send_queue_to_socket (GSocket *gsock, - GQueue *send_queue) -{ - NiceSocketQueuedSend *tbs; - GError *gerr = NULL; - - - while ((tbs = g_queue_pop_head (send_queue)) != NULL) { - int ret; - - GOutputVector local_bufs = { tbs->buf, tbs->length }; - ret = g_socket_send_message (gsock, NULL, &local_bufs, 1, NULL, 0, - G_SOCKET_MSG_NONE, NULL, &gerr); - - if (ret < 0) { - if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - GOutputVector local_buf = { tbs->buf, tbs->length }; - NiceOutputMessage local_message = {&local_buf, 1}; - - nice_socket_queue_send_with_callback (send_queue, &local_message, - 0, local_buf.size, TRUE, NULL, NULL, NULL, NULL, NULL); - nice_socket_free_queued_send (tbs); - g_error_free (gerr); - return FALSE; - } - g_clear_error (&gerr); - } else if (ret < (int) tbs->length) { - GOutputVector local_buf = { tbs->buf + ret, tbs->length - ret }; - NiceOutputMessage local_message = {&local_buf, 1}; - - nice_socket_queue_send_with_callback (send_queue, &local_message, - 0, local_buf.size, TRUE, NULL, NULL, NULL, NULL, NULL); - nice_socket_free_queued_send (tbs); - return FALSE; - } - - nice_socket_free_queued_send (tbs); - } - - return TRUE; -} - -void -nice_socket_free_send_queue (GQueue *send_queue) -{ - g_list_free_full (send_queue->head, (GDestroyNotify) nice_socket_free_queued_send); - g_queue_init (send_queue); -} diff --git a/socket/socket.h b/socket/socket.h deleted file mode 100644 index c4c287b..0000000 --- a/socket/socket.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _SOCKET_H -#define _SOCKET_H - -#include "agent.h" -#include "address.h" -#include - -#ifdef G_OS_WIN32 -#include -#include -#else -#include -#include -#include -#include -#endif - -G_BEGIN_DECLS - -typedef struct _NiceSocket NiceSocket; - -typedef enum { - NICE_SOCKET_TYPE_UDP_BSD, - NICE_SOCKET_TYPE_TCP_BSD, - NICE_SOCKET_TYPE_PSEUDOSSL, - NICE_SOCKET_TYPE_HTTP, - NICE_SOCKET_TYPE_SOCKS5, - NICE_SOCKET_TYPE_UDP_TURN, - NICE_SOCKET_TYPE_UDP_TURN_OVER_TCP, - NICE_SOCKET_TYPE_TCP_ACTIVE, - NICE_SOCKET_TYPE_TCP_PASSIVE, - NICE_SOCKET_TYPE_TCP_SO -} NiceSocketType; - -typedef void (*NiceSocketWritableCb) (NiceSocket *sock, gpointer user_data); - -struct _NiceSocket -{ - NiceAddress addr; - NiceSocketType type; - GSocket *fileno; - /* Implementations must handle any value of n_recv_messages, including 0. Iff - * n_recv_messages is 0, recv_messages may be NULL. */ - gint (*recv_messages) (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); - /* As above, @n_messages may be zero. Iff so, @messages may be %NULL. */ - gint (*send_messages) (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); - gint (*send_messages_reliable) (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); - gboolean (*is_reliable) (NiceSocket *sock); - gboolean (*can_send) (NiceSocket *sock, NiceAddress *addr); - void (*set_writable_callback) (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); - gboolean (*is_based_on) (NiceSocket *sock, NiceSocket *other); - void (*close) (NiceSocket *sock); - void *priv; -}; - - -G_GNUC_WARN_UNUSED_RESULT -gint -nice_socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); - -gint -nice_socket_send_messages (NiceSocket *sock, const NiceAddress *addr, - const NiceOutputMessage *messages, guint n_messages); -gint -nice_socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *addr, - const NiceOutputMessage *messages, guint n_messages); -gssize -nice_socket_recv (NiceSocket *sock, NiceAddress *from, gsize len, - gchar *buf); -gssize -nice_socket_send (NiceSocket *sock, const NiceAddress *to, gsize len, - const gchar *buf); -gssize -nice_socket_send_reliable (NiceSocket *sock, const NiceAddress *addr, gsize len, - const gchar *buf); - -gboolean -nice_socket_is_reliable (NiceSocket *sock); - -gboolean -nice_socket_can_send (NiceSocket *sock, NiceAddress *addr); - -void -nice_socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); - -/** - * nice_socket_is_based_on: - * @sock: a #NiceSocket - * @other: another #NiceSocket - * - * Checks whether @sock wraps @other as a source and destination of its read and - * write operations. The function traverses the whole chain of @sock's base - * sockets until @other is found or the end is reached. - * - * Returns: %TRUE if @sock is based on @other or if @sock and @other are - * the same socket, %FALSE otherwise. - * - * Since: 0.1.14 - */ -gboolean -nice_socket_is_based_on (NiceSocket *sock, NiceSocket *other); - -void -nice_socket_free (NiceSocket *sock); - -#include "udp-bsd.h" -#include "tcp-bsd.h" -#include "tcp-active.h" -#include "tcp-passive.h" -#include "pseudossl.h" -#include "socks5.h" -#include "http.h" -#include "udp-turn.h" -#include "udp-turn-over-tcp.h" - -G_END_DECLS - -#endif /* _SOCKET_H */ - diff --git a/socket/socks5.c b/socket/socks5.c deleted file mode 100644 index d15fc29..0000000 --- a/socket/socks5.c +++ /dev/null @@ -1,499 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See - * http://en.wikipedia.org/wiki/Berkeley_sockets.) - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "socks5.h" -#include "agent-priv.h" -#include "socket-priv.h" - -#include - -#ifndef G_OS_WIN32 -#include -#endif - -typedef enum { - SOCKS_STATE_INIT, - SOCKS_STATE_AUTH, - SOCKS_STATE_CONNECT, - SOCKS_STATE_CONNECTED, - SOCKS_STATE_ERROR -} SocksState; - -typedef struct { - SocksState state; - NiceSocket *base_socket; - NiceAddress addr; - gchar *username; - gchar *password; - GQueue send_queue; -} Socks5Priv; - - -static void socket_close (NiceSocket *sock); -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages); -static gboolean socket_is_reliable (NiceSocket *sock); -static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr); -static void socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); -static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other); - - -NiceSocket * -nice_socks5_socket_new (NiceSocket *base_socket, - NiceAddress *addr, gchar *username, gchar *password) -{ - Socks5Priv *priv; - NiceSocket *sock = NULL; - - if (addr) { - sock = g_slice_new0 (NiceSocket); - sock->priv = priv = g_slice_new0 (Socks5Priv); - - priv->base_socket = base_socket; - priv->addr = *addr; - priv->username = g_strdup (username); - priv->password = g_strdup (password); - - sock->type = NICE_SOCKET_TYPE_SOCKS5; - sock->fileno = priv->base_socket->fileno; - sock->addr = priv->base_socket->addr; - sock->send_messages = socket_send_messages; - sock->send_messages_reliable = socket_send_messages_reliable; - sock->recv_messages = socket_recv_messages; - sock->is_reliable = socket_is_reliable; - sock->can_send = socket_can_send; - sock->set_writable_callback = socket_set_writable_callback; - sock->is_based_on = socket_is_based_on; - sock->close = socket_close; - - /* Send SOCKS5 handshake */ - { - gchar msg[4]; - gint len = 3; - - msg[0] = 0x05; /* SOCKS version */ - msg[1] = 0x01; /* number of methods supported */ - msg[2] = 0x00; /* no authentication method*/ - - g_debug ("user/pass : %s - %s", username, password); - /* add support for authentication method */ - if (username || password) { - msg[1] = 0x02; /* number of methods supported */ - msg[3] = 0x02; /* authentication method */ - len++; - } - - /* We send 'to' NULL because it will always be to an already connected - * TCP base socket, which ignores the destination */ - nice_socket_send_reliable (priv->base_socket, NULL, len, msg); - priv->state = SOCKS_STATE_INIT; - } - } - - return sock; -} - - -static void -socket_close (NiceSocket *sock) -{ - Socks5Priv *priv = sock->priv; - - if (priv->base_socket) - nice_socket_free (priv->base_socket); - - if (priv->username) - g_free (priv->username); - - if (priv->password) - g_free (priv->password); - - nice_socket_free_send_queue (&priv->send_queue); - - g_slice_free(Socks5Priv, sock->priv); - sock->priv = NULL; -} - - -static gint -socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages) -{ - Socks5Priv *priv = sock->priv; - guint i; - gint ret = -1; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - switch (priv->state) { - case SOCKS_STATE_CONNECTED: - /* Common case: fast pass-through to the base socket once we’re - * connected. */ - if (priv->base_socket) { - ret = nice_socket_recv_messages (priv->base_socket, - recv_messages, n_recv_messages); - } - - if (ret <= 0) - return ret; - - /* After successfully receiving into at least one NiceInputMessage, - * update the from address in each valid NiceInputMessage. */ - for (i = 0; i < (guint) ret; i++) { - if (recv_messages[i].from != NULL) - *recv_messages[i].from = priv->addr; - } - - return ret; - - case SOCKS_STATE_INIT: - { - guint8 data[2]; - GInputVector local_recv_buf = { data, sizeof (data) }; - NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 }; - - nice_debug ("Socks5 state Init"); - - if (priv->base_socket) { - ret = nice_socket_recv_messages (priv->base_socket, - &local_recv_message, 1); - } - - if (ret <= 0) { - return ret; - } else if (ret == 1 && local_recv_buf.size == sizeof(data)) { - if (data[0] == 0x05) { - if (data[1] == 0x02) { - gchar msg[515]; - gint len = 0; - - if (priv->username || priv->password) { - gint ulen = 0; - gint plen = 0; - - if (priv->username) - ulen = strlen (priv->username); - if (ulen > 255) { - nice_debug ("Socks5 username length > 255"); - goto error; - } - - if (priv->password) - plen = strlen (priv->password); - if (plen > 255) { - nice_debug ("Socks5 password length > 255"); - goto error; - } - - msg[len++] = 0x01; /* auth version */ - msg[len++] = ulen; /* username length */ - if (ulen > 0) - memcpy (msg + len, priv->username, ulen); /* Username */ - len += ulen; - msg[len++] = plen; /* Password length */ - if (plen > 0) - memcpy (msg + len, priv->password, plen); /* Password */ - len += plen; - - nice_socket_send_reliable (priv->base_socket, NULL, len, msg); - priv->state = SOCKS_STATE_AUTH; - } else { - /* Authentication required but no auth info available */ - goto error; - } - } else if (data[1] == 0x00) { - goto send_connect; - } else { - /* method not supported by socks server */ - goto error; - } - } else { - /* invalid SOCKS server version */ - goto error; - } - } else { - /* read error */ - goto error; - } - } - break; - case SOCKS_STATE_AUTH: - { - guint8 data[2]; - GInputVector local_recv_buf = { data, sizeof (data) }; - NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 }; - - nice_debug ("Socks5 state auth"); - if (priv->base_socket) { - ret = nice_socket_recv_messages (priv->base_socket, - &local_recv_message, 1); - } - - if (ret <= 0) { - return ret; - } else if (ret == 1 && local_recv_buf.size == sizeof(data)) { - if (data[0] == 0x01 && data[1] == 0x00) { - /* Authenticated */ - goto send_connect; - } else { - /* Authentication failed */ - goto error; - } - } - } - break; - case SOCKS_STATE_CONNECT: - { - guint8 data[22]; - GInputVector local_recv_buf = { data, sizeof (data) }; - NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 }; - - nice_debug ("Socks5 state connect"); - if (priv->base_socket) { - local_recv_buf.size = 4; - ret = nice_socket_recv_messages (priv->base_socket, - &local_recv_message, 1); - } - - if (ret <= 0) { - return ret; - } else if (ret == 1 && local_recv_buf.size == 4) { - if (data[0] == 0x05) { - switch (data[1]) { - case 0x00: - if (data[2] == 0x00) { - switch (data[3]) { - case 0x01: /* IPV4 bound address */ - local_recv_buf.size = 6; - ret = nice_socket_recv_messages (priv->base_socket, - &local_recv_message, 1); - if (ret != 1 || local_recv_buf.size != 6) { - /* Could not read server bound address */ - goto error; - } - break; - case 0x04: /* IPV6 bound address */ - local_recv_buf.size = 18; - ret = nice_socket_recv_messages (priv->base_socket, - &local_recv_message, 1); - if (ret != 1 || local_recv_buf.size != 18) { - /* Could not read server bound address */ - goto error; - } - break; - default: - /* Unsupported address type */ - goto error; - } - nice_socket_flush_send_queue (priv->base_socket, - &priv->send_queue); - priv->state = SOCKS_STATE_CONNECTED; - } else { - /* Wrong reserved value */ - goto error; - } - break; - case 0x01: /* general SOCKS server failure */ - case 0x02: /* connection not allowed by ruleset */ - case 0x03: /* Network unreachable */ - case 0x04: /* Host unreachable */ - case 0x05: /* Connection refused */ - case 0x06: /* TTL expired */ - case 0x07: /* Command not supported */ - case 0x08: /* Address type not supported */ - default: /* Unknown error */ - goto error; - break; - } - } else { - /* Wrong server version */ - goto error; - } - } else { - /* Invalid data received */ - goto error; - } - } - break; - case SOCKS_STATE_ERROR: - default: - /* Unknown status */ - goto error; - } - - return 0; - - send_connect: - { - gchar msg[22]; - gint len = 0; - union { - struct sockaddr_storage storage; - struct sockaddr addr; - struct sockaddr_in in; - struct sockaddr_in6 in6; - } name; - nice_address_copy_to_sockaddr(&priv->addr, &name.addr); - - msg[len++] = 0x05; /* SOCKS version */ - msg[len++] = 0x01; /* connect command */ - msg[len++] = 0x00; /* reserved */ - if (name.storage.ss_family == AF_INET) { - msg[len++] = 0x01; /* IPV4 address type */ - /* Address */ - memcpy (msg + len, &(&name.in)->sin_addr, 4); - len += 4; - /* Port */ - memcpy (msg + len, &(&name.in)->sin_port, 2); - len += 2; - } else if (name.storage.ss_family == AF_INET6) { - msg[len++] = 0x04; /* IPV6 address type */ - /* Address */ - memcpy (msg + len, &(&name.in6)->sin6_addr, 16); - len += 16; - /* Port */ - memcpy (msg + len, &(&name.in6)->sin6_port, 2); - len += 2; - } - - nice_socket_send_reliable (priv->base_socket, NULL, len, msg); - priv->state = SOCKS_STATE_CONNECT; - - return 0; - } - error: - nice_debug ("Socks5 error"); - if (priv->base_socket) - nice_socket_free (priv->base_socket); - priv->base_socket = NULL; - priv->state = SOCKS_STATE_ERROR; - - return -1; -} - -static gint -socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - Socks5Priv *priv = sock->priv; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - if (priv->state == SOCKS_STATE_CONNECTED) { - /* Fast path: pass through to the base socket once connected. */ - if (priv->base_socket == NULL) - return -1; - - return nice_socket_send_messages (priv->base_socket, to, messages, - n_messages); - } else if (priv->state == SOCKS_STATE_ERROR) { - return -1; - } else { - return 0; - } -} - - -static gint -socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - Socks5Priv *priv = sock->priv; - - if (priv->state == SOCKS_STATE_CONNECTED) { - /* Fast path: pass through to the base socket once connected. */ - if (priv->base_socket == NULL) - return -1; - - return nice_socket_send_messages_reliable (priv->base_socket, to, messages, - n_messages); - } else if (priv->state == SOCKS_STATE_ERROR) { - return -1; - } else { - nice_socket_queue_send (&priv->send_queue, to, messages, n_messages); - } - return n_messages; -} - - -static gboolean -socket_is_reliable (NiceSocket *sock) -{ - Socks5Priv *priv = sock->priv; - - return nice_socket_is_reliable (priv->base_socket); -} - -static gboolean -socket_can_send (NiceSocket *sock, NiceAddress *addr) -{ - Socks5Priv *priv = sock->priv; - - return nice_socket_can_send (priv->base_socket, addr); -} - -static void -socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data) -{ - Socks5Priv *priv = sock->priv; - - nice_socket_set_writable_callback (priv->base_socket, callback, user_data); -} - -static gboolean -socket_is_based_on (NiceSocket *sock, NiceSocket *other) -{ - Socks5Priv *priv = sock->priv; - - return (sock == other) || - (priv && nice_socket_is_based_on (priv->base_socket, other)); -} diff --git a/socket/socks5.h b/socket/socks5.h deleted file mode 100644 index f164542..0000000 --- a/socket/socks5.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _SOCKS5_H -#define _SOCKS5_H - -#include "socket.h" -#include "agent.h" - -G_BEGIN_DECLS - - -NiceSocket * -nice_socks5_socket_new (NiceSocket *base_socket, - NiceAddress *addr, gchar *username, gchar *password); - - -G_END_DECLS - -#endif /* _SOCKS5_H */ - diff --git a/socket/tcp-active.c b/socket/tcp-active.c deleted file mode 100644 index eb7cd7f..0000000 --- a/socket/tcp-active.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2012 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * George Kiagiadakis, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "socket.h" -#include "tcp-active.h" - -#include -#include -#include - -#ifndef G_OS_WIN32 -#include -#endif - -/* FIXME: This should be defined in gio/gnetworking.h, which we should include; - * but we cannot do that without refactoring. - * (See: https://phabricator.freedesktop.org/D230). */ -#undef TCP_NODELAY -#define TCP_NODELAY 1 - -typedef struct { - GSocketAddress *local_addr; - GMainContext *context; -} TcpActivePriv; - - -static void socket_close (NiceSocket *sock); -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages); -static gboolean socket_is_reliable (NiceSocket *sock); -static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr); -static void socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); - - -NiceSocket * -nice_tcp_active_socket_new (GMainContext *ctx, NiceAddress *addr) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } name; - NiceSocket *sock; - TcpActivePriv *priv; - GSocketAddress *gaddr; - NiceAddress local_addr; - - if (addr != NULL) { - - local_addr = *addr; - /* Make sure we don't bind to any local port */ - nice_address_set_port (&local_addr, 0); - nice_address_copy_to_sockaddr(&local_addr, &name.addr); - } else { - memset (&local_addr, 0, sizeof (local_addr)); - memset (&name, 0, sizeof (name)); - name.storage.ss_family = AF_UNSPEC; - } - - gaddr = g_socket_address_new_from_native (&name, sizeof (name)); - - if (gaddr == NULL) { - return NULL; - } - - if (ctx == NULL) { - ctx = g_main_context_default (); - } - - sock = g_slice_new0 (NiceSocket); - - sock->priv = priv = g_slice_new0 (TcpActivePriv); - - priv->context = g_main_context_ref (ctx); - priv->local_addr = gaddr; - - sock->type = NICE_SOCKET_TYPE_TCP_ACTIVE; - sock->fileno = NULL; - sock->addr = local_addr; - sock->send_messages = socket_send_messages; - sock->send_messages_reliable = socket_send_messages_reliable; - sock->recv_messages = socket_recv_messages; - sock->is_reliable = socket_is_reliable; - sock->can_send = socket_can_send; - sock->set_writable_callback = socket_set_writable_callback; - sock->close = socket_close; - - return sock; -} - -static void -socket_close (NiceSocket *sock) -{ - TcpActivePriv *priv = sock->priv; - - if (priv->context) - g_main_context_unref (priv->context); - if (priv->local_addr) - g_object_unref (priv->local_addr); - - g_slice_free(TcpActivePriv, sock->priv); -} - -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages) -{ - return -1; -} - -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - return -1; -} - -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages) -{ - return -1; -} - -static gboolean -socket_is_reliable (NiceSocket *sock) -{ - return TRUE; -} - -static gboolean -socket_can_send (NiceSocket *sock, NiceAddress *addr) -{ - return FALSE; -} - -static void -socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data) -{ -} - -NiceSocket * -nice_tcp_active_socket_connect (NiceSocket *sock, NiceAddress *addr) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } name; - TcpActivePriv *priv = sock->priv; - GSocket *gsock = NULL; - GError *gerr = NULL; - gboolean gret = FALSE; - GSocketAddress *gaddr; - NiceAddress local_addr; - NiceSocket *new_socket = NULL; - - if (addr == NULL) { - /* We can't connect a tcp socket with no destination address */ - return NULL; - } - - nice_address_copy_to_sockaddr (addr, &name.addr); - - if (name.storage.ss_family == AF_UNSPEC || name.storage.ss_family == AF_INET) { - gsock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_TCP, NULL); - - name.storage.ss_family = AF_INET; -#ifdef HAVE_SA_LEN - name.storage.ss_len = sizeof (struct sockaddr_in); -#endif - } else if (name.storage.ss_family == AF_INET6) { - gsock = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_TCP, NULL); - name.storage.ss_family = AF_INET6; -#ifdef HAVE_SA_LEN - name.storage.ss_len = sizeof (struct sockaddr_in6); -#endif - } - - if (gsock == NULL) { - return NULL; - } - - gaddr = g_socket_address_new_from_native (&name.addr, sizeof (name)); - if (gaddr == NULL) { - g_object_unref (gsock); - return NULL; - } - - /* GSocket: All socket file descriptors are set to be close-on-exec. */ - g_socket_set_blocking (gsock, false); - - /* setting TCP_NODELAY to TRUE in order to avoid packet batching */ - g_socket_set_option (gsock, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL); - - /* Allow g_socket_bind to fail */ - g_socket_bind (gsock, priv->local_addr, FALSE, NULL); - - gret = g_socket_connect (gsock, gaddr, NULL, &gerr); - g_object_unref (gaddr); - - if (gret == FALSE) { - if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_PENDING) == FALSE) { - g_error_free (gerr); - g_socket_close (gsock, NULL); - g_object_unref (gsock); - return NULL; - } - g_error_free (gerr); - } - - gaddr = g_socket_get_local_address (gsock, NULL); - if (gaddr == NULL || - !g_socket_address_to_native (gaddr, &name.addr, sizeof (name), NULL)) { - g_socket_close (gsock, NULL); - g_object_unref (gsock); - return NULL; - } - g_object_unref (gaddr); - - nice_address_set_from_sockaddr (&local_addr, &name.addr); - - new_socket = nice_tcp_bsd_socket_new_from_gsock (priv->context, gsock, - &local_addr, addr, TRUE); - g_object_unref (gsock); - - return new_socket; -} diff --git a/socket/tcp-active.h b/socket/tcp-active.h deleted file mode 100644 index cf4a0d9..0000000 --- a/socket/tcp-active.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _TCP_ACTIVE_H -#define _TCP_ACTIVE_H - -#include "socket.h" - -G_BEGIN_DECLS - - -NiceSocket * nice_tcp_active_socket_new (GMainContext *ctx, NiceAddress *addr); -NiceSocket * nice_tcp_active_socket_connect (NiceSocket *socket, NiceAddress *addr); - - -G_END_DECLS - -#endif /* _TCP_ACTIVE_H */ - diff --git a/socket/tcp-bsd.c b/socket/tcp-bsd.c deleted file mode 100644 index 3cac22c..0000000 --- a/socket/tcp-bsd.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See - * http://en.wikipedia.org/wiki/Berkeley_sockets.) - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "tcp-bsd.h" -#include "agent-priv.h" -#include "socket-priv.h" - -#include "tcp-passive.h" - -#include -#include -#include - -#ifndef G_OS_WIN32 -#include -#endif - -/* FIXME: This should be defined in gio/gnetworking.h, which we should include; - * but we cannot do that without refactoring. - * (See: https://phabricator.freedesktop.org/D230). */ -#undef TCP_NODELAY -#define TCP_NODELAY 1 - -static GMutex mutex; - -typedef struct { - NiceAddress remote_addr; - GQueue send_queue; - GMainContext *context; - GSource *io_source; - gboolean error; - gboolean reliable; - NiceSocketWritableCb writable_cb; - gpointer writable_data; - NiceSocket *passive_parent; -} TcpPriv; - -#define MAX_QUEUE_LENGTH 20 - -static void socket_close (NiceSocket *sock); -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages); -static gboolean socket_is_reliable (NiceSocket *sock); -static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr); -static void socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); - -static gboolean socket_send_more (GSocket *gsocket, GIOCondition condition, - gpointer data); - -NiceSocket * -nice_tcp_bsd_socket_new_from_gsock (GMainContext *ctx, GSocket *gsock, - NiceAddress *local_addr, NiceAddress *remote_addr, gboolean reliable) -{ - NiceSocket *sock; - TcpPriv *priv; - - g_return_val_if_fail (G_IS_SOCKET (gsock), NULL); - - sock = g_slice_new0 (NiceSocket); - sock->priv = priv = g_slice_new0 (TcpPriv); - - if (ctx == NULL) - ctx = g_main_context_default (); - priv->context = g_main_context_ref (ctx); - priv->remote_addr = *remote_addr; - priv->error = FALSE; - priv->reliable = reliable; - priv->writable_cb = NULL; - priv->writable_data = NULL; - - sock->type = NICE_SOCKET_TYPE_TCP_BSD; - sock->fileno = g_object_ref (gsock); - sock->addr = *local_addr; - sock->send_messages = socket_send_messages; - sock->send_messages_reliable = socket_send_messages_reliable; - sock->recv_messages = socket_recv_messages; - sock->is_reliable = socket_is_reliable; - sock->can_send = socket_can_send; - sock->set_writable_callback = socket_set_writable_callback; - sock->close = socket_close; - - return sock; -} - -NiceSocket * -nice_tcp_bsd_socket_new (GMainContext *ctx, NiceAddress *local_addr, - NiceAddress *remote_addr, gboolean reliable) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } name; - NiceSocket *sock; - GSocket *gsock = NULL; - GError *gerr = NULL; - gboolean gret = FALSE; - GSocketAddress *gaddr; - - if (remote_addr == NULL) { - /* We can't connect a tcp socket with no destination address */ - return NULL; - } - - nice_address_copy_to_sockaddr (remote_addr, &name.addr); - - if (name.storage.ss_family == AF_UNSPEC || name.storage.ss_family == AF_INET) { - gsock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_TCP, NULL); - - name.storage.ss_family = AF_INET; -#ifdef HAVE_SA_LEN - name.storage.ss_len = sizeof (struct sockaddr_in); -#endif - } else if (name.storage.ss_family == AF_INET6) { - gsock = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_TCP, NULL); - name.storage.ss_family = AF_INET6; -#ifdef HAVE_SA_LEN - name.storage.ss_len = sizeof (struct sockaddr_in6); -#endif - } - - if (gsock == NULL) { - return NULL; - } - - gaddr = g_socket_address_new_from_native (&name.addr, sizeof (name)); - if (gaddr == NULL) { - g_object_unref (gsock); - return NULL; - } - - /* GSocket: All socket file descriptors are set to be close-on-exec. */ - g_socket_set_blocking (gsock, false); - - /* setting TCP_NODELAY to TRUE in order to avoid packet batching */ - g_socket_set_option (gsock, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL); - - gret = g_socket_connect (gsock, gaddr, NULL, &gerr); - g_object_unref (gaddr); - - if (gret == FALSE) { - if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_PENDING) == FALSE) { - g_error_free (gerr); - g_socket_close (gsock, NULL); - g_object_unref (gsock); - return NULL; - } - g_error_free (gerr); - } - - nice_address_copy_to_sockaddr (local_addr, &name.addr); - gaddr = g_socket_address_new_from_native (&name.addr, sizeof (name)); - if (gaddr == NULL) { - g_socket_close (gsock, NULL); - g_object_unref (gsock); - return NULL; - } - g_socket_bind (gsock, gaddr, FALSE, NULL); - g_object_unref (gaddr); - - sock = nice_tcp_bsd_socket_new_from_gsock (ctx, gsock, local_addr, remote_addr, - reliable); - g_object_unref (gsock); - - return sock; -} - - -static void -socket_close (NiceSocket *sock) -{ - TcpPriv *priv = sock->priv; - - g_mutex_lock (&mutex); - - if (sock->fileno) { - g_socket_close (sock->fileno, NULL); - g_object_unref (sock->fileno); - sock->fileno = NULL; - } - if (priv->io_source) { - g_source_destroy (priv->io_source); - g_source_unref (priv->io_source); - } - - if (priv->passive_parent) { - nice_tcp_passive_socket_remove_connection (priv->passive_parent, &priv->remote_addr); - } - - nice_socket_free_send_queue (&priv->send_queue); - - if (priv->context) - g_main_context_unref (priv->context); - - g_mutex_unlock (&mutex); - - g_slice_free(TcpPriv, sock->priv); -} - -static gint -socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages) -{ - TcpPriv *priv = sock->priv; - guint i; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - /* Don't try to access the socket if it had an error */ - if (priv->error) - return -1; - - for (i = 0; i < n_recv_messages; i++) { - gint flags = G_SOCKET_MSG_NONE; - GError *gerr = NULL; - gssize len; - - len = g_socket_receive_message (sock->fileno, NULL, - recv_messages[i].buffers, recv_messages[i].n_buffers, - NULL, NULL, &flags, NULL, &gerr); - - recv_messages[i].length = MAX (len, 0); - - /* recv returns 0 when the peer performed a shutdown.. we must return -1 - * here so that the agent destroys the g_source */ - if (len == 0) { - priv->error = TRUE; - break; - } - - if (len < 0) { - if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) - len = 0; - - g_error_free (gerr); - return len; - } - - if (recv_messages[i].from) - *recv_messages[i].from = priv->remote_addr; - } - - /* Was there an error processing the first message? */ - if (priv->error && i == 0) - return -1; - - return i; -} - -static gssize -socket_send_message (NiceSocket *sock, - const NiceOutputMessage *message, gboolean reliable) -{ - TcpPriv *priv = sock->priv; - gssize ret; - GError *gerr = NULL; - gsize message_len; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - /* Don't try to access the socket if it had an error, otherwise we risk a - * crash with SIGPIPE (Broken pipe) */ - if (priv->error) - return -1; - - message_len = output_message_get_size (message); - - /* First try to send the data, don't send it later if it can be sent now - * this way we avoid allocating memory on every send */ - if (g_queue_is_empty (&priv->send_queue)) { - ret = g_socket_send_message (sock->fileno, NULL, message->buffers, - message->n_buffers, NULL, 0, G_SOCKET_MSG_NONE, NULL, &gerr); - - if (ret < 0) { - if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) || - g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_FAILED)) { - /* Queue the message and send it later. */ - nice_socket_queue_send_with_callback (&priv->send_queue, - message, 0, message_len, FALSE, sock->fileno, &priv->io_source, - priv->context, socket_send_more, sock); - ret = message_len; - } - - g_error_free (gerr); - } else if ((gsize) ret < message_len) { - /* Partial send. */ - nice_socket_queue_send_with_callback (&priv->send_queue, - message, ret, message_len, TRUE, sock->fileno, &priv->io_source, - priv->context, socket_send_more, sock); - ret = message_len; - } - } else { - /* Only queue if we're sending reliably */ - if (reliable) { - /* Queue the message and send it later. */ - nice_socket_queue_send_with_callback (&priv->send_queue, - message, 0, message_len, FALSE, sock->fileno, &priv->io_source, - priv->context, socket_send_more, sock); - ret = message_len; - } else { - /* non reliable send, so we shouldn't queue the message */ - ret = 0; - } - } - - return ret; -} - -/* Data sent to this function must be a single entity because buffers can be - * dropped if the bandwidth isn't fast enough. So do not send a message in - * multiple chunks. */ -static gint -socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - guint i; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - for (i = 0; i < n_messages; i++) { - const NiceOutputMessage *message = &messages[i]; - gssize len; - - len = socket_send_message (sock, message, FALSE); - - if (len < 0) { - /* Error. */ - if (i > 0) - break; - return len; - } else if (len == 0) { - /* EWOULDBLOCK. */ - break; - } - } - - return i; -} - -static gint -socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - guint i; - - for (i = 0; i < n_messages; i++) { - if (socket_send_message (sock, &messages[i], TRUE) < 0) { - /* Error. */ - return -1; - } - } - - return i; -} - -static gboolean -socket_is_reliable (NiceSocket *sock) -{ - TcpPriv *priv = sock->priv; - - return priv->reliable; -} - -static gboolean -socket_can_send (NiceSocket *sock, NiceAddress *addr) -{ - TcpPriv *priv = sock->priv; - - return g_queue_is_empty (&priv->send_queue); -} - -static void -socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data) -{ - TcpPriv *priv = sock->priv; - - priv->writable_cb = callback; - priv->writable_data = user_data; -} - -static gboolean -socket_send_more ( - GSocket *gsocket, - GIOCondition condition, - gpointer data) -{ - NiceSocket *sock = (NiceSocket *) data; - TcpPriv *priv; - - g_mutex_lock (&mutex); - - if (g_source_is_destroyed (g_main_current_source ())) { - nice_debug ("Source was destroyed. " - "Avoided race condition in tcp-bsd.c:socket_send_more"); - g_mutex_unlock (&mutex); - return FALSE; - } - - priv = sock->priv; - - /* connection hangs up or queue was emptied */ - if (condition & G_IO_HUP || - nice_socket_flush_send_queue_to_socket (sock->fileno, - &priv->send_queue)) { - g_source_destroy (priv->io_source); - g_source_unref (priv->io_source); - priv->io_source = NULL; - - g_mutex_unlock (&mutex); - - if (priv->writable_cb) - priv->writable_cb (sock, priv->writable_data); - - return FALSE; - } - - g_mutex_unlock (&mutex); - return TRUE; -} - -void -nice_tcp_bsd_socket_set_passive_parent (NiceSocket *sock, NiceSocket *passive_parent) -{ - TcpPriv *priv = sock->priv; - - g_assert (priv->passive_parent == NULL); - - priv->passive_parent = passive_parent; -} - -NiceSocket * -nice_tcp_bsd_socket_get_passive_parent (NiceSocket *sock) -{ - TcpPriv *priv = sock->priv; - - return priv->passive_parent; -} diff --git a/socket/tcp-bsd.h b/socket/tcp-bsd.h deleted file mode 100644 index 7c42ed3..0000000 --- a/socket/tcp-bsd.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _TCP_BSD_H -#define _TCP_BSD_H - -#include "socket.h" - -G_BEGIN_DECLS - -NiceSocket * -nice_tcp_bsd_socket_new (GMainContext *ctx, NiceAddress *remote_addr, - NiceAddress *local_addr, gboolean reliable); - -NiceSocket * -nice_tcp_bsd_socket_new_from_gsock (GMainContext *ctx, GSocket *gsock, - NiceAddress *remote_addr, NiceAddress *local_addr, gboolean reliable); - -void -nice_tcp_bsd_socket_set_passive_parent (NiceSocket *socket, NiceSocket *passive_parent); - -NiceSocket * -nice_tcp_bsd_socket_get_passive_parent (NiceSocket *socket); - -G_END_DECLS - -#endif /* _TCP_BSD_H */ - diff --git a/socket/tcp-passive.c b/socket/tcp-passive.c deleted file mode 100644 index 6bc43d3..0000000 --- a/socket/tcp-passive.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2012 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * George Kiagiadakis, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "tcp-passive.h" -#include "agent-priv.h" - -#include -#include -#include - -#ifndef G_OS_WIN32 -#include -#endif - -/* FIXME: This should be defined in gio/gnetworking.h, which we should include; - * but we cannot do that without refactoring. - * (See: https://phabricator.freedesktop.org/D230). */ -#undef TCP_NODELAY -#define TCP_NODELAY 1 - -typedef struct { - GMainContext *context; - GHashTable *connections; - NiceSocketWritableCb writable_cb; - gpointer writable_data; -} TcpPassivePriv; - - -static void socket_close (NiceSocket *sock); -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages); -static gboolean socket_is_reliable (NiceSocket *sock); -static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr); -static void socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); - -static guint nice_address_hash (const NiceAddress * key); - -NiceSocket * -nice_tcp_passive_socket_new (GMainContext *ctx, NiceAddress *addr) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } name; - NiceSocket *sock; - TcpPassivePriv *priv; - GSocket *gsock = NULL; - gboolean gret = FALSE; - GSocketAddress *gaddr; - - if (addr != NULL) { - nice_address_copy_to_sockaddr(addr, &name.addr); - } else { - memset (&name, 0, sizeof (name)); - name.storage.ss_family = AF_UNSPEC; - } - - if (name.storage.ss_family == AF_UNSPEC || name.storage.ss_family == AF_INET) { - gsock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_TCP, NULL); - - name.storage.ss_family = AF_INET; -#ifdef HAVE_SA_LEN - name.storage.ss_len = sizeof (struct sockaddr_in); -#endif - } else if (name.storage.ss_family == AF_INET6) { - gsock = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_TCP, NULL); - name.storage.ss_family = AF_INET6; -#ifdef HAVE_SA_LEN - name.storage.ss_len = sizeof (struct sockaddr_in6); -#endif - } - - if (gsock == NULL) { - return NULL; - } - - gaddr = g_socket_address_new_from_native (&name.addr, sizeof (name)); - - if (gaddr == NULL) { - g_object_unref (gsock); - return NULL; - } - - /* GSocket: All socket file descriptors are set to be close-on-exec. */ - g_socket_set_blocking (gsock, false); - - gret = g_socket_bind (gsock, gaddr, FALSE, NULL) && - g_socket_listen (gsock, NULL); - g_object_unref (gaddr); - - if (gret == FALSE) { - g_socket_close (gsock, NULL); - g_object_unref (gsock); - return NULL; - } - - gaddr = g_socket_get_local_address (gsock, NULL); - if (gaddr == NULL || - !g_socket_address_to_native (gaddr, &name.addr, sizeof (name), NULL)) { - g_socket_close (gsock, NULL); - g_object_unref (gsock); - return NULL; - } - g_object_unref (gaddr); - - if (ctx == NULL) { - ctx = g_main_context_default (); - } - - sock = g_slice_new0 (NiceSocket); - - nice_address_set_from_sockaddr (&sock->addr, &name.addr); - - sock->priv = priv = g_slice_new0 (TcpPassivePriv); - priv->context = g_main_context_ref (ctx); - priv->connections = g_hash_table_new_full ((GHashFunc) nice_address_hash, - (GEqualFunc) nice_address_equal, ( - GDestroyNotify) nice_address_free, NULL); - priv->writable_cb = NULL; - priv->writable_data = NULL; - - sock->type = NICE_SOCKET_TYPE_TCP_PASSIVE; - sock->fileno = gsock; - sock->send_messages = socket_send_messages; - sock->send_messages_reliable = socket_send_messages_reliable; - sock->recv_messages = socket_recv_messages; - sock->is_reliable = socket_is_reliable; - sock->can_send = socket_can_send; - sock->set_writable_callback = socket_set_writable_callback; - sock->close = socket_close; - - return sock; -} - -static void -socket_close (NiceSocket *sock) -{ - TcpPassivePriv *priv = sock->priv; - - if (sock->fileno != NULL) { - g_socket_close (sock->fileno, NULL); - g_object_unref (sock->fileno); - sock->fileno = NULL; - } - - if (priv->context) - g_main_context_unref (priv->context); - g_hash_table_unref (priv->connections); - - g_slice_free (TcpPassivePriv, sock->priv); -} - -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages) -{ - return -1; -} - -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - TcpPassivePriv *priv = sock->priv; - - if (to) { - NiceSocket *peer_socket = g_hash_table_lookup (priv->connections, to); - if (peer_socket) - return nice_socket_send_messages (peer_socket, to, messages, n_messages); - } - return -1; -} - -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages) -{ - TcpPassivePriv *priv = sock->priv; - - if (to) { - NiceSocket *peer_socket = g_hash_table_lookup (priv->connections, to); - if (peer_socket) - return nice_socket_send_messages_reliable (peer_socket, to, messages, - n_messages); - } - return -1; -} - -static gboolean -socket_is_reliable (NiceSocket *sock) -{ - return TRUE; -} - -static gboolean -socket_can_send (NiceSocket *sock, NiceAddress *addr) -{ - TcpPassivePriv *priv = sock->priv; - NiceSocket *peer_socket = NULL; - - /* FIXME: Danger if child socket was closed */ - if (addr) - peer_socket = g_hash_table_lookup (priv->connections, addr); - if (peer_socket) - return nice_socket_can_send (peer_socket, addr); - return FALSE; -} - -static void -_child_writable_cb (NiceSocket *child, gpointer data) -{ - NiceSocket *sock = data; - TcpPassivePriv *priv = sock->priv; - - if (priv->writable_cb) - priv->writable_cb (sock, priv->writable_data); -} - -static void -socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data) -{ - TcpPassivePriv *priv = sock->priv; - - priv->writable_cb = callback; - priv->writable_data = user_data; -} - -NiceSocket * -nice_tcp_passive_socket_accept (NiceSocket *sock) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } name; - TcpPassivePriv *priv = sock->priv; - GSocket *gsock = NULL; - GSocketAddress *gaddr; - NiceAddress remote_addr; - NiceSocket *new_socket = NULL; - - gsock = g_socket_accept (sock->fileno, NULL, NULL); - - if (gsock == NULL) { - return NULL; - } - - /* GSocket: All socket file descriptors are set to be close-on-exec. */ - g_socket_set_blocking (gsock, false); - - /* setting TCP_NODELAY to TRUE in order to avoid packet batching */ - g_socket_set_option (gsock, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL); - - gaddr = g_socket_get_remote_address (gsock, NULL); - if (gaddr == NULL || - !g_socket_address_to_native (gaddr, &name.addr, sizeof (name), NULL)) { - g_socket_close (gsock, NULL); - g_object_unref (gsock); - return NULL; - } - g_object_unref (gaddr); - - nice_address_set_from_sockaddr (&remote_addr, &name.addr); - - new_socket = nice_tcp_bsd_socket_new_from_gsock (priv->context, gsock, - &sock->addr, &remote_addr, TRUE); - g_object_unref (gsock); - - if (new_socket) { - NiceAddress *key = nice_address_dup (&remote_addr); - - nice_tcp_bsd_socket_set_passive_parent (new_socket, sock); - - nice_socket_set_writable_callback (new_socket, _child_writable_cb, sock); - g_hash_table_insert (priv->connections, key, new_socket); - } - return new_socket; -} - -static guint nice_address_hash (const NiceAddress * key) -{ - gchar ip[INET6_ADDRSTRLEN]; - gchar *str; - guint hash; - - nice_address_to_string (key, ip); - str = g_strdup_printf ("%s:%u", ip, nice_address_get_port (key)); - hash = g_str_hash (str); - g_free (str); - - return hash; -} - -void nice_tcp_passive_socket_remove_connection (NiceSocket *sock, const NiceAddress *to) -{ - TcpPassivePriv *priv = sock->priv; - - g_hash_table_remove (priv->connections, to); -} diff --git a/socket/tcp-passive.h b/socket/tcp-passive.h deleted file mode 100644 index 914f081..0000000 --- a/socket/tcp-passive.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2012 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * George Kiagiadakis, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _TCP_PASSIVE_H -#define _TCP_PASSIVE_H - -#include "socket.h" - -G_BEGIN_DECLS - - -NiceSocket * nice_tcp_passive_socket_new (GMainContext *ctx, NiceAddress *addr); -NiceSocket * nice_tcp_passive_socket_accept (NiceSocket *socket); - -void nice_tcp_passive_socket_remove_connection (NiceSocket *socket, - const NiceAddress *to); - - -G_END_DECLS - -#endif /* _TCP_PASSIVE_H */ - diff --git a/socket/udp-bsd.c b/socket/udp-bsd.c deleted file mode 100644 index 65974c2..0000000 --- a/socket/udp-bsd.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * Implementation of UDP socket interface using Berkeley sockets. (See - * http://en.wikipedia.org/wiki/Berkeley_sockets.) - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - - -#include -#include -#include - -#include "udp-bsd.h" -#include "agent-priv.h" - -#ifndef G_OS_WIN32 -#include -#endif - - -static void socket_close (NiceSocket *sock); -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages); -static gboolean socket_is_reliable (NiceSocket *sock); -static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr); -static void socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); - -struct UdpBsdSocketPrivate -{ - GMutex mutex; - - /* protected by mutex */ - NiceAddress niceaddr; - GSocketAddress *gaddr; -}; - -NiceSocket * -nice_udp_bsd_socket_new (NiceAddress *addr) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } name; - NiceSocket *sock = g_slice_new0 (NiceSocket); - GSocket *gsock = NULL; - gboolean gret = FALSE; - GSocketAddress *gaddr; - struct UdpBsdSocketPrivate *priv; - - if (addr != NULL) { - nice_address_copy_to_sockaddr(addr, &name.addr); - } else { - memset (&name, 0, sizeof (name)); - name.storage.ss_family = AF_UNSPEC; - } - - if (name.storage.ss_family == AF_UNSPEC || name.storage.ss_family == AF_INET) { - gsock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, - G_SOCKET_PROTOCOL_UDP, NULL); - name.storage.ss_family = AF_INET; -#ifdef HAVE_SA_LEN - name.storage.ss_len = sizeof (struct sockaddr_in); -#endif - } else if (name.storage.ss_family == AF_INET6) { - gsock = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_DATAGRAM, - G_SOCKET_PROTOCOL_UDP, NULL); - name.storage.ss_family = AF_INET6; -#ifdef HAVE_SA_LEN - name.storage.ss_len = sizeof (struct sockaddr_in6); -#endif - } - - if (gsock == NULL) { - g_slice_free (NiceSocket, sock); - return NULL; - } - - /* GSocket: All socket file descriptors are set to be close-on-exec. */ - g_socket_set_blocking (gsock, false); - gaddr = g_socket_address_new_from_native (&name.addr, sizeof (name)); - if (gaddr != NULL) { - gret = g_socket_bind (gsock, gaddr, FALSE, NULL); - g_object_unref (gaddr); - } - - if (gret == FALSE) { - g_slice_free (NiceSocket, sock); - g_socket_close (gsock, NULL); - g_object_unref (gsock); - return NULL; - } - - gaddr = g_socket_get_local_address (gsock, NULL); - if (gaddr == NULL || - !g_socket_address_to_native (gaddr, &name, sizeof(name), NULL)) { - g_slice_free (NiceSocket, sock); - g_socket_close (gsock, NULL); - g_object_unref (gsock); - return NULL; - } - - g_object_unref (gaddr); - - nice_address_set_from_sockaddr (&sock->addr, &name.addr); - - priv = sock->priv = g_slice_new0 (struct UdpBsdSocketPrivate); - nice_address_init (&priv->niceaddr); - - sock->type = NICE_SOCKET_TYPE_UDP_BSD; - sock->fileno = gsock; - sock->send_messages = socket_send_messages; - sock->send_messages_reliable = socket_send_messages_reliable; - sock->recv_messages = socket_recv_messages; - sock->is_reliable = socket_is_reliable; - sock->can_send = socket_can_send; - sock->set_writable_callback = socket_set_writable_callback; - sock->close = socket_close; - - g_mutex_init (&priv->mutex); - - return sock; -} - -static void -socket_close (NiceSocket *sock) -{ - struct UdpBsdSocketPrivate *priv = sock->priv; - - g_clear_object (&priv->gaddr); - g_mutex_clear (&priv->mutex); - g_slice_free (struct UdpBsdSocketPrivate, sock->priv); - sock->priv = NULL; - - if (sock->fileno) { - g_socket_close (sock->fileno, NULL); - g_object_unref (sock->fileno); - sock->fileno = NULL; - } -} - -static gint -socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages) -{ - guint i; - gboolean error = FALSE; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - /* Read messages into recv_messages until one fails or would block, or we - * reach the end. */ - for (i = 0; i < n_recv_messages; i++) { - NiceInputMessage *recv_message = &recv_messages[i]; - GSocketAddress *gaddr = NULL; - GError *gerr = NULL; - gssize recvd; - gint flags = G_SOCKET_MSG_NONE; - - recvd = g_socket_receive_message (sock->fileno, - (recv_message->from != NULL) ? &gaddr : NULL, - recv_message->buffers, recv_message->n_buffers, NULL, NULL, - &flags, NULL, &gerr); - - if (recvd < 0) { - /* Handle ECONNRESET here as if it were EWOULDBLOCK; see - * https://phabricator.freedesktop.org/T121 */ - if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) || - g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED)) - recvd = 0; - else if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_MESSAGE_TOO_LARGE)) - recvd = input_message_get_size (recv_message); - else - error = TRUE; - - g_error_free (gerr); - } - - recv_message->length = MAX (recvd, 0); - - if (recvd > 0 && recv_message->from != NULL && gaddr != NULL) { - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sa; - - g_socket_address_to_native (gaddr, &sa, sizeof (sa), NULL); - nice_address_set_from_sockaddr (recv_message->from, &sa.addr); - } - - if (gaddr != NULL) - g_object_unref (gaddr); - - /* Return early on error or EWOULDBLOCK. */ - if (recvd <= 0) - break; - } - - /* Was there an error processing the first message? */ - if (error && i == 0) - return -1; - - return i; -} - -static gssize -socket_send_message (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *message) -{ - struct UdpBsdSocketPrivate *priv = sock->priv; - GError *child_error = NULL; - gssize len; - GSocketAddress *gaddr = NULL; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - g_mutex_lock (&priv->mutex); - if (!nice_address_is_valid (&priv->niceaddr) || - !nice_address_equal (&priv->niceaddr, to)) { - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sa; - - g_clear_object (&priv->gaddr); - - nice_address_copy_to_sockaddr (to, &sa.addr); - gaddr = g_socket_address_new_from_native (&sa.addr, sizeof(sa)); - if (gaddr) - priv->gaddr = g_object_ref (gaddr); - - if (gaddr == NULL) { - g_mutex_unlock (&priv->mutex); - return -1; - } - - priv->niceaddr = *to; - } else { - if (priv->gaddr) - gaddr = g_object_ref (priv->gaddr); - } - g_mutex_unlock (&priv->mutex); - - len = g_socket_send_message (sock->fileno, gaddr, message->buffers, - message->n_buffers, NULL, 0, G_SOCKET_MSG_NONE, NULL, &child_error); - - if (len < 0) { - if (g_error_matches (child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - len = 0; - } else if (nice_debug_is_verbose()) { - union { - struct sockaddr_storage ss; - struct sockaddr sa; - } sa; - GSocketAddress *gsocket; - NiceAddress local_addr; - NiceAddress remote_addr; - char remote_addr_str[INET6_ADDRSTRLEN]; - char local_addr_str[INET6_ADDRSTRLEN]; - - g_socket_address_to_native (gaddr, &sa, sizeof (sa), NULL); - nice_address_set_from_sockaddr (&remote_addr, &sa.sa); - nice_address_to_string (&remote_addr, remote_addr_str); - - gsocket = g_socket_get_local_address (sock->fileno, NULL); - g_socket_address_to_native (gsocket, &sa, sizeof (sa), NULL); - nice_address_set_from_sockaddr (&local_addr, &sa.sa); - nice_address_to_string (&local_addr, local_addr_str); - g_object_unref (gsocket); - - nice_debug_verbose ("%s: udp-bsd socket %p %s:%u -> %s:%u: error: %s", - G_STRFUNC, sock, - local_addr_str, nice_address_get_port (&local_addr), - remote_addr_str, nice_address_get_port (&remote_addr), - child_error->message); - } - - g_error_free (child_error); - } - - g_clear_object (&gaddr); - - return len; -} - -static gint -socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - guint i; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - for (i = 0; i < n_messages; i++) { - const NiceOutputMessage *message = &messages[i]; - gssize len; - - len = socket_send_message (sock, to, message); - - if (len < 0) { - /* Error. */ - if (i > 0) - break; - return len; - } else if (len == 0) { - /* EWOULDBLOCK. */ - break; - } - } - - return i; -} - -static gint -socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - return -1; -} - -static gboolean -socket_is_reliable (NiceSocket *sock) -{ - return FALSE; -} - -static gboolean -socket_can_send (NiceSocket *sock, NiceAddress *addr) -{ - return TRUE; -} - -static void -socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data) -{ -} - diff --git a/socket/udp-bsd.h b/socket/udp-bsd.h deleted file mode 100644 index c8d6190..0000000 --- a/socket/udp-bsd.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2009 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _UDP_BSD_H -#define _UDP_BSD_H - -#include "socket.h" - -G_BEGIN_DECLS - -NiceSocket * -nice_udp_bsd_socket_new (NiceAddress *addr); - -G_END_DECLS - -#endif /* _UDP_BSD_H */ - diff --git a/socket/udp-turn-over-tcp.c b/socket/udp-turn-over-tcp.c deleted file mode 100644 index 2b91f92..0000000 --- a/socket/udp-turn-over-tcp.c +++ /dev/null @@ -1,465 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See - * http://en.wikipedia.org/wiki/Berkeley_sockets.) - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "udp-turn-over-tcp.h" -#include "agent-priv.h" - -#include -#include -#include - -#ifndef G_OS_WIN32 -#include -#endif - -typedef struct { - NiceTurnSocketCompatibility compatibility; - union { - guint8 u8[65536]; - guint16 u16[32768]; - } recv_buf; - gsize recv_buf_len; /* in bytes */ - guint expecting_len; - NiceSocket *base_socket; -} TurnTcpPriv; - -typedef enum { - MS_TURN_CONTROL_MESSAGE = 2, - MS_TURN_END_TO_END_DATA = 3 -} MsTurnPayloadType; - -#define MAX_UDP_MESSAGE_SIZE 65535 - -#define MAGIC_COOKIE_OFFSET \ - STUN_MESSAGE_HEADER_LENGTH + STUN_MESSAGE_TYPE_LEN + \ - STUN_MESSAGE_LENGTH_LEN + sizeof(guint16) - -static void socket_close (NiceSocket *sock); -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages); -static gboolean socket_is_reliable (NiceSocket *sock); -static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr); -static void socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); -static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other); - -NiceSocket * -nice_udp_turn_over_tcp_socket_new (NiceSocket *base_socket, - NiceTurnSocketCompatibility compatibility) -{ - TurnTcpPriv *priv; - NiceSocket *sock = g_slice_new0 (NiceSocket); - sock->priv = priv = g_slice_new0 (TurnTcpPriv); - - priv->compatibility = compatibility; - priv->base_socket = base_socket; - - sock->type = NICE_SOCKET_TYPE_UDP_TURN_OVER_TCP; - sock->fileno = priv->base_socket->fileno; - sock->addr = priv->base_socket->addr; - sock->send_messages = socket_send_messages; - sock->send_messages_reliable = socket_send_messages_reliable; - sock->recv_messages = socket_recv_messages; - sock->is_reliable = socket_is_reliable; - sock->can_send = socket_can_send; - sock->set_writable_callback = socket_set_writable_callback; - sock->is_based_on = socket_is_based_on; - sock->close = socket_close; - - return sock; -} - - -static void -socket_close (NiceSocket *sock) -{ - TurnTcpPriv *priv = sock->priv; - - if (priv->base_socket) - nice_socket_free (priv->base_socket); - - g_slice_free(TurnTcpPriv, sock->priv); - sock->priv = NULL; -} - -static gssize -socket_recv_message (NiceSocket *sock, NiceInputMessage *recv_message) -{ - TurnTcpPriv *priv = sock->priv; - gssize ret; - guint padlen; - GInputVector local_recv_buf; - NiceInputMessage local_recv_message; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - if (priv->expecting_len == 0) { - guint headerlen = 0; - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) - headerlen = 4; - else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) - headerlen = 2; - else - return -1; - - local_recv_buf.buffer = priv->recv_buf.u8 + priv->recv_buf_len; - local_recv_buf.size = headerlen - priv->recv_buf_len; - local_recv_message.buffers = &local_recv_buf; - local_recv_message.n_buffers = 1; - local_recv_message.from = recv_message->from; - local_recv_message.length = 0; - - ret = nice_socket_recv_messages (priv->base_socket, &local_recv_message, 1); - if (ret < 0) - return ret; - - priv->recv_buf_len += local_recv_message.length; - - if (priv->recv_buf_len < headerlen) - return 0; - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) { - guint16 magic = ntohs (*priv->recv_buf.u16); - guint16 packetlen = ntohs (*(priv->recv_buf.u16 + 1)); - - if (magic < 0x4000) { - /* Its STUN */ - priv->expecting_len = 20 + packetlen; - } else { - /* Channel data */ - priv->expecting_len = 4 + packetlen; - } - } - else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) { - guint compat_len = ntohs (*priv->recv_buf.u16); - priv->expecting_len = compat_len; - priv->recv_buf_len = 0; - } - else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) { - guint8 pt = *priv->recv_buf.u8; - guint16 packetlen = ntohs (priv->recv_buf.u16[1]); - - if (pt != MS_TURN_CONTROL_MESSAGE && - pt != MS_TURN_END_TO_END_DATA) { - /* Unexpected data, error in stream */ - return -1; - } - - /* Keep the RFC4571 framing for the NiceAgent to unframe */ - priv->expecting_len = packetlen + sizeof(guint16); - priv->recv_buf_len = sizeof(guint16); - priv->recv_buf.u16[0] = priv->recv_buf.u16[1]; - } - } - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) - padlen = (priv->expecting_len % 4) ? 4 - (priv->expecting_len % 4) : 0; - else - padlen = 0; - - local_recv_buf.buffer = priv->recv_buf.u8 + priv->recv_buf_len; - local_recv_buf.size = priv->expecting_len + padlen - priv->recv_buf_len; - local_recv_message.buffers = &local_recv_buf; - local_recv_message.n_buffers = 1; - local_recv_message.from = recv_message->from; - local_recv_message.length = 0; - - ret = nice_socket_recv_messages (priv->base_socket, &local_recv_message, 1); - if (ret < 0) - return ret; - - priv->recv_buf_len += local_recv_message.length; - - if (priv->recv_buf_len == priv->expecting_len + padlen) { - /* FIXME: Eliminate this memcpy(). */ - ret = memcpy_buffer_to_input_message (recv_message, - priv->recv_buf.u8, priv->recv_buf_len); - - priv->expecting_len = 0; - priv->recv_buf_len = 0; - - return ret; - } - - return 0; -} - -static gint -socket_recv_messages (NiceSocket *nicesock, - NiceInputMessage *recv_messages, guint n_recv_messages) -{ - guint i; - gboolean error = FALSE; - - /* Make sure socket has not been freed: */ - g_assert (nicesock->priv != NULL); - - for (i = 0; i < n_recv_messages; i++) { - gssize len; - - len = socket_recv_message (nicesock, &recv_messages[i]); - recv_messages[i].length = MAX (len, 0); - - if (len < 0) - error = TRUE; - - if (len <= 0) - break; - } - - /* Was there an error processing the first message? */ - if (error && i == 0) - return -1; - - return i; -} - -static gssize -socket_send_message (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *message, gboolean reliable) -{ - TurnTcpPriv *priv = sock->priv; - guint8 padbuf[3] = {0, 0, 0}; - GOutputVector *local_bufs; - NiceOutputMessage local_message; - guint j; - gint ret; - guint n_bufs; - union { - guint16 google_len; - struct { - guint8 pt; - guint8 zero; - } msoc; - } header_buf; - guint offset = 0; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - /* Count the number of buffers. */ - if (message->n_buffers == -1) { - n_bufs = 0; - - for (j = 0; message->buffers[j].buffer != NULL; j++) - n_bufs++; - } else { - n_bufs = message->n_buffers; - } - - /* Allocate a new array of buffers, covering all the buffers in the input - * @message, but with an additional one for a header and one for a footer. */ - local_bufs = g_alloca ((n_bufs + 1) * sizeof (GOutputVector)); - local_message.buffers = local_bufs; - local_message.n_buffers = n_bufs + 1; - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) { - header_buf.google_len = htons (output_message_get_size (message)); - local_bufs[0].buffer = &header_buf; - local_bufs[0].size = sizeof (guint16); - offset = 1; - } else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) { - gsize message_len = output_message_get_size (message); - gsize padlen = (message_len % 4) ? 4 - (message_len % 4) : 0; - - local_bufs[n_bufs].buffer = &padbuf; - local_bufs[n_bufs].size = padlen; - } else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) { - union { - guint32 u32; - guint8 u8[4]; - } cookie; - guint16 len = output_message_get_size (message); - - /* Copy the cookie from possibly split messages */ - cookie.u32 = 0; - if (len > sizeof (TURN_MAGIC_COOKIE) + MAGIC_COOKIE_OFFSET) { - guint16 buf_offset = 0; - guint i; - - for (i = 0; i < n_bufs; i++) { - if (message->buffers[i].size > - (gsize) (MAGIC_COOKIE_OFFSET - buf_offset)) { - /* If the cookie is split, we assume it's data */ - if (message->buffers[i].size > sizeof (TURN_MAGIC_COOKIE) + - MAGIC_COOKIE_OFFSET - buf_offset) { - const guint8 *buf = message->buffers[i].buffer; - memcpy (&cookie.u8, buf + MAGIC_COOKIE_OFFSET - buf_offset, - sizeof (TURN_MAGIC_COOKIE)); - } - break; - } else { - buf_offset += message->buffers[i].size; - } - } - } - - cookie.u32 = ntohl(cookie.u32); - header_buf.msoc.zero = 0; - if (cookie.u32 == TURN_MAGIC_COOKIE) - header_buf.msoc.pt = MS_TURN_CONTROL_MESSAGE; - else - header_buf.msoc.pt = MS_TURN_END_TO_END_DATA; - - local_bufs[0].buffer = &header_buf; - local_bufs[0].size = sizeof(header_buf.msoc); - offset = 1; - } else { - local_message.n_buffers = n_bufs; - } - - /* Copy the existing buffers across. */ - for (j = 0; j < n_bufs; j++) { - local_bufs[j + offset].buffer = message->buffers[j].buffer; - local_bufs[j + offset].size = message->buffers[j].size; - } - - - if (reliable) - ret = nice_socket_send_messages_reliable (priv->base_socket, to, - &local_message, 1); - else - ret = nice_socket_send_messages (priv->base_socket, to, &local_message, 1); - - if (ret == 1) - ret = output_message_get_size (&local_message); - - return ret; -} - -static gint -socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - guint i; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - for (i = 0; i < n_messages; i++) { - const NiceOutputMessage *message = &messages[i]; - gssize len; - - len = socket_send_message (sock, to, message, FALSE); - - if (len < 0) { - /* Error. */ - if (i > 0) - break; - return len; - } else if (len == 0) { - /* EWOULDBLOCK. */ - break; - } - } - - return i; -} - -static gint -socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - guint i; - - for (i = 0; i < n_messages; i++) { - const NiceOutputMessage *message = &messages[i]; - gssize len; - - len = socket_send_message (sock, to, message, TRUE); - - if (len < 0) { - /* Error. */ - return len; - } - } - - return i; -} - - -static gboolean -socket_is_reliable (NiceSocket *sock) -{ - TurnTcpPriv *priv = sock->priv; - - return nice_socket_is_reliable (priv->base_socket); -} - -static gboolean -socket_can_send (NiceSocket *sock, NiceAddress *addr) -{ - TurnTcpPriv *priv = sock->priv; - - return nice_socket_can_send (priv->base_socket, addr); -} - -static void -socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data) -{ - TurnTcpPriv *priv = sock->priv; - - nice_socket_set_writable_callback (priv->base_socket, callback, user_data); -} - -static gboolean -socket_is_based_on (NiceSocket *sock, NiceSocket *other) -{ - TurnTcpPriv *priv = sock->priv; - - return (sock == other) || - (priv && nice_socket_is_based_on (priv->base_socket, other)); -} diff --git a/socket/udp-turn-over-tcp.h b/socket/udp-turn-over-tcp.h deleted file mode 100644 index 92e79b8..0000000 --- a/socket/udp-turn-over-tcp.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _UDP_TURN_OVER_TCP_H -#define _UDP_TURN_OVER_TCP_H - -#include "socket.h" -#include "agent.h" - -G_BEGIN_DECLS - - -NiceSocket * -nice_udp_turn_over_tcp_socket_new (NiceSocket *base_socket, - NiceTurnSocketCompatibility compatibility); - - -G_END_DECLS - -#endif /* _UDP_TURN_OVER_TCP_H */ - diff --git a/socket/udp-turn.c b/socket/udp-turn.c deleted file mode 100644 index b0a2a02..0000000 --- a/socket/udp-turn.c +++ /dev/null @@ -1,2275 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* - * Implementation of TURN - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include - -#include "udp-turn.h" -#include "stun/stunagent.h" -#include "stun/usages/timer.h" -#include "agent-priv.h" - -#define STUN_END_TIMEOUT 8000 -#define STUN_MAX_MS_REALM_LEN 128 // as defined in [MS-TURN] -#define STUN_EXPIRE_TIMEOUT 60 /* Time we refresh before expiration */ -#define STUN_PERMISSION_TIMEOUT (300 - STUN_EXPIRE_TIMEOUT) /* 240 s */ -#define STUN_BINDING_TIMEOUT (600 - STUN_EXPIRE_TIMEOUT) /* 540 s */ - -static GMutex mutex; - -typedef struct { - StunMessage message; - uint8_t buffer[STUN_MAX_MESSAGE_SIZE]; - StunTimer timer; -} TURNMessage; - -typedef struct { - NiceAddress peer; - uint16_t channel; - gboolean renew; - GSource *timeout_source; -} ChannelBinding; - -typedef struct { - GMainContext *ctx; - StunAgent agent; - GList *channels; - GList *pending_bindings; - ChannelBinding *current_binding; - TURNMessage *current_binding_msg; - GList *pending_permissions; - GSource *tick_source_channel_bind; - GSource *tick_source_create_permission; - NiceSocket *base_socket; - NiceAddress server_addr; - uint8_t *username; - gsize username_len; - uint8_t *password; - gsize password_len; - NiceTurnSocketCompatibility compatibility; - GQueue *send_requests; - uint8_t ms_realm[STUN_MAX_MS_REALM_LEN + 1]; - uint8_t ms_connection_id[20]; - uint32_t ms_sequence_num; - bool ms_connection_id_valid; - GList *permissions; /* the peers (NiceAddress) for which - there is an installed permission */ - GList *sent_permissions; /* ongoing permission installed */ - GHashTable *send_data_queues; /* stores a send data queue for per peer */ - GSource *permission_timeout_source; /* timer used to invalidate - permissions */ - - guint8 *cached_realm; - uint16_t cached_realm_len; - guint8 *cached_nonce; - uint16_t cached_nonce_len; - - GByteArray *fragment_buffer; - NiceAddress from; -} UdpTurnPriv; - - -typedef struct { - StunTransactionId id; - GSource *source; - UdpTurnPriv *priv; -} SendRequest; - -/* used to store data sent while obtaining a permission */ -typedef struct { - gchar *data; - guint data_len; - gboolean reliable; -} SendData; - -static void socket_close (NiceSocket *sock); -static gint socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages); -static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages); -static gint socket_send_messages_reliable (NiceSocket *sock, - const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages); -static gboolean socket_is_reliable (NiceSocket *sock); -static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr); -static void socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data); -static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other); - -static void priv_process_pending_bindings (UdpTurnPriv *priv); -static gboolean priv_retransmissions_tick_unlocked (UdpTurnPriv *priv); -static gboolean priv_retransmissions_tick (gpointer pointer); -static void priv_schedule_tick (UdpTurnPriv *priv); -static void priv_send_turn_message (UdpTurnPriv *priv, TURNMessage *msg); -static gboolean priv_send_create_permission (UdpTurnPriv *priv, - const NiceAddress *peer); -static gboolean priv_send_channel_bind (UdpTurnPriv *priv, - uint16_t channel, - const NiceAddress *peer); -static gboolean priv_add_channel_binding (UdpTurnPriv *priv, - const NiceAddress *peer); -static gboolean priv_forget_send_request_timeout (gpointer pointer); -static void priv_clear_permissions (UdpTurnPriv *priv); - -static void -send_request_free (SendRequest *r) -{ - g_source_destroy (r->source); - g_source_unref (r->source); - - stun_agent_forget_transaction (&r->priv->agent, r->id); - - g_slice_free (SendRequest, r); -} - -static guint -priv_nice_address_hash (gconstpointer data) -{ - gchar address[NICE_ADDRESS_STRING_LEN]; - - nice_address_to_string ((NiceAddress *) data, address); - - return g_str_hash(address); -} - -static void -priv_send_data_queue_destroy (gpointer user_data) -{ - GQueue *send_queue = (GQueue *) user_data; - GList *i; - - for (i = g_queue_peek_head_link (send_queue); i; i = i->next) { - SendData *data = (SendData *) i->data; - - g_free (data->data); - g_slice_free (SendData, data); - } - g_queue_free (send_queue); -} - -NiceSocket * -nice_udp_turn_socket_new (GMainContext *ctx, NiceAddress *addr, - NiceSocket *base_socket, const NiceAddress *server_addr, - const gchar *username, const gchar *password, - NiceTurnSocketCompatibility compatibility) -{ - UdpTurnPriv *priv; - NiceSocket *sock = g_slice_new0 (NiceSocket); - - if (!sock) { - return NULL; - } - - priv = g_new0 (UdpTurnPriv, 1); - - if (compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 || - compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) { - stun_agent_init (&priv->agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC5389, - STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS); - } else if (compatibility == NICE_TURN_SOCKET_COMPATIBILITY_MSN) { - stun_agent_init (&priv->agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC3489, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS | - STUN_AGENT_USAGE_NO_INDICATION_AUTH); - } else if (compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) { - stun_agent_init (&priv->agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC3489, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS | - STUN_AGENT_USAGE_IGNORE_CREDENTIALS); - } else if (compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) { - stun_agent_init (&priv->agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_OC2007, - STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS | - STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES); - } - - priv->channels = NULL; - priv->current_binding = NULL; - priv->base_socket = base_socket; - if (ctx) - priv->ctx = g_main_context_ref (ctx); - - if (compatibility == NICE_TURN_SOCKET_COMPATIBILITY_MSN || - compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) { - priv->username = g_base64_decode (username, &priv->username_len); - priv->password = g_base64_decode (password, &priv->password_len); - } else { - priv->username = (uint8_t *)g_strdup (username); - priv->username_len = (gsize) strlen (username); - if (compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) { - priv->password = NULL; - priv->password_len = 0; - } else { - priv->password = (uint8_t *)g_strdup (password); - priv->password_len = (gsize) strlen (password); - } - } - priv->server_addr = *server_addr; - priv->compatibility = compatibility; - priv->send_requests = g_queue_new (); - - priv->send_data_queues = - g_hash_table_new_full (priv_nice_address_hash, - (GEqualFunc) nice_address_equal, - (GDestroyNotify) nice_address_free, - priv_send_data_queue_destroy); - - sock->type = NICE_SOCKET_TYPE_UDP_TURN; - sock->fileno = NULL; - sock->addr = *addr; - sock->send_messages = socket_send_messages; - sock->send_messages_reliable = socket_send_messages_reliable; - sock->recv_messages = socket_recv_messages; - sock->is_reliable = socket_is_reliable; - sock->can_send = socket_can_send; - sock->set_writable_callback = socket_set_writable_callback; - sock->is_based_on = socket_is_based_on; - sock->close = socket_close; - sock->priv = (void *) priv; - - return sock; -} - - - -static void -socket_close (NiceSocket *sock) -{ - UdpTurnPriv *priv = (UdpTurnPriv *) sock->priv; - GList *i = NULL; - - g_mutex_lock (&mutex); - - for (i = priv->channels; i; i = i->next) { - ChannelBinding *b = i->data; - if (b->timeout_source) { - g_source_destroy (b->timeout_source); - g_source_unref (b->timeout_source); - } - g_free (b); - } - g_list_free (priv->channels); - - g_list_free_full (priv->pending_bindings, (GDestroyNotify) nice_address_free); - - if (priv->tick_source_channel_bind != NULL) { - g_source_destroy (priv->tick_source_channel_bind); - g_source_unref (priv->tick_source_channel_bind); - priv->tick_source_channel_bind = NULL; - } - - if (priv->tick_source_create_permission != NULL) { - g_source_destroy (priv->tick_source_create_permission); - g_source_unref (priv->tick_source_create_permission); - priv->tick_source_create_permission = NULL; - } - - g_queue_free_full (priv->send_requests, (GDestroyNotify) send_request_free); - - priv_clear_permissions (priv); - g_list_free_full (priv->sent_permissions, (GDestroyNotify) nice_address_free); - g_hash_table_destroy (priv->send_data_queues); - - if (priv->permission_timeout_source) { - g_source_destroy (priv->permission_timeout_source); - g_source_unref (priv->permission_timeout_source); - priv->permission_timeout_source = NULL; - } - - if (priv->ctx) - g_main_context_unref (priv->ctx); - - g_free (priv->current_binding); - g_free (priv->current_binding_msg); - g_list_free_full (priv->pending_permissions, g_free); - g_free (priv->username); - g_free (priv->password); - g_free (priv->cached_realm); - g_free (priv->cached_nonce); - - if (priv->fragment_buffer) { - g_byte_array_free(priv->fragment_buffer, TRUE); - } - - g_free (priv); - - sock->priv = NULL; - - g_mutex_unlock (&mutex); -} - -static gint -socket_recv_messages (NiceSocket *sock, - NiceInputMessage *recv_messages, guint n_recv_messages) -{ - UdpTurnPriv *priv = (UdpTurnPriv *) sock->priv; - gint n_messages; - gint n_output_messages = 0; - guint i; - gboolean error = FALSE; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - nice_debug_verbose ("received message on TURN socket"); - - if (priv->fragment_buffer) { - /* Fill as many recv_messages as possible with RFC4571-framed data we - * already hold in our buffer before reading more from the base socket. */ - guint8 *f_buffer = priv->fragment_buffer->data; - guint f_buffer_len = priv->fragment_buffer->len; - - for (i = 0; i < n_recv_messages && f_buffer_len >= sizeof (guint16); ++i) { - guint32 msg_len = ((f_buffer[0] << 8) | f_buffer[1]) + sizeof (guint16); - - if (msg_len > f_buffer_len) { - /* The next message in the buffer isn't complete yet. Wait for more - * data from the base socket. */ - break; - } - - /* We have a full message in the buffer. Copy it into the user-provided - * NiceInputMessage. */ - memcpy_buffer_to_input_message (&recv_messages[i], f_buffer, msg_len); - *recv_messages[i].from = priv->from; - - f_buffer += msg_len; - f_buffer_len -= msg_len; - ++n_output_messages; - } - - /* Adjust recv_messages with the number of messages we've just filled. */ - recv_messages += n_output_messages; - n_recv_messages -= n_output_messages; - - /* Shrink the fragment buffer, deallocate it if empty. */ - g_byte_array_remove_range (priv->fragment_buffer, 0, - priv->fragment_buffer->len - f_buffer_len); - if (priv->fragment_buffer->len == 0) { - g_byte_array_free (priv->fragment_buffer, TRUE); - priv->fragment_buffer = NULL; - } - } - - n_messages = nice_socket_recv_messages (priv->base_socket, - recv_messages, n_recv_messages); - - if (n_messages < 0) - return n_messages; - - /* Process all the messages. Those which fail parsing are re-used for the next - * message. - * - * FIXME: This needs a fast path which avoids allocations or memcpy()s. - * Implementing such a path means rewriting the TURN parser (and hence the - * STUN message code) to operate on vectors of buffers, rather than a - * monolithic buffer. */ - for (i = 0; i < (guint) n_messages; ++i) { - NiceInputMessage *message = &recv_messages[i]; - NiceSocket *dummy; - NiceAddress from; - guint8 *buffer; - gsize buffer_length; - gint parsed_buffer_length; - gboolean allocated_buffer = FALSE; - - if (message->length == 0) - continue; - - /* Compact the message’s buffers into a single one for parsing. Avoid this - * in the (hopefully) common case of a single-element buffer vector. */ - if (message->n_buffers == 1 || - (message->n_buffers == -1 && - message->buffers[0].buffer != NULL && - message->buffers[1].buffer == NULL)) { - buffer = message->buffers[0].buffer; - buffer_length = message->length; - } else { - nice_debug_verbose ("%s: **WARNING: SLOW PATH**", G_STRFUNC); - - buffer = compact_input_message (message, &buffer_length); - allocated_buffer = TRUE; - } - - /* Parse in-place. */ - parsed_buffer_length = nice_udp_turn_socket_parse_recv (sock, &dummy, - &from, buffer_length, buffer, - message->from, buffer, buffer_length); - message->length = MAX (parsed_buffer_length, 0); - - if (parsed_buffer_length < 0) { - error = TRUE; - } else if (parsed_buffer_length > 0) { - *message->from = from; - } - /* parsed_buffer_length == 0 means this is a TURN control message which - * needs ignoring. */ - - if (nice_socket_is_reliable (sock) && parsed_buffer_length > 0) { - /* Determine the portion of the current NiceInputMessage we can already - * return. */ - gint32 msg_len = 0; - if (!priv->fragment_buffer) { - msg_len = ((buffer[0] << 8) | buffer[1]) + sizeof (guint16); - if (msg_len > parsed_buffer_length) { - /* The RFC4571 frame is larger than the current TURN message, need to - * buffer it and wait for more data. */ - msg_len = 0; - } - } - - if (msg_len != parsed_buffer_length && !priv->fragment_buffer) { - /* Start of message fragmenting detected. Allocate fragment buffer - * large enough for the recv_message's we haven't parsed yet. */ - gint j; - guint buffer_len = 0; - - for (j = i; j < n_messages; ++j) { - buffer_len += recv_messages[j].length; - } - priv->fragment_buffer = g_byte_array_sized_new (buffer_len); - } - - if (priv->fragment_buffer) { - /* The messages are fragmented. Store the excess data (after msg_len - * bytes) into fragment buffer for reassembly. */ - g_byte_array_append (priv->fragment_buffer, buffer + msg_len, - parsed_buffer_length - msg_len); - - parsed_buffer_length = msg_len; - message->length = msg_len; - priv->from = from; - } - } - - /* Split up the monolithic buffer again into the caller-provided buffers. */ - if (parsed_buffer_length > 0 && allocated_buffer) { - memcpy_buffer_to_input_message (message, buffer, - parsed_buffer_length); - } - - if (allocated_buffer) - g_free (buffer); - - if (error) - break; - - ++n_output_messages; - } - - /* Was there an error processing the first message? */ - if (error && i == 0) - return -1; - - return n_output_messages; -} - -/* interval is given in milliseconds */ -static GSource * -priv_timeout_add_with_context (UdpTurnPriv *priv, guint interval, - GSourceFunc function, gpointer data) -{ - GSource *source = NULL; - - g_return_val_if_fail (function != NULL, NULL); - - source = g_timeout_source_new (interval); - - g_source_set_callback (source, function, data, NULL); - g_source_attach (source, priv->ctx); - - return source; -} - -/* interval is given in seconds */ -static GSource * -priv_timeout_add_seconds_with_context (UdpTurnPriv *priv, guint interval, - GSourceFunc function, gpointer data) -{ - GSource *source = NULL; - - g_return_val_if_fail (function != NULL, NULL); - - source = g_timeout_source_new_seconds (interval); - - g_source_set_callback (source, function, data, NULL); - g_source_attach (source, priv->ctx); - - return source; -} - -static StunMessageReturn -stun_message_append_ms_connection_id(StunMessage *msg, - uint8_t *ms_connection_id, uint32_t ms_sequence_num) -{ - union { - uint8_t buf8[24]; - uint32_t buf32[24/4]; - } buf; - - memcpy(buf.buf8, ms_connection_id, 20); - buf.buf32[5] = htonl(ms_sequence_num); - return stun_message_append_bytes (msg, STUN_ATTRIBUTE_MS_SEQUENCE_NUMBER, - buf.buf8, 24); -} - -static void -stun_message_ensure_ms_realm(StunMessage *msg, uint8_t *realm) -{ - /* With MS-TURN, original clients do not send REALM attribute in Send and Set - * Active Destination requests, but use it to compute MESSAGE-INTEGRITY. We - * simply append cached realm value to the message and use it in subsequent - * stun_agent_finish_message() call. Messages with this additional attribute - * are handled correctly on OCS Access Edge working as TURN server. */ - if (stun_message_get_method(msg) == STUN_SEND || - stun_message_get_method(msg) == STUN_OLD_SET_ACTIVE_DST) { - stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, - strlen((char *)realm)); - } -} - -static gboolean -priv_is_peer_in_list (const GList *list, const NiceAddress *peer) -{ - const GList *iter; - - for (iter = list ; iter ; iter = g_list_next (iter)) { - NiceAddress *address = (NiceAddress *) iter->data; - - if (nice_address_equal (address, peer)) - return TRUE; - } - - return FALSE; -} - -static gboolean -priv_has_permission_for_peer (UdpTurnPriv *priv, const NiceAddress *peer) -{ - return priv_is_peer_in_list (priv->permissions, peer); -} - -static gboolean -priv_has_sent_permission_for_peer (UdpTurnPriv *priv, const NiceAddress *peer) -{ - return priv_is_peer_in_list (priv->sent_permissions, peer); -} - -static void -priv_add_permission_for_peer (UdpTurnPriv *priv, const NiceAddress *peer) -{ - priv->permissions = - g_list_append (priv->permissions, nice_address_dup (peer)); -} - -static void -priv_add_sent_permission_for_peer (UdpTurnPriv *priv, const NiceAddress *peer) -{ - priv->sent_permissions = - g_list_append (priv->sent_permissions, nice_address_dup (peer)); -} - -static GList * -priv_remove_peer_from_list (GList *list, const NiceAddress *peer) -{ - GList *iter; - - for (iter = list ; iter ; iter = g_list_next (iter)) { - NiceAddress *address = (NiceAddress *) iter->data; - - if (nice_address_equal (address, peer)) { - GList *prev = iter->prev; - - nice_address_free (address); - list = g_list_delete_link (list, iter); - iter = prev; - if (iter) - iter = list; - } - } - - return list; -} - -static void -priv_remove_sent_permission_for_peer (UdpTurnPriv *priv, const NiceAddress *peer) -{ - priv->sent_permissions = - priv_remove_peer_from_list (priv->sent_permissions, peer); -} - -static void -priv_clear_permissions (UdpTurnPriv *priv) -{ - g_list_free_full (priv->permissions, (GDestroyNotify) nice_address_free); - priv->permissions = NULL; -} - -static gint -_socket_send_messages_wrapped (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages, gboolean reliable) -{ - if (!nice_socket_is_reliable (sock)) { - if (reliable) - return nice_socket_send_messages_reliable (sock, to, messages, n_messages); - else - return nice_socket_send_messages (sock, to, messages, n_messages); - } else { - GOutputVector *local_bufs; - NiceOutputMessage local_message; - const NiceOutputMessage *message; - gsize message_len; - guint n_bufs = 0; - guint16 rfc4571_frame; - guint i; - gint ret; - - g_assert_cmpuint (n_messages, ==, 1); - message = &messages[0]; - message_len = output_message_get_size (message); - g_assert_cmpint (message_len, <=, G_MAXUINT16); - - /* ICE-TCP requires that all packets be framed with RFC4571 */ - - /* Count the number of buffers. */ - if (message->n_buffers == -1) { - for (i = 0; message->buffers[i].buffer != NULL; i++) - n_bufs++; - } else { - n_bufs = message->n_buffers; - } - - local_bufs = g_alloca ((n_bufs + 1) * sizeof (GOutputVector)); - local_message.buffers = local_bufs; - local_message.n_buffers = n_bufs + 1; - - rfc4571_frame = htons (message_len); - local_bufs[0].buffer = &rfc4571_frame; - local_bufs[0].size = sizeof (guint16); - - for (i = 0; i < n_bufs; i++) { - local_bufs[i + 1].buffer = message->buffers[i].buffer; - local_bufs[i + 1].size = message->buffers[i].size; - } - - - if (reliable) - ret = nice_socket_send_messages_reliable (sock, to, - &local_message, 1); - else - ret = nice_socket_send_messages (sock, to, &local_message, 1); - - if (ret == 1) - ret = message_len; - - return ret; - } -} - -static gssize -_socket_send_wrapped (NiceSocket *sock, const NiceAddress *to, - guint len, const gchar *buf, gboolean reliable) -{ - gint ret; - - if (!nice_socket_is_reliable (sock)) { - GOutputVector local_buf = { buf, len }; - NiceOutputMessage local_message = { &local_buf, 1}; - - ret = _socket_send_messages_wrapped (sock, to, &local_message, 1, reliable); - if (ret == 1) - return len; - return ret; - } else { - guint16 rfc4571_frame = htons (len); - GOutputVector local_buf[2] = {{&rfc4571_frame, 2}, { buf, len }}; - NiceOutputMessage local_message = { local_buf, 2}; - - if (reliable) - ret = nice_socket_send_messages_reliable (sock, to, &local_message, 1); - else - ret = nice_socket_send_messages (sock, to, &local_message, 1); - - if (ret == 1) - return len; - return ret; - } -} - -static void -socket_enqueue_data(UdpTurnPriv *priv, const NiceAddress *to, - guint len, const gchar *buf, gboolean reliable) -{ - SendData *data = g_slice_new0 (SendData); - GQueue *queue = g_hash_table_lookup (priv->send_data_queues, to); - - if (queue == NULL) { - queue = g_queue_new (); - g_hash_table_insert (priv->send_data_queues, nice_address_dup (to), - queue); - } - - data->data = g_memdup(buf, len); - data->data_len = len; - data->reliable = reliable; - g_queue_push_tail (queue, data); -} - -static void -socket_dequeue_all_data (UdpTurnPriv *priv, const NiceAddress *to) -{ - GQueue *send_queue = g_hash_table_lookup (priv->send_data_queues, to); - - if (send_queue) { - while (!g_queue_is_empty (send_queue)) { - SendData *data = - (SendData *) g_queue_pop_head(send_queue); - - nice_debug_verbose ("dequeuing data"); - _socket_send_wrapped (priv->base_socket, &priv->server_addr, - data->data_len, data->data, data->reliable); - - g_free (data->data); - g_slice_free (SendData, data); - } - - /* remove queue from table */ - g_hash_table_remove (priv->send_data_queues, to); - } -} - - -static gssize -socket_send_message (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *message, gboolean reliable) -{ - UdpTurnPriv *priv = (UdpTurnPriv *) sock->priv; - StunMessage msg; - uint8_t buffer[STUN_MAX_MESSAGE_SIZE]; - size_t msg_len; - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sa; - GList *i; - ChannelBinding *binding = NULL; - gint ret; - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - for (i = priv->channels; i; i = i->next) { - ChannelBinding *b = i->data; - if (nice_address_equal (&b->peer, to)) { - binding = b; - break; - } - } - - nice_address_copy_to_sockaddr (to, &sa.addr); - - if (binding) { - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) { - gsize message_len = output_message_get_size (message); - - if (message_len + sizeof(uint32_t) <= sizeof(buffer)) { - guint j; - uint16_t len16, channel16; - gsize message_offset = 0; - - len16 = htons ((uint16_t) message_len); - channel16 = htons (binding->channel); - - memcpy (buffer, &channel16, sizeof(uint16_t)); - memcpy (buffer + sizeof(uint16_t), &len16, sizeof(uint16_t)); - - /* FIXME: Slow path! This should be replaced by code which manipulates - * the GOutputVector array, rather than the buffer contents - * themselves. */ - for (j = 0; - (message->n_buffers >= 0 && j < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[j].buffer != NULL); - j++) { - const GOutputVector *out_buf = &message->buffers[j]; - gsize out_len; - - out_len = MIN (message_len - message_offset, out_buf->size); - memcpy (buffer + sizeof (uint32_t) + message_offset, - out_buf->buffer, out_len); - message_offset += out_len; - } - - msg_len = message_len + sizeof(uint32_t); - } else { - goto error; - } - } else { - ret = _socket_send_messages_wrapped (priv->base_socket, - &priv->server_addr, message, 1, reliable); - - if (ret == 1) - return output_message_get_size (message); - return ret; - } - } else { - guint8 *compacted_buf; - gsize compacted_buf_len; - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) { - if (!stun_agent_init_indication (&priv->agent, &msg, - buffer, sizeof(buffer), STUN_IND_SEND)) - goto error; - if (stun_message_append_xor_addr (&msg, STUN_ATTRIBUTE_PEER_ADDRESS, - &sa.storage, sizeof(sa)) != - STUN_MESSAGE_RETURN_SUCCESS) - goto error; - } else { - if (!stun_agent_init_request (&priv->agent, &msg, - buffer, sizeof(buffer), STUN_SEND)) - goto error; - - if (stun_message_append32 (&msg, STUN_ATTRIBUTE_MAGIC_COOKIE, - TURN_MAGIC_COOKIE) != STUN_MESSAGE_RETURN_SUCCESS) - goto error; - if (priv->username != NULL && priv->username_len > 0) { - if (stun_message_append_bytes (&msg, STUN_ATTRIBUTE_USERNAME, - priv->username, priv->username_len) != - STUN_MESSAGE_RETURN_SUCCESS) - goto error; - } - if (stun_message_append_addr (&msg, STUN_ATTRIBUTE_DESTINATION_ADDRESS, - &sa.addr, sizeof(sa)) != - STUN_MESSAGE_RETURN_SUCCESS) - goto error; - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE && - priv->current_binding && - nice_address_equal (&priv->current_binding->peer, to)) { - if (stun_message_append32 (&msg, STUN_ATTRIBUTE_OPTIONS, 1) != - STUN_MESSAGE_RETURN_SUCCESS) - goto error; - } - } - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) { - if(stun_message_append32(&msg, STUN_ATTRIBUTE_MS_VERSION, 1) != - STUN_MESSAGE_RETURN_SUCCESS) - goto error; - - if (priv->ms_connection_id_valid) - if (stun_message_append_ms_connection_id(&msg, priv->ms_connection_id, - ++priv->ms_sequence_num) != - STUN_MESSAGE_RETURN_SUCCESS) - goto error; - - stun_message_ensure_ms_realm(&msg, priv->ms_realm); - } - - /* Slow path! We have to compact the buffers to append them to the message. - * FIXME: This could be improved by adding vectored I/O support to - * stun_message_append_bytes(). */ - compacted_buf = compact_output_message (message, &compacted_buf_len); - - if (stun_message_append_bytes (&msg, STUN_ATTRIBUTE_DATA, - compacted_buf, compacted_buf_len) != STUN_MESSAGE_RETURN_SUCCESS) { - g_free (compacted_buf); - goto error; - } - - g_free (compacted_buf); - - /* Finish the message. */ - msg_len = stun_agent_finish_message (&priv->agent, &msg, - priv->password, priv->password_len); - if (msg_len > 0 && stun_message_get_class (&msg) == STUN_REQUEST && - priv->compatibility != NICE_TURN_SOCKET_COMPATIBILITY_OC2007) { - SendRequest *req = g_slice_new0 (SendRequest); - - req->priv = priv; - stun_message_id (&msg, req->id); - req->source = priv_timeout_add_with_context (priv, - STUN_END_TIMEOUT, priv_forget_send_request_timeout, req); - g_queue_push_tail (priv->send_requests, req); - } - } - - if (msg_len > 0) { - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766 && - !priv_has_permission_for_peer (priv, to)) { - if (!priv_has_sent_permission_for_peer (priv, to)) { - priv_send_create_permission (priv, to); - } - - /* enque data */ - nice_debug_verbose ("enqueuing data"); - socket_enqueue_data(priv, to, msg_len, (gchar *)buffer, reliable); - - return msg_len; - } else { - GOutputVector local_buf = { buffer, msg_len }; - NiceOutputMessage local_message = {&local_buf, 1}; - - ret = _socket_send_messages_wrapped (priv->base_socket, - &priv->server_addr, &local_message, 1, reliable); - - if (ret == 1) - return msg_len; - return ret; - } - } - - /* Error condition pass through to the base socket. */ - ret = _socket_send_messages_wrapped (priv->base_socket, to, message, 1, - reliable); - if (ret == 1) - return output_message_get_size (message); - return ret; -error: - return -1; -} - -static gint -socket_send_messages (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - guint i; - - g_mutex_lock (&mutex); - - /* Make sure socket has not been freed: */ - g_assert (sock->priv != NULL); - - for (i = 0; i < n_messages; i++) { - const NiceOutputMessage *message = &messages[i]; - gssize len; - - len = socket_send_message (sock, to, message, FALSE); - - if (len < 0) { - /* Error. */ - if (i > 0) - break; - g_mutex_unlock (&mutex); - return len; - } else if (len == 0) { - /* EWOULDBLOCK. */ - break; - } - } - - g_mutex_unlock (&mutex); - - return i; -} - -static gint -socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to, - const NiceOutputMessage *messages, guint n_messages) -{ - UdpTurnPriv *priv = (UdpTurnPriv *) sock->priv; - guint i; - - g_mutex_lock (&mutex); - - /* TURN can depend either on tcp-turn or udp-bsd as a base socket - * if we allow reliable send and need to create permissions and we queue the - * data, then we must be sure that the reliable send will succeed later, so - * we check for udp-bsd here as the base socket and don't allow it. - */ - if (priv->base_socket->type == NICE_SOCKET_TYPE_UDP_BSD) { - g_mutex_unlock (&mutex); - return -1; - } - - for (i = 0; i < n_messages; i++) { - const NiceOutputMessage *message = &messages[i]; - gssize len; - - len = socket_send_message (sock, to, message, TRUE); - - if (len < 0) { - /* Error. */ - g_mutex_unlock (&mutex); - return len; - } else if (len == 0) { - /* EWOULDBLOCK. */ - break; - } - } - - g_mutex_unlock (&mutex); - return i; -} - -static gboolean -socket_is_reliable (NiceSocket *sock) -{ - UdpTurnPriv *priv = (UdpTurnPriv *) sock->priv; - - return nice_socket_is_reliable (priv->base_socket); -} - -static gboolean -socket_can_send (NiceSocket *sock, NiceAddress *addr) -{ - UdpTurnPriv *priv = sock->priv; - - return nice_socket_can_send (priv->base_socket, addr); -} - -static void -socket_set_writable_callback (NiceSocket *sock, - NiceSocketWritableCb callback, gpointer user_data) -{ - UdpTurnPriv *priv = sock->priv; - - nice_socket_set_writable_callback (priv->base_socket, callback, user_data); -} - -static gboolean -socket_is_based_on (NiceSocket *sock, NiceSocket *other) -{ - UdpTurnPriv *priv = sock->priv; - - return (sock == other) || - (priv && nice_socket_is_based_on (priv->base_socket, other)); -} - -static gboolean -priv_forget_send_request_timeout (gpointer pointer) -{ - SendRequest *req = pointer; - - g_mutex_lock (&mutex); - if (g_source_is_destroyed (g_main_current_source ())) { - nice_debug ("Source was destroyed. " - "Avoided race condition in turn.c:priv_forget_send_request"); - g_mutex_unlock (&mutex); - return G_SOURCE_REMOVE; - } - - send_request_free (req); - g_queue_remove (req->priv->send_requests, req); - - g_mutex_unlock (&mutex); - - return G_SOURCE_REMOVE; -} - -static gboolean -priv_permission_timeout (gpointer data) -{ - UdpTurnPriv *priv = (UdpTurnPriv *) data; - - nice_debug ("Permission is about to timeout, schedule renewal"); - - g_mutex_lock (&mutex); - - if (g_source_is_destroyed (g_main_current_source ())) { - nice_debug ("Source was destroyed. Avoided race condition in " - "udp-turn.c:priv_permission_timeout"); - - g_mutex_unlock (&mutex); - return G_SOURCE_REMOVE; - } - - - /* remove all permissions for this agent (the permission for the peer - we are sending to will be renewed) */ - priv_clear_permissions (priv); - g_mutex_unlock (&mutex); - - return TRUE; -} - -static gboolean -priv_binding_expired_timeout (gpointer data) -{ - UdpTurnPriv *priv = (UdpTurnPriv *) data; - GList *i; - GSource *source = NULL; - - g_mutex_lock (&mutex); - if (g_source_is_destroyed (g_main_current_source ())) { - nice_debug ("Source was destroyed. Avoided race condition in " - "udp-turn.c:priv_permission_timeout"); - - g_mutex_unlock (&mutex); - return G_SOURCE_REMOVE; - } - - nice_debug ("Permission expired, refresh failed"); - - /* find current binding and destroy it */ - for (i = priv->channels ; i; i = i->next) { - ChannelBinding *b = i->data; - if (b->timeout_source == source) { - priv->channels = g_list_remove (priv->channels, b); - /* Make sure we don't free a currently being-refreshed binding */ - if (priv->current_binding_msg && !priv->current_binding) { - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sa; - socklen_t sa_len = sizeof(sa); - NiceAddress to; - - /* look up binding associated with peer */ - stun_message_find_xor_addr ( - &priv->current_binding_msg->message, - STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &sa.storage, &sa_len); - nice_address_set_from_sockaddr (&to, &sa.addr); - - /* If the binding is being refreshed, then move it to - priv->current_binding so it counts as a 'new' binding and - will get readded to the list if it succeeds */ - if (nice_address_equal (&b->peer, &to)) { - priv->current_binding = b; - break; - } - } - /* In case the binding timed out before it could be processed, add it to - the pending list */ - priv_add_channel_binding (priv, &b->peer); - g_free (b); - break; - } - } - - g_mutex_unlock (&mutex); - return G_SOURCE_REMOVE; -} - -static gboolean -priv_binding_timeout (gpointer data) -{ - UdpTurnPriv *priv = (UdpTurnPriv *) data; - GList *i; - GSource *source = NULL; - - g_mutex_lock (&mutex); - if (g_source_is_destroyed (g_main_current_source ())) { - nice_debug ("Source was destroyed. Avoided race condition in " - "udp-turn.c:priv_permission_timeout"); - - g_mutex_unlock (&mutex); - return G_SOURCE_REMOVE; - } - - nice_debug ("Permission is about to timeout, sending binding renewal"); - source = g_main_current_source (); - - /* find current binding and mark it for renewal */ - for (i = priv->channels ; i; i = i->next) { - ChannelBinding *b = i->data; - - if (b->timeout_source == source) { - b->renew = TRUE; - - /* Remove any existing timer */ - if (b->timeout_source) { - g_source_destroy (b->timeout_source); - g_source_unref (b->timeout_source); - } - - /* Install timer to expire the permission */ - b->timeout_source = priv_timeout_add_seconds_with_context (priv, - STUN_EXPIRE_TIMEOUT, priv_binding_expired_timeout, priv); - - /* Send renewal */ - if (!priv->current_binding_msg) - priv_send_channel_bind (priv, b->channel, &b->peer); - break; - } - } - - g_mutex_unlock (&mutex); - - return G_SOURCE_REMOVE; -} - -static void -nice_udp_turn_socket_cache_realm_nonce_locked (NiceSocket *sock, - StunMessage *msg) -{ - UdpTurnPriv *priv = sock->priv; - gconstpointer tmp; - - g_assert_cmpint (sock->type, ==, NICE_SOCKET_TYPE_UDP_TURN); - - g_free (priv->cached_realm); - priv->cached_realm = NULL; - priv->cached_realm_len = 0; - - g_free (priv->cached_nonce); - priv->cached_nonce = NULL; - priv->cached_nonce_len = 0; - - tmp = stun_message_find (msg, STUN_ATTRIBUTE_REALM, &priv->cached_realm_len); - if (tmp && priv->cached_realm_len < 764) - priv->cached_realm = g_memdup (tmp, priv->cached_realm_len); - - tmp = stun_message_find (msg, STUN_ATTRIBUTE_NONCE, &priv->cached_nonce_len); - if (tmp && priv->cached_nonce_len < 764) - priv->cached_nonce = g_memdup (tmp, priv->cached_nonce_len); - -} - -void -nice_udp_turn_socket_cache_realm_nonce (NiceSocket *sock, - StunMessage *msg) -{ - g_mutex_lock (&mutex); - nice_udp_turn_socket_cache_realm_nonce_locked (sock, msg); - g_mutex_unlock (&mutex); -} - -guint -nice_udp_turn_socket_parse_recv_message (NiceSocket *sock, NiceSocket **from_sock, - NiceInputMessage *message) -{ - /* TODO: Speed this up in the common reliable case of having a 24-byte header - * buffer to begin with, followed by one or more massive buffers. */ - guint8 *buf; - gsize buf_len, len; - - if (message->n_buffers == 1 || - (message->n_buffers == -1 && - message->buffers[0].buffer != NULL && - message->buffers[1].buffer == NULL)) { - /* Fast path. Single massive buffer. */ - len = nice_udp_turn_socket_parse_recv (sock, from_sock, - message->from, message->length, message->buffers[0].buffer, - message->from, message->buffers[0].buffer, message->length); - - g_assert_cmpuint (len, <=, message->length); - - message->length = len; - - return (len > 0) ? 1 : 0; - } - - /* Slow path. */ - nice_debug_verbose ("%s: **WARNING: SLOW PATH**", G_STRFUNC); - - buf = compact_input_message (message, &buf_len); - len = nice_udp_turn_socket_parse_recv (sock, from_sock, - message->from, buf_len, buf, - message->from, buf, buf_len); - len = memcpy_buffer_to_input_message (message, buf, len); - g_free (buf); - - return (len > 0) ? 1 : 0; -} - -gsize -nice_udp_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, - NiceAddress *from, gsize len, guint8 *buf, - const NiceAddress *recv_from, const guint8 *_recv_buf, gsize recv_len) -{ - - UdpTurnPriv *priv = (UdpTurnPriv *) sock->priv; - StunValidationStatus valid; - StunMessage msg; - GList *l; - ChannelBinding *binding = NULL; - - union { - const guint8 *u8; - const guint16 *u16; - } recv_buf; - - g_mutex_lock (&mutex); - - /* In the case of a reliable UDP-TURN-OVER-TCP (which means MS-TURN) - * we must use RFC4571 framing */ - if (nice_socket_is_reliable (sock)) { - recv_buf.u8 = _recv_buf + sizeof(guint16); - recv_len -= sizeof(guint16); - } else { - recv_buf.u8 = _recv_buf; - } - - if (nice_address_equal (&priv->server_addr, recv_from)) { - valid = stun_agent_validate (&priv->agent, &msg, - recv_buf.u8, recv_len, NULL, NULL); - - if (valid == STUN_VALIDATION_SUCCESS) { - if (priv->compatibility != NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 && - priv->compatibility != NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) { - uint32_t cookie; - if (stun_message_find32 (&msg, STUN_ATTRIBUTE_MAGIC_COOKIE, - &cookie) != STUN_MESSAGE_RETURN_SUCCESS) - goto recv; - if (cookie != TURN_MAGIC_COOKIE) - goto recv; - } - - if (stun_message_get_method (&msg) == STUN_SEND) { - if (stun_message_get_class (&msg) == STUN_RESPONSE) { - SendRequest *req = NULL; - GList *i = g_queue_peek_head_link (priv->send_requests); - StunTransactionId msg_id; - - stun_message_id (&msg, msg_id); - - for (; i; i = i->next) { - SendRequest *r = i->data; - if (memcmp (&r->id, msg_id, sizeof(StunTransactionId)) == 0) { - req = r; - break; - } - } - - if (req) { - g_queue_remove (priv->send_requests, req); - send_request_free (req); - } - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) { - uint32_t opts = 0; - if (stun_message_find32 (&msg, STUN_ATTRIBUTE_OPTIONS, &opts) == - STUN_MESSAGE_RETURN_SUCCESS && opts & 0x1) - goto msn_google_lock; - } - } - - goto done; - } else if (stun_message_get_method (&msg) == STUN_OLD_SET_ACTIVE_DST) { - StunTransactionId request_id; - StunTransactionId response_id; - - if (priv->current_binding && priv->current_binding_msg) { - stun_message_id (&msg, response_id); - stun_message_id (&priv->current_binding_msg->message, request_id); - if (memcmp (request_id, response_id, - sizeof(StunTransactionId)) == 0) { - g_free (priv->current_binding_msg); - priv->current_binding_msg = NULL; - - if (stun_message_get_class (&msg) == STUN_RESPONSE && - (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_MSN)) { - goto msn_google_lock; - } else { - g_free (priv->current_binding); - priv->current_binding = NULL; - } - } - } - - goto done; - } else if (stun_message_get_method (&msg) == STUN_CHANNELBIND) { - StunTransactionId request_id; - StunTransactionId response_id; - - if (priv->current_binding_msg) { - stun_message_id (&msg, response_id); - stun_message_id (&priv->current_binding_msg->message, request_id); - if (memcmp (request_id, response_id, - sizeof(StunTransactionId)) == 0) { - - if (priv->current_binding) { - /* New channel binding */ - binding = priv->current_binding; - } else { - /* Existing binding refresh */ - GList *i; - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sa; - socklen_t sa_len = sizeof(sa); - NiceAddress to; - - /* look up binding associated with peer */ - stun_message_find_xor_addr ( - &priv->current_binding_msg->message, - STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &sa.storage, &sa_len); - nice_address_set_from_sockaddr (&to, &sa.addr); - - for (i = priv->channels; i; i = i->next) { - ChannelBinding *b = i->data; - if (nice_address_equal (&b->peer, &to)) { - binding = b; - break; - } - } - } - - if (stun_message_get_class (&msg) == STUN_ERROR) { - int code = -1; - uint8_t *sent_realm = NULL; - uint8_t *recv_realm = NULL; - uint16_t sent_realm_len = 0; - uint16_t recv_realm_len = 0; - - sent_realm = - (uint8_t *) stun_message_find ( - &priv->current_binding_msg->message, - STUN_ATTRIBUTE_REALM, &sent_realm_len); - recv_realm = - (uint8_t *) stun_message_find (&msg, - STUN_ATTRIBUTE_REALM, &recv_realm_len); - - /* check for unauthorized error response */ - if (stun_message_find_error (&msg, &code) == - STUN_MESSAGE_RETURN_SUCCESS && - (code == STUN_ERROR_STALE_NONCE || - (code == STUN_ERROR_UNAUTHORIZED && - !(recv_realm != NULL && - recv_realm_len > 0 && - recv_realm_len == sent_realm_len && - sent_realm != NULL && - memcmp (sent_realm, recv_realm, - sent_realm_len) == 0)))) { - - g_free (priv->current_binding_msg); - priv->current_binding_msg = NULL; - nice_udp_turn_socket_cache_realm_nonce_locked (sock, &msg); - if (binding) - priv_send_channel_bind (priv, binding->channel, - &binding->peer); - } else { - g_free (priv->current_binding); - priv->current_binding = NULL; - g_free (priv->current_binding_msg); - priv->current_binding_msg = NULL; - priv_process_pending_bindings (priv); - } - } else if (stun_message_get_class (&msg) == STUN_RESPONSE) { - g_free (priv->current_binding_msg); - priv->current_binding_msg = NULL; - - /* If it's a new channel binding, then add it to the list */ - if (priv->current_binding) - priv->channels = g_list_append (priv->channels, - priv->current_binding); - priv->current_binding = NULL; - - if (binding) { - binding->renew = FALSE; - - /* Remove any existing timer */ - if (binding->timeout_source) { - g_source_destroy (binding->timeout_source); - g_source_unref (binding->timeout_source); - } - /* Install timer to schedule refresh of the permission */ - binding->timeout_source = - priv_timeout_add_seconds_with_context (priv, - STUN_BINDING_TIMEOUT, priv_binding_timeout, priv); - } - priv_process_pending_bindings (priv); - } - } - } - goto done; - } else if (stun_message_get_method (&msg) == STUN_CREATEPERMISSION) { - StunTransactionId request_id; - StunTransactionId response_id; - GList *i, *next; - TURNMessage *current_create_permission_msg; - - for (i = priv->pending_permissions; i; i = next) { - current_create_permission_msg = (TURNMessage *) i->data; - next = i->next; - - stun_message_id (&msg, response_id); - stun_message_id (¤t_create_permission_msg->message, request_id); - - if (memcmp (request_id, response_id, - sizeof(StunTransactionId)) == 0) { - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } peer; - socklen_t peer_len = sizeof(peer); - NiceAddress to; - gchar tmpbuf[INET6_ADDRSTRLEN]; - - stun_message_find_xor_addr ( - ¤t_create_permission_msg->message, - STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &peer.storage, &peer_len); - nice_address_set_from_sockaddr (&to, &peer.addr); - nice_address_to_string (&to, tmpbuf); - nice_debug ("TURN: got response for CreatePermission " - "with XOR_PEER_ADDRESS=[%s]:%u : %s", - tmpbuf, nice_address_get_port (&to), - stun_message_get_class (&msg) == STUN_ERROR ? "unauthorized" : "ok"); - - /* unathorized => resend with realm and nonce */ - if (stun_message_get_class (&msg) == STUN_ERROR) { - int code = -1; - uint8_t *sent_realm = NULL; - uint8_t *recv_realm = NULL; - uint16_t sent_realm_len = 0; - uint16_t recv_realm_len = 0; - - sent_realm = - (uint8_t *) stun_message_find ( - ¤t_create_permission_msg->message, - STUN_ATTRIBUTE_REALM, &sent_realm_len); - recv_realm = - (uint8_t *) stun_message_find (&msg, - STUN_ATTRIBUTE_REALM, &recv_realm_len); - - /* check for unauthorized error response */ - if (stun_message_find_error (&msg, &code) == - STUN_MESSAGE_RETURN_SUCCESS && - (code == STUN_ERROR_STALE_NONCE || - (code == STUN_ERROR_UNAUTHORIZED && - !(recv_realm != NULL && - recv_realm_len > 0 && - recv_realm_len == sent_realm_len && - sent_realm != NULL && - memcmp (sent_realm, recv_realm, - sent_realm_len) == 0)))) { - - priv->pending_permissions = g_list_delete_link ( - priv->pending_permissions, i); - g_free (current_create_permission_msg); - current_create_permission_msg = NULL; - - nice_udp_turn_socket_cache_realm_nonce_locked (sock, &msg); - /* resend CreatePermission */ - priv_send_create_permission (priv, &to); - goto done; - } - } - /* If we get an error, we just assume the server somehow - doesn't support permissions and we ignore the error and - fake a successful completion. If the server needs a permission - but it failed to create it, then the connchecks will fail. */ - priv_remove_sent_permission_for_peer (priv, &to); - priv_add_permission_for_peer (priv, &to); - - /* install timer to schedule refresh of the permission */ - /* (will not schedule refresh if we got an error) */ - if (stun_message_get_class (&msg) == STUN_RESPONSE && - !priv->permission_timeout_source) { - priv->permission_timeout_source = - priv_timeout_add_seconds_with_context (priv, - STUN_PERMISSION_TIMEOUT, priv_permission_timeout, - priv); - } - - /* send enqued data */ - socket_dequeue_all_data (priv, &to); - - priv->pending_permissions = g_list_delete_link ( - priv->pending_permissions, i); - g_free (current_create_permission_msg); - current_create_permission_msg = NULL; - - break; - } - } - - goto done; - } else if (stun_message_get_class (&msg) == STUN_INDICATION && - stun_message_get_method (&msg) == STUN_IND_DATA) { - uint16_t data_len; - uint8_t *data; - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sa; - socklen_t from_len = sizeof (sa); - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) { - if (stun_message_find_xor_addr (&msg, STUN_ATTRIBUTE_REMOTE_ADDRESS, - &sa.storage, &from_len) != - STUN_MESSAGE_RETURN_SUCCESS) - goto recv; - } else { - if (stun_message_find_addr (&msg, STUN_ATTRIBUTE_REMOTE_ADDRESS, - &sa.storage, &from_len) != - STUN_MESSAGE_RETURN_SUCCESS) - goto recv; - } - - data = (uint8_t *) stun_message_find (&msg, STUN_ATTRIBUTE_DATA, - &data_len); - - if (data == NULL) - goto recv; - - nice_address_set_from_sockaddr (from, &sa.addr); - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766 && - !priv_has_permission_for_peer (priv, from)) { - if (!priv_has_sent_permission_for_peer (priv, from)) { - priv_send_create_permission (priv, from); - } - } - - *from_sock = sock; - memmove (buf, data, len > data_len ? data_len : len); - g_mutex_unlock (&mutex); - return len > data_len ? data_len : len; - } else { - goto recv; - } - } - } - - recv: - for (l = priv->channels; l; l = l->next) { - ChannelBinding *b = l->data; - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) { - if (b->channel == ntohs(recv_buf.u16[0])) { - recv_len = ntohs (recv_buf.u16[1]); - recv_buf.u8 += sizeof(uint32_t); - binding = b; - break; - } - } else { - binding = b; - break; - } - } - - if (binding) { - *from = binding->peer; - *from_sock = sock; - } else { - *from = *recv_from; - } - - memmove (buf, recv_buf.u8, len > recv_len ? recv_len : len); - g_mutex_unlock (&mutex); - return len > recv_len ? recv_len : len; - - msn_google_lock: - - if (priv->current_binding) { - GList *i = priv->channels; - for (; i; i = i->next) { - ChannelBinding *b = i->data; - g_free (b); - } - g_list_free (priv->channels); - priv->channels = g_list_append (NULL, priv->current_binding); - priv->current_binding = NULL; - priv_process_pending_bindings (priv); - } - - done: - g_mutex_unlock (&mutex); - return 0; -} - -gboolean -nice_udp_turn_socket_set_peer (NiceSocket *sock, NiceAddress *peer) -{ - UdpTurnPriv *priv; - gboolean ret; - - g_mutex_lock (&mutex); - - priv = (UdpTurnPriv *) sock->priv; - - ret = priv_add_channel_binding (priv, peer); - - g_mutex_unlock (&mutex); - - return ret; -} - -static void -priv_process_pending_bindings (UdpTurnPriv *priv) -{ - gboolean ret = FALSE; - - while (priv->pending_bindings != NULL && ret == FALSE) { - NiceAddress *peer = priv->pending_bindings->data; - ret = priv_add_channel_binding (priv, peer); - priv->pending_bindings = g_list_remove (priv->pending_bindings, peer); - nice_address_free (peer); - } - - /* If no new channel bindings are in progress and there are no - pending bindings, then renew the soon to be expired bindings */ - if (priv->pending_bindings == NULL && priv->current_binding_msg == NULL) { - GList *i = NULL; - - /* find binding to renew */ - for (i = priv->channels ; i; i = i->next) { - ChannelBinding *b = i->data; - if (b->renew) { - priv_send_channel_bind (priv, b->channel, &b->peer); - break; - } - } - } -} - - -static gboolean -priv_retransmissions_tick_unlocked (UdpTurnPriv *priv) -{ - gboolean ret = FALSE; - - if (priv->current_binding_msg) { - switch (stun_timer_refresh (&priv->current_binding_msg->timer)) { - case STUN_USAGE_TIMER_RETURN_TIMEOUT: - { - /* Time out */ - StunTransactionId id; - - stun_message_id (&priv->current_binding_msg->message, id); - stun_agent_forget_transaction (&priv->agent, id); - - g_free (priv->current_binding); - priv->current_binding = NULL; - g_free (priv->current_binding_msg); - priv->current_binding_msg = NULL; - - - priv_process_pending_bindings (priv); - break; - } - case STUN_USAGE_TIMER_RETURN_RETRANSMIT: - /* Retransmit */ - _socket_send_wrapped (priv->base_socket, &priv->server_addr, - stun_message_length (&priv->current_binding_msg->message), - (gchar *)priv->current_binding_msg->buffer, FALSE); - ret = TRUE; - break; - case STUN_USAGE_TIMER_RETURN_SUCCESS: - ret = TRUE; - break; - default: - /* Nothing to do. */ - break; - } - } - - if (ret) - priv_schedule_tick (priv); - return ret; -} - -static gboolean -priv_retransmissions_create_permission_tick_unlocked (UdpTurnPriv *priv, GList *list_element) -{ - gboolean ret = FALSE; - TURNMessage *current_create_permission_msg; - - current_create_permission_msg = (TURNMessage *)list_element->data; - - if (current_create_permission_msg) { - switch (stun_timer_refresh (¤t_create_permission_msg->timer)) { - case STUN_USAGE_TIMER_RETURN_TIMEOUT: - { - /* Time out */ - StunTransactionId id; - NiceAddress to; - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } addr; - socklen_t addr_len = sizeof(addr); - - stun_message_id (¤t_create_permission_msg->message, id); - stun_agent_forget_transaction (&priv->agent, id); - stun_message_find_xor_addr ( - ¤t_create_permission_msg->message, - STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &addr.storage, &addr_len); - nice_address_set_from_sockaddr (&to, &addr.addr); - - priv_remove_sent_permission_for_peer (priv, &to); - priv->pending_permissions = g_list_delete_link ( - priv->pending_permissions, list_element); - g_free (current_create_permission_msg); - current_create_permission_msg = NULL; - - /* we got a timeout when retransmitting a CreatePermission - message, assume we can just send the data, the server - might not support RFC TURN, or connectivity check will - fail eventually anyway */ - priv_add_permission_for_peer (priv, &to); - - socket_dequeue_all_data (priv, &to); - - break; - } - case STUN_USAGE_TIMER_RETURN_RETRANSMIT: - /* Retransmit */ - _socket_send_wrapped (priv->base_socket, &priv->server_addr, - stun_message_length (¤t_create_permission_msg->message), - (gchar *)current_create_permission_msg->buffer, FALSE); - ret = TRUE; - break; - case STUN_USAGE_TIMER_RETURN_SUCCESS: - ret = TRUE; - break; - default: - /* Nothing to do. */ - break; - } - } - - return ret; -} - -static gboolean -priv_retransmissions_tick (gpointer pointer) -{ - UdpTurnPriv *priv = pointer; - - g_mutex_lock (&mutex); - if (g_source_is_destroyed (g_main_current_source ())) { - nice_debug ("Source was destroyed. Avoided race condition in " - "udp-turn.c:priv_permission_timeout"); - - g_mutex_unlock (&mutex); - return G_SOURCE_REMOVE; - } - - if (priv_retransmissions_tick_unlocked (priv) == FALSE) { - if (priv->tick_source_channel_bind != NULL) { - g_source_destroy (priv->tick_source_channel_bind); - g_source_unref (priv->tick_source_channel_bind); - priv->tick_source_channel_bind = NULL; - } - } - - g_mutex_unlock (&mutex); - - return G_SOURCE_REMOVE; -} - -static gboolean -priv_retransmissions_create_permission_tick (gpointer pointer) -{ - UdpTurnPriv *priv = pointer; - - g_mutex_lock (&mutex); - if (g_source_is_destroyed (g_main_current_source ())) { - nice_debug ("Source was destroyed. Avoided race condition in " - "udp-turn.c:priv_permission_timeout"); - - g_mutex_unlock (&mutex); - return G_SOURCE_REMOVE; - } - - /* This will call priv_retransmissions_create_permission_tick_unlocked() for - * every pending permission with an expired timer and will create a new timer - * if there are pending permissions that require it */ - priv_schedule_tick (priv); - - g_mutex_unlock (&mutex); - - return G_SOURCE_REMOVE; -} - -static void -priv_schedule_tick (UdpTurnPriv *priv) -{ - GList *i, *next, *prev; - TURNMessage *current_create_permission_msg; - guint min_timeout = G_MAXUINT; - - if (priv->tick_source_channel_bind != NULL) { - g_source_destroy (priv->tick_source_channel_bind); - g_source_unref (priv->tick_source_channel_bind); - priv->tick_source_channel_bind = NULL; - } - - if (priv->current_binding_msg) { - guint timeout = stun_timer_remainder (&priv->current_binding_msg->timer); - if (timeout > 0) { - priv->tick_source_channel_bind = - priv_timeout_add_with_context (priv, timeout, - priv_retransmissions_tick, priv); - } else { - priv_retransmissions_tick_unlocked (priv); - } - } - - if (priv->tick_source_create_permission != NULL) { - g_source_destroy (priv->tick_source_create_permission); - g_source_unref (priv->tick_source_create_permission); - priv->tick_source_create_permission = NULL; - } - - for (i = priv->pending_permissions, prev = NULL; i; i = next) { - guint timeout; - - current_create_permission_msg = (TURNMessage *)i->data; - next = i->next; - - timeout = stun_timer_remainder (¤t_create_permission_msg->timer); - - if (timeout > 0) { - min_timeout = MIN (min_timeout, timeout); - prev = i; - } else { - /* This could either delete the permission from the list, or it could - * refresh it, changing its timeout value */ - priv_retransmissions_create_permission_tick_unlocked (priv, i); - if (prev == NULL) - next = priv->pending_permissions; - else - next = prev->next; - } - } - - /* We create one timer for the minimal timeout we need */ - if (min_timeout != G_MAXUINT) { - priv->tick_source_create_permission = - priv_timeout_add_with_context (priv, min_timeout, - priv_retransmissions_create_permission_tick, - priv); - } -} - -static void -priv_send_turn_message (UdpTurnPriv *priv, TURNMessage *msg) -{ - size_t stun_len = stun_message_length (&msg->message); - - if (priv->current_binding_msg) { - g_free (priv->current_binding_msg); - priv->current_binding_msg = NULL; - } - - if (nice_socket_is_reliable (priv->base_socket)) { - _socket_send_wrapped (priv->base_socket, &priv->server_addr, - stun_len, (gchar *)msg->buffer, TRUE); - stun_timer_start_reliable (&msg->timer, - STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT); - } else { - if (_socket_send_wrapped (priv->base_socket, &priv->server_addr, - stun_len, (gchar *)msg->buffer, TRUE) < 0) - _socket_send_wrapped (priv->base_socket, &priv->server_addr, - stun_len, (gchar *)msg->buffer, FALSE); - stun_timer_start (&msg->timer, STUN_TIMER_DEFAULT_TIMEOUT, - STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS); - } - - priv->current_binding_msg = msg; - priv_schedule_tick (priv); -} - -static gboolean -priv_send_create_permission(UdpTurnPriv *priv, - const NiceAddress *peer) -{ - guint msg_buf_len; - gboolean res = FALSE; - TURNMessage *msg = g_new0 (TURNMessage, 1); - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } addr; - - /* register this peer as being pening a permission (if not already pending) */ - if (!priv_has_sent_permission_for_peer (priv, peer)) { - priv_add_sent_permission_for_peer (priv, peer); - } - - nice_address_copy_to_sockaddr (peer, &addr.addr); - - /* send CreatePermission */ - msg_buf_len = stun_usage_turn_create_permission(&priv->agent, &msg->message, - msg->buffer, - sizeof(msg->buffer), - priv->username, - priv->username_len, - priv->password, - priv->password_len, - priv->cached_realm, priv->cached_realm_len, - priv->cached_nonce, priv->cached_nonce_len, - &addr.storage, - STUN_USAGE_TURN_COMPATIBILITY_RFC5766); - - if (msg_buf_len > 0) { - if (nice_socket_is_reliable (priv->base_socket)) { - res = _socket_send_wrapped (priv->base_socket, &priv->server_addr, - msg_buf_len, (gchar *) msg->buffer, TRUE); - } else { - res = _socket_send_wrapped (priv->base_socket, &priv->server_addr, - msg_buf_len, (gchar *) msg->buffer, TRUE); - if (res < 0) - res = _socket_send_wrapped (priv->base_socket, &priv->server_addr, - msg_buf_len, (gchar *) msg->buffer, FALSE); - } - - if (nice_socket_is_reliable (priv->base_socket)) { - stun_timer_start_reliable (&msg->timer, - STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT); - } else { - stun_timer_start (&msg->timer, STUN_TIMER_DEFAULT_TIMEOUT, - STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS); - } - - priv->pending_permissions = g_list_append (priv->pending_permissions, msg); - priv_schedule_tick (priv); - } else { - g_free(msg); - } - - return res; -} - -static gboolean -priv_send_channel_bind (UdpTurnPriv *priv, uint16_t channel, - const NiceAddress *peer) -{ - uint32_t channel_attr = channel << 16; - size_t stun_len; - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sa; - TURNMessage *msg = g_new0 (TURNMessage, 1); - - nice_address_copy_to_sockaddr (peer, &sa.addr); - - if (!stun_agent_init_request (&priv->agent, &msg->message, - msg->buffer, sizeof(msg->buffer), - STUN_CHANNELBIND)) { - g_free (msg); - return FALSE; - } - - if (stun_message_append32 (&msg->message, STUN_ATTRIBUTE_CHANNEL_NUMBER, - channel_attr) != STUN_MESSAGE_RETURN_SUCCESS) { - g_free (msg); - return FALSE; - } - - if (stun_message_append_xor_addr (&msg->message, STUN_ATTRIBUTE_PEER_ADDRESS, - &sa.storage, - sizeof(sa)) - != STUN_MESSAGE_RETURN_SUCCESS) { - g_free (msg); - return FALSE; - } - - if (priv->username != NULL && priv->username_len > 0 && - priv->cached_realm != NULL && priv->cached_realm_len > 0 && - priv->cached_nonce != NULL && priv->cached_nonce_len > 0) { - - if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_USERNAME, - priv->username, priv->username_len) - != STUN_MESSAGE_RETURN_SUCCESS) { - g_free (msg); - return FALSE; - } - - if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_REALM, - priv->cached_realm, priv->cached_realm_len) - != STUN_MESSAGE_RETURN_SUCCESS) { - g_free (msg); - return 0; - } - - if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_NONCE, - priv->cached_nonce, priv->cached_nonce_len) - != STUN_MESSAGE_RETURN_SUCCESS) { - g_free (msg); - return 0; - } - } - - stun_len = stun_agent_finish_message (&priv->agent, &msg->message, - priv->password, priv->password_len); - - if (stun_len > 0) { - priv_send_turn_message (priv, msg); - return TRUE; - } - - g_free (msg); - return FALSE; -} - -static gboolean -priv_add_channel_binding (UdpTurnPriv *priv, const NiceAddress *peer) -{ - size_t stun_len; - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } sa; - - nice_address_copy_to_sockaddr (peer, &sa.addr); - - if (priv->current_binding) { - NiceAddress * pending= nice_address_new (); - *pending = *peer; - priv->pending_bindings = g_list_append (priv->pending_bindings, pending); - return FALSE; - } - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) { - uint16_t channel = 0x4000; - GList *i = priv->channels; - for (; i; i = i->next) { - ChannelBinding *b = i->data; - if (channel == b->channel) { - i = priv->channels; - channel++; - continue; - } - } - - if (channel >= 0x4000 && channel < 0xffff) { - gboolean ret = priv_send_channel_bind (priv, channel, peer); - if (ret) { - priv->current_binding = g_new0 (ChannelBinding, 1); - priv->current_binding->channel = channel; - priv->current_binding->peer = *peer; - } - return ret; - } - return FALSE; - } else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_MSN || - priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) { - TURNMessage *msg = g_new0 (TURNMessage, 1); - if (!stun_agent_init_request (&priv->agent, &msg->message, - msg->buffer, sizeof(msg->buffer), - STUN_OLD_SET_ACTIVE_DST)) { - g_free (msg); - return FALSE; - } - - if (stun_message_append32 (&msg->message, STUN_ATTRIBUTE_MAGIC_COOKIE, - TURN_MAGIC_COOKIE) - != STUN_MESSAGE_RETURN_SUCCESS) { - g_free (msg); - return FALSE; - } - - if (priv->username != NULL && priv->username_len > 0) { - if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_USERNAME, - priv->username, priv->username_len) - != STUN_MESSAGE_RETURN_SUCCESS) { - g_free (msg); - return FALSE; - } - } - - if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_OC2007) { - if (priv->ms_connection_id_valid) - stun_message_append_ms_connection_id(&msg->message, - priv->ms_connection_id, ++priv->ms_sequence_num); - - stun_message_ensure_ms_realm(&msg->message, priv->ms_realm); - } - - if (stun_message_append_addr (&msg->message, - STUN_ATTRIBUTE_DESTINATION_ADDRESS, - &sa.addr, sizeof(sa)) - != STUN_MESSAGE_RETURN_SUCCESS) { - g_free (msg); - return FALSE; - } - - stun_len = stun_agent_finish_message (&priv->agent, &msg->message, - priv->password, priv->password_len); - - if (stun_len > 0) { - priv->current_binding = g_new0 (ChannelBinding, 1); - priv->current_binding->channel = 0; - priv->current_binding->peer = *peer; - priv_send_turn_message (priv, msg); - return TRUE; - } - g_free (msg); - return FALSE; - } else if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE) { - priv->current_binding = g_new0 (ChannelBinding, 1); - priv->current_binding->channel = 0; - priv->current_binding->peer = *peer; - return TRUE; - } else { - return FALSE; - } - - return FALSE; -} - -void -nice_udp_turn_socket_set_ms_realm(NiceSocket *sock, StunMessage *msg) -{ - UdpTurnPriv *priv = (UdpTurnPriv *)sock->priv; - uint16_t alen; - const uint8_t *realm = stun_message_find(msg, STUN_ATTRIBUTE_REALM, &alen); - - if (realm && alen <= STUN_MAX_MS_REALM_LEN) { - g_mutex_lock (&mutex); - memcpy(priv->ms_realm, realm, alen); - priv->ms_realm[alen] = '\0'; - g_mutex_unlock (&mutex); - } -} - -void -nice_udp_turn_socket_set_ms_connection_id (NiceSocket *sock, StunMessage *msg) -{ - UdpTurnPriv *priv = (UdpTurnPriv *)sock->priv; - uint16_t alen; - const uint8_t *ms_seq_num = stun_message_find(msg, - STUN_ATTRIBUTE_MS_SEQUENCE_NUMBER, &alen); - - - if (ms_seq_num && alen == 24) { - g_mutex_lock (&mutex); - memcpy (priv->ms_connection_id, ms_seq_num, 20); - priv->ms_sequence_num = ntohl((uint32_t)*(ms_seq_num + 20)); - priv->ms_connection_id_valid = TRUE; - g_mutex_unlock (&mutex); - } -} diff --git a/socket/udp-turn.h b/socket/udp-turn.h deleted file mode 100644 index df10a1c..0000000 --- a/socket/udp-turn.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _UDP_TURN_H -#define _UDP_TURN_H - - -typedef enum { - NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9, - NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE, - NICE_TURN_SOCKET_COMPATIBILITY_MSN, - NICE_TURN_SOCKET_COMPATIBILITY_OC2007, - NICE_TURN_SOCKET_COMPATIBILITY_RFC5766, -} NiceTurnSocketCompatibility; - -#include "socket.h" -#include "stun/stunmessage.h" - - -G_BEGIN_DECLS - -guint -nice_udp_turn_socket_parse_recv_message (NiceSocket *sock, NiceSocket **from_sock, - NiceInputMessage *message); - -gsize -nice_udp_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, - NiceAddress *from, gsize len, guint8 *buf, - const NiceAddress *recv_from, const guint8 *recv_buf, gsize recv_len); - -gboolean -nice_udp_turn_socket_set_peer (NiceSocket *sock, NiceAddress *peer); - -NiceSocket * -nice_udp_turn_socket_new (GMainContext *ctx, NiceAddress *addr, - NiceSocket *base_socket, const NiceAddress *server_addr, - const gchar *username, const gchar *password, - NiceTurnSocketCompatibility compatibility); - -void -nice_udp_turn_socket_set_ms_realm(NiceSocket *sock, StunMessage *msg); - -void -nice_udp_turn_socket_set_ms_connection_id (NiceSocket *sock, StunMessage *msg); - -void -nice_udp_turn_socket_cache_realm_nonce (NiceSocket *sock, StunMessage *msg); - - -G_END_DECLS - -#endif /* _UDP_TURN_H */ - diff --git a/stun/Makefile.am b/stun/Makefile.am deleted file mode 100644 index 3fcc58f..0000000 --- a/stun/Makefile.am +++ /dev/null @@ -1,50 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2006, 2007 Collabora Ltd. -# (C) 2006, 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. - -SUBDIRS = . tools tests - -include $(top_srcdir)/common.mk - -AM_CFLAGS = \ - -std=gnu99 \ - -DG_LOG_DOMAIN=\"libnice-stun\" \ - $(LIBNICE_CFLAGS) \ - $(GNUTLS_CFLAGS) \ - $(OPENSSL_INCLUDES) \ - $(NULL) -AM_CPPFLAGS = -I$(top_srcdir) - -if WINDOWS - AM_CFLAGS += -DWINVER=0x0501 # _WIN32_WINNT_WINXP -endif - -noinst_LTLIBRARIES = libstun.la - -libstun_la_SOURCES = constants.h \ - stunagent.c stunagent.h \ - stunmessage.c stunmessage.h \ - stun5389.c stun5389.h \ - stuncrc32.c stuncrc32.h \ - rand.c rand.h \ - stunhmac.c stunhmac.h \ - utils.c utils.h \ - debug.c debug.h \ - usages/ice.c usages/ice.h \ - usages/bind.c usages/bind.h \ - usages/turn.c usages/turn.h \ - usages/timer.c usages/timer.h - -libstun_la_LIBADD = $(LIBRT) $(GNUTLS_LIBS) $(OPENSSL_LIBS) $(OPENSSL_LDFLAGS) - -EXTRA_DIST = win32_common.h meson.build - -libstun_la_includedir=$(includedir)/stun -libstun_la_include_HEADERS = stunagent.h stunmessage.h win32_common.h debug.h constants.h - -libstun_usage_includedir=$(includedir)/stun/usages -libstun_usage_include_HEADERS = usages/bind.h usages/ice.h usages/turn.h usages/timer.h diff --git a/stun/constants.h b/stun/constants.h deleted file mode 100644 index 29e1cec..0000000 --- a/stun/constants.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _STUN_CONSTANTS_H -#define _STUN_CONSTANTS_H - - -/** - * SECTION:stunconstants - * @short_description: STUN constants - * @include: stun/constants.h - * @stability: Stable - * - * Various constants defining parts of the STUN and TURN protocols and - * on-the-wire packet formats. - */ - -/** - * STUN_ATTRIBUTE_LENGTH_LEN: - * - * Length of the length field of a STUN attribute (in bytes). - */ -/** - * STUN_ATTRIBUTE_LENGTH_POS: - * - * Offset of the length field of a STUN attribute (in bytes). - */ -/** - * STUN_ATTRIBUTE_TYPE_LEN: - * - * Length of the type field of a STUN attribute (in bytes). - */ -/** - * STUN_ATTRIBUTE_TYPE_POS: - * - * Offset of the type field of a STUN attribute (in bytes). - */ -/** - * STUN_ATTRIBUTE_VALUE_POS: - * - * Offset of the value field of a STUN attribute (in bytes). - */ -/** - * STUN_ID_LEN: - * - * Length of the ID field of a STUN message (in bytes). - */ -/** - * STUN_MAGIC_COOKIE: - * - * Magic cookie value used to identify STUN messages. - */ -/** - * TURN_MAGIC_COOKIE: - * - * Magic cookie value used to identify TURN messages. - */ -/** - * STUN_MAX_MESSAGE_SIZE_IPV4: - * - * Maximum size of a STUN message sent over IPv4 (in bytes). - */ -/** - * STUN_MAX_MESSAGE_SIZE_IPV6: - * - * Maximum size of a STUN message sent over IPv6 (in bytes). - */ -/** - * STUN_MESSAGE_ATTRIBUTES_POS: - * - * Offset of the attributes of a STUN message (in bytes). - */ -/** - * STUN_MESSAGE_HEADER_LENGTH: - * - * Total length of a STUN message header (in bytes). - */ -/** - * STUN_MESSAGE_LENGTH_LEN: - * - * Length of the length field of a STUN message (in bytes). - */ -/** - * STUN_MESSAGE_LENGTH_POS: - * - * Offset of the length field of a STUN message (in bytes). - */ -/** - * STUN_MESSAGE_TRANS_ID_LEN: - * - * Length of the transaction ID field of a STUN message (in bytes). - */ -/** - * STUN_MESSAGE_TRANS_ID_POS: - * - * Offset of the transaction ID field of a STUN message (in bytes). - */ -/** - * STUN_MESSAGE_TYPE_LEN: - * - * Length of the type field of a STUN message (in bytes). - */ -/** - * STUN_MESSAGE_TYPE_POS: - * - * Offset of the type field of a STUN message (in bytes). - */ - -#define STUN_MESSAGE_TYPE_POS 0 -#define STUN_MESSAGE_TYPE_LEN 2 -#define STUN_MESSAGE_LENGTH_POS \ - (STUN_MESSAGE_TYPE_POS + STUN_MESSAGE_TYPE_LEN) -#define STUN_MESSAGE_LENGTH_LEN 2 -#define STUN_MESSAGE_TRANS_ID_POS \ - (STUN_MESSAGE_LENGTH_POS + STUN_MESSAGE_LENGTH_LEN) -#define STUN_MESSAGE_TRANS_ID_LEN 16 -#define STUN_MESSAGE_ATTRIBUTES_POS \ - (STUN_MESSAGE_TRANS_ID_POS + STUN_MESSAGE_TRANS_ID_LEN) - -#define STUN_MESSAGE_HEADER_LENGTH STUN_MESSAGE_ATTRIBUTES_POS - -#define STUN_ATTRIBUTE_TYPE_POS 0 -#define STUN_ATTRIBUTE_TYPE_LEN 2 -#define STUN_ATTRIBUTE_LENGTH_POS \ - (STUN_ATTRIBUTE_TYPE_POS + STUN_ATTRIBUTE_TYPE_LEN) -#define STUN_ATTRIBUTE_LENGTH_LEN 2 -#define STUN_ATTRIBUTE_VALUE_POS \ - (STUN_ATTRIBUTE_LENGTH_POS + STUN_ATTRIBUTE_LENGTH_LEN) - -/** - * STUN_ATTRIBUTE_HEADER_LENGTH: - * - * Length of a single STUN attribute header (in bytes). - */ -#define STUN_ATTRIBUTE_HEADER_LENGTH STUN_ATTRIBUTE_VALUE_POS - - -#define STUN_MAX_MESSAGE_SIZE_IPV4 576 -#define STUN_MAX_MESSAGE_SIZE_IPV6 1280 -/* #define STUN_MAX_MESSAGE_SIZE STUN_MAX_MESSAGE_SIZE_IPV4 */ - -#define STUN_ID_LEN 16 - -/** - * STUN_AGENT_MAX_SAVED_IDS: - * - * Maximum number of simultaneously ongoing STUN transactions. - */ -#define STUN_AGENT_MAX_SAVED_IDS 200 - -/** - * STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES: - * - * Maximum number of unknown attribute which can be handled in a single STUN - * message. - */ -#define STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES 256 - -#define STUN_MAGIC_COOKIE 0x2112A442 -#define TURN_MAGIC_COOKIE 0x72c64bc6 - -#ifndef TRUE -#define TRUE (1 == 1) -#endif - -#ifndef FALSE -#define FALSE (0 == 1) -#endif - -#endif /* _STUN_CONSTANTS_H */ diff --git a/stun/debug.c b/stun/debug.c deleted file mode 100644 index 9d3d59b..0000000 --- a/stun/debug.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#include "debug.h" - - -static int debug_enabled = 0; - -void stun_debug_enable (void) { - debug_enabled = 1; -} -void stun_debug_disable (void) { - debug_enabled = 0; -} - -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) -#define GNUC_PRINTF(format_idx, arg_idx) \ - __attribute__((__format__ (__printf__, format_idx, arg_idx))) -#else -#define GNUC_PRINTF( format_idx, arg_idx) -#endif - -static void -default_handler (const char *format, va_list ap) GNUC_PRINTF (1, 0); - -static void -default_handler (const char *format, va_list ap) -{ - vfprintf (stderr, format, ap); - fprintf (stderr, "\n"); -} - -static StunDebugHandler handler = default_handler; - -void stun_debug (const char *fmt, ...) -{ - va_list ap; - if (debug_enabled) { - va_start (ap, fmt); - handler (fmt, ap); - va_end (ap); - } -} - -void stun_debug_bytes (const char *prefix, const void *data, size_t len) -{ - size_t i; - size_t prefix_len = strlen (prefix); - char *bytes; - char *j; - unsigned char k; - const char *hex = "0123456789abcdef"; - - if (!debug_enabled) - return; - - bytes = malloc (prefix_len + 2 + (len * 2) + 1); - bytes[0] = 0; - strcpy (bytes, prefix); - strcpy (bytes + prefix_len, "0x"); - - j = bytes + prefix_len + 2; - for (i = 0; i < len; i++) { - k = ((const unsigned char *)data)[i]; - j[0] = hex[(k & 0xf0) >> 4]; - j[1] = hex[k & 0xf]; - j = j + 2; - } - j[0] = 0; - stun_debug ("%s", bytes); - free (bytes); -} - - -void stun_set_debug_handler (StunDebugHandler _handler) -{ - if (_handler == NULL) - _handler = default_handler; - - handler = _handler; -} - diff --git a/stun/debug.h b/stun/debug.h deleted file mode 100644 index 47a6114..0000000 --- a/stun/debug.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef STUN_DEBUG_H -#define STUN_DEBUG_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * stun_debug_enable: - * - * Enable debug messages to stderr - */ -void stun_debug_enable (void); - -/** - * stun_debug_disable: - * - * Disable debug messages to stderr - */ -void stun_debug_disable (void); - -/** - * StunDebugHandler: - * @format: printf()-style debug message format string - * @ap: Parameters to substitute into message placeholders - * - * Callback for a debug message from the STUN code. - */ -#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)) -typedef void (*StunDebugHandler) (const char *format, va_list ap) - __attribute__((__format__ (__printf__, 1, 0))); -#else -typedef void (*StunDebugHandler) (const char *format, va_list ap); -#endif - -/** - * stun_set_debug_handler: - * @handler: (nullable): Handler for STUN debug messages, or %NULL to use the - * default - * - * Set a callback function to be invoked for each debug message from the STUN - * code. The callback will only be invoked if STUN debugging is enabled using - * stun_debug_enable(). - * - * The default callback prints the formatted debug message to stderr. - */ -void stun_set_debug_handler (StunDebugHandler handler); - -#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)) -void stun_debug (const char *fmt, ...) - __attribute__((__format__ (__printf__, 1, 2))); -#else -void stun_debug (const char *fmt, ...); -#endif -void stun_debug_bytes (const char *prefix, const void *data, size_t len); - - -# ifdef __cplusplus -} -# endif - -#endif /* STUN_DEBUG_H */ diff --git a/stun/meson.build b/stun/meson.build deleted file mode 100644 index 2c7cb82..0000000 --- a/stun/meson.build +++ /dev/null @@ -1,41 +0,0 @@ -stun_sources = [ - 'stunagent.c', - 'stunmessage.c', - 'stun5389.c', - 'stuncrc32.c', - 'rand.c', - 'stunhmac.c', - 'utils.c', - 'debug.c', - 'usages/ice.c', - 'usages/bind.c', - 'usages/turn.c', - 'usages/timer.c', -] - -stun_include = include_directories('.') - -install_headers( - 'stunagent.h', - 'stunmessage.h', - 'win32_common.h', # installed unconditionally?! - 'debug.h', - 'constants.h', subdir: 'stun') - -install_headers( - 'usages/bind.h', - 'usages/ice.h', - 'usages/turn.h', - 'usages/timer.h', subdir: 'stun/usages') - -libstun = static_library('stun', stun_sources, - c_args: ['-DG_LOG_DOMAIN="libnice-stun"'], - include_directories: nice_incs, - dependencies: nice_deps, - install: false) - -subdir('tools') - -if not get_option('tests').disabled() - subdir('tests') -endif diff --git a/stun/rand.c b/stun/rand.c deleted file mode 100644 index cc0927f..0000000 --- a/stun/rand.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. All rights reserved. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - - - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "rand.h" - - -#ifdef _WIN32 - -#include -#include - -void nice_RAND_nonce (uint8_t *dst, int len) -{ - HCRYPTPROV hCryptProv; - LPCSTR container = "Libnice key container"; - - if(!CryptAcquireContext(&hCryptProv, container, NULL, PROV_RSA_FULL, 0)) { - /* non existing container. try to create a new one */ - // I hope this cast here doesn't cause issues - // gcc was complaining about comparing signed and unsigned values - if (GetLastError() == (DWORD) NTE_BAD_KEYSET) { - if(!CryptAcquireContext(&hCryptProv, container, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { - return; - } - } - return; - } - - CryptGenRandom (hCryptProv, len, dst); - - CryptReleaseContext(hCryptProv,0); -} -#else - -#ifdef HAVE_OPENSSL - -#include - -void nice_RAND_nonce (uint8_t *dst, int len) -{ - RAND_bytes (dst, len); -} - -#else - -#include -#include -#include - -void nice_RAND_nonce (uint8_t *dst, int len) -{ - gnutls_rnd (GNUTLS_RND_NONCE, dst, len); -} - -#endif /* HAVE_OPENSSL */ - -#endif /* _WIN32 */ diff --git a/stun/rand.h b/stun/rand.h deleted file mode 100644 index 4266a4f..0000000 --- a/stun/rand.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. All rights reserved. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - - -#ifndef RAND_H -#define RAND_H - - -#ifdef _WIN32 -#include "win32_common.h" -#else -#include -#endif - -void nice_RAND_nonce (uint8_t *dst, int len); - -#endif /* RAND_H */ diff --git a/stun/stun5389.c b/stun/stun5389.c deleted file mode 100644 index 136531d..0000000 --- a/stun/stun5389.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef _WIN32 -#include -#else -#include -#include /* htons() */ -#endif - -#include -#include - -#include "stun5389.h" -#include "stuncrc32.h" -#include "stunmessage.h" - - -static const char utf8_skip_data[256] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 -}; - -#define next_utf8_char(p) (char *)((p) + \ - utf8_skip_data[*(const unsigned char *)(p)]) - -uint32_t stun_fingerprint (const uint8_t *msg, size_t len, - bool wlm2009_stupid_crc32_typo) -{ - crc_data data[3]; - uint16_t fakelen = htons (len - 20u); - - // assert (len >= 28u); - - data[0].buf = (void *)msg; - data[0].len = 2; - data[1].buf = (uint8_t *)&fakelen; - data[1].len = 2; - data[2].buf = (void *)(msg + 4); - /* first 4 bytes done, last 8 bytes not summed */ - data[2].len = len - 12u; - - return htonl (stun_crc32 (data, 3, wlm2009_stupid_crc32_typo) ^ 0x5354554e); -} - -bool stun_message_has_cookie (const StunMessage *msg) -{ - StunTransactionId id; - uint32_t cookie = htonl (STUN_MAGIC_COOKIE); - stun_message_id (msg, id); - return memcmp (id, &cookie, sizeof (cookie)) == 0; -} - - -StunMessageReturn stun_message_append_software (StunMessage *msg, - const char *software) -{ - int len = 0; - const char *ptr = NULL; - - if (software == NULL) - software = PACKAGE_STRING; - - ptr = software; - while (*ptr && len < 128) { - ptr = next_utf8_char (ptr); - len++; - } - - return stun_message_append_bytes (msg, STUN_ATTRIBUTE_SOFTWARE, software, - ptr - software); -} diff --git a/stun/stun5389.h b/stun/stun5389.h deleted file mode 100644 index 5f3a65e..0000000 --- a/stun/stun5389.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - - -#ifndef _STUN_5389_H -#define _STUN_5389_H - - -#ifdef _WIN32 -#include "win32_common.h" -#else -# include -# include -#endif -# include - -#include "stunmessage.h" -/* - * Computes the FINGERPRINT checksum of a STUN message. - * @param msg pointer to the STUN message - * @param len size of the message from header (inclusive) and up to - * FINGERPRINT attribute (inclusive) - * - * @return fingerprint value in host byte order. - */ -uint32_t stun_fingerprint (const uint8_t *msg, size_t len, - bool wlm2009_stupid_crc32_typo); - -StunMessageReturn stun_message_append_software (StunMessage *msg, - const char *software); - - -#endif /* _STUN_5389_H */ - diff --git a/stun/stunagent.c b/stun/stunagent.c deleted file mode 100644 index 26adb9f..0000000 --- a/stun/stunagent.c +++ /dev/null @@ -1,739 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "stunmessage.h" -#include "stunagent.h" -#include "stunhmac.h" -#include "stun5389.h" -#include "utils.h" - -#include -#include -#include - - -static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type); -static unsigned stun_agent_find_unknowns (StunAgent *agent, - const StunMessage * msg, uint16_t *list, unsigned max); - -void stun_agent_init (StunAgent *agent, const uint16_t *known_attributes, - StunCompatibility compatibility, StunAgentUsageFlags usage_flags) -{ - int i; - - agent->known_attributes = (uint16_t *) known_attributes; - agent->compatibility = compatibility; - agent->usage_flags = usage_flags; - agent->software_attribute = NULL; - agent->ms_ice2_send_legacy_connchecks = - compatibility == STUN_COMPATIBILITY_MSICE2; - - for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) { - agent->sent_ids[i].valid = FALSE; - } -} - - -bool stun_agent_default_validater (StunAgent *agent, - StunMessage *message, uint8_t *username, uint16_t username_len, - uint8_t **password, size_t *password_len, void *user_data) -{ - StunDefaultValidaterData* val = (StunDefaultValidaterData *) user_data; - int i; - - for (i = 0; val && val[i].username ; i++) { -#if 0 - stun_debug ("Comparing username of size %d and %" PRIuPTR ": %d", - username_len, val[i].username_len, - (memcmp (username, val[i].username, username_len) == 0)); -#endif - stun_debug_bytes (" First username: ", username, username_len); - stun_debug_bytes (" Second username: ", val[i].username, - val[i].username_len); - if (username_len == val[i].username_len && - memcmp (username, val[i].username, username_len) == 0) { - *password = (uint8_t *) val[i].password; - *password_len = val[i].password_len; - stun_debug ("Found valid username, returning password : '%s'", *password); - return TRUE; - } - } - - return FALSE; - -} - -static bool stun_agent_check_fingerprint(StunAgent *agent, StunMessage *msg) -{ - uint32_t fpr; - uint32_t crc32; - uint16_t msg_len; - - /* Looks for FINGERPRINT */ - if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) != - STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug ("STUN demux error: no FINGERPRINT attribute!"); - return FALSE; - } - - msg_len = stun_message_length (msg); - - /* Checks FINGERPRINT */ - crc32 = stun_fingerprint (msg->buffer, msg_len, FALSE); - fpr = ntohl (fpr); - if (fpr != crc32) { - uint16_t palen; - - /* [MS-ICE2] 3.1.4.8.2 Connectivity Checks Phase - legacy compatibility */ - if (agent->compatibility == STUN_COMPATIBILITY_MSICE2 && - stun_message_find (msg, STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION, - &palen) == NULL && - fpr == stun_fingerprint (msg->buffer, msg_len, TRUE)) { - return TRUE; - } - - stun_debug ("STUN demux error: bad fingerprint: 0x%08x, expected: 0x%08x!", - fpr, crc32); - return FALSE; - } - - return TRUE; -} - -StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg, - const uint8_t *buffer, size_t buffer_len, - StunMessageIntegrityValidate validater, void * validater_data) -{ - StunTransactionId msg_id; - int len; - uint8_t *username = NULL; - uint16_t username_len; - uint8_t *key = NULL; - size_t key_len; - uint8_t *hash; - uint8_t sha[20]; - uint16_t hlen; - uint32_t implementation_version; - int sent_id_idx = -1; - uint16_t unknown; - int error_code; - int ignore_credentials = 0; - uint8_t long_term_key[16] = { 0 }; - bool long_term_key_valid = FALSE; - - len = stun_message_validate_buffer_length (buffer, buffer_len, - !(agent->usage_flags & STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES)); - if (len == STUN_MESSAGE_BUFFER_INVALID) { - return STUN_VALIDATION_NOT_STUN; - } else if (len == STUN_MESSAGE_BUFFER_INCOMPLETE) { - return STUN_VALIDATION_INCOMPLETE_STUN; - } else if (len != (int) buffer_len) { - return STUN_VALIDATION_NOT_STUN; - } - - msg->buffer = (uint8_t *) buffer; - msg->buffer_len = buffer_len; - msg->agent = agent; - msg->key = NULL; - msg->key_len = 0; - msg->long_term_valid = FALSE; - - /* TODO: reject it or not ? */ - if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 || - agent->compatibility == STUN_COMPATIBILITY_MSICE2) && - !stun_message_has_cookie (msg)) { - stun_debug ("STUN demux error: no cookie!"); - return STUN_VALIDATION_BAD_REQUEST; - } - - if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 || - agent->compatibility == STUN_COMPATIBILITY_MSICE2) && - agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) { - if (stun_agent_check_fingerprint(agent, msg) == FALSE) { - return STUN_VALIDATION_BAD_REQUEST; - } - - stun_debug ("STUN demux: OK!"); - } - - if (stun_message_get_class (msg) == STUN_RESPONSE || - stun_message_get_class (msg) == STUN_ERROR) { - stun_message_id (msg, msg_id); - for (sent_id_idx = 0; sent_id_idx < STUN_AGENT_MAX_SAVED_IDS; sent_id_idx++) { - if (agent->sent_ids[sent_id_idx].valid == TRUE && - agent->sent_ids[sent_id_idx].method == stun_message_get_method (msg) && - memcmp (msg_id, agent->sent_ids[sent_id_idx].id, - sizeof(StunTransactionId)) == 0) { - - key = agent->sent_ids[sent_id_idx].key; - key_len = agent->sent_ids[sent_id_idx].key_len; - memcpy (long_term_key, agent->sent_ids[sent_id_idx].long_term_key, - sizeof(long_term_key)); - long_term_key_valid = agent->sent_ids[sent_id_idx].long_term_valid; - break; - } - } - if (sent_id_idx == STUN_AGENT_MAX_SAVED_IDS) { - return STUN_VALIDATION_UNMATCHED_RESPONSE; - } - } - - ignore_credentials = - (agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) || - (stun_message_get_class (msg) == STUN_ERROR && - stun_message_find_error (msg, &error_code) == - STUN_MESSAGE_RETURN_SUCCESS && - (error_code == STUN_ERROR_BAD_REQUEST || - error_code == STUN_ERROR_UNAUTHORIZED || - error_code == STUN_ERROR_STALE_NONCE || - error_code == STUN_ERROR_TRY_ALTERNATE)) || - (stun_message_get_class (msg) == STUN_INDICATION && - (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS || - agent->usage_flags & STUN_AGENT_USAGE_NO_INDICATION_AUTH)); - - if (key == NULL && - ignore_credentials == 0 && - (stun_message_get_class (msg) == STUN_REQUEST || - stun_message_get_class (msg) == STUN_INDICATION) && - (((agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS) && - (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) || - !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY))) || - ((agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) && - stun_message_get_class (msg) == STUN_REQUEST && - (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) || - !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) || - !stun_message_has_attribute (msg, STUN_ATTRIBUTE_NONCE) || - !stun_message_has_attribute (msg, STUN_ATTRIBUTE_REALM))) || - ((agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) == 0 && - stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) && - !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY)))) { - return STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST; - } - - if (stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) && - ((key == NULL && ignore_credentials == 0) || - (agent->usage_flags & STUN_AGENT_USAGE_FORCE_VALIDATER))) { - username_len = 0; - username = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_USERNAME, - &username_len); - if (validater == NULL || - validater (agent, msg, username, username_len, - &key, &key_len, validater_data) == FALSE) { - return STUN_VALIDATION_UNAUTHORIZED; - } - } - - if (ignore_credentials == 0 && key != NULL && key_len > 0) { - hash = (uint8_t *) stun_message_find (msg, - STUN_ATTRIBUTE_MESSAGE_INTEGRITY, &hlen); - - if (hash) { - /* We must give the size from start to the end of the attribute - because you might have a FINGERPRINT attribute after it... */ - if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) { - uint8_t *realm = NULL; - uint16_t realm_len; - uint8_t md5[16]; - - if (long_term_key_valid) { - memcpy (md5, long_term_key, sizeof (md5)); - } else { - realm = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_REALM, &realm_len); - username = (uint8_t *) stun_message_find (msg, - STUN_ATTRIBUTE_USERNAME, &username_len); - if (username == NULL || realm == NULL) { - return STUN_VALIDATION_UNAUTHORIZED; - } - stun_hash_creds (realm, realm_len, - username, username_len, - key, key_len, md5); - } - - memcpy (msg->long_term_key, md5, sizeof(md5)); - msg->long_term_valid = TRUE; - - if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 || - agent->compatibility == STUN_COMPATIBILITY_OC2007) { - stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer, - sha, md5, sizeof(md5), TRUE); - } else if (agent->compatibility == STUN_COMPATIBILITY_MSICE2) { - stun_sha1 (msg->buffer, hash + 20 - msg->buffer, - stun_message_length (msg) - 20, sha, md5, sizeof(md5), TRUE); - } else { - stun_sha1 (msg->buffer, hash + 20 - msg->buffer, - hash - msg->buffer, sha, md5, sizeof(md5), FALSE); - } - } else { - if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 || - agent->compatibility == STUN_COMPATIBILITY_OC2007) { - stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer, - sha, key, key_len, TRUE); - } else if (agent->compatibility == STUN_COMPATIBILITY_MSICE2) { - stun_sha1 (msg->buffer, hash + 20 - msg->buffer, - stun_message_length (msg) - 20, sha, key, key_len, TRUE); - } else { - stun_sha1 (msg->buffer, hash + 20 - msg->buffer, - hash - msg->buffer, sha, key, key_len, FALSE); - } - } - - stun_debug (" Message HMAC-SHA1 fingerprint:"); - stun_debug_bytes (" key : ", key, key_len); - stun_debug_bytes (" expected: ", sha, sizeof (sha)); - stun_debug_bytes (" received: ", hash, sizeof (sha)); - - if (memcmp (sha, hash, sizeof (sha))) { - stun_debug ("STUN auth error: SHA1 fingerprint mismatch!"); - return STUN_VALIDATION_UNAUTHORIZED; - } - - stun_debug ("STUN auth: OK!"); - msg->key = key; - msg->key_len = key_len; - } else if (!(stun_message_get_class (msg) == STUN_ERROR && - stun_message_find_error (msg, &error_code) == - STUN_MESSAGE_RETURN_SUCCESS && - (error_code == STUN_ERROR_BAD_REQUEST || - error_code == STUN_ERROR_UNAUTHORIZED))) { - stun_debug ("STUN auth error: No message integrity attribute!"); - return STUN_VALIDATION_UNAUTHORIZED; - } - } - - - if (sent_id_idx != -1 && sent_id_idx < STUN_AGENT_MAX_SAVED_IDS) { - agent->sent_ids[sent_id_idx].valid = FALSE; - } - - /* [MS-ICE2] 3.1.4.8.2 stop sending additional connectivity checks */ - if (stun_message_find32(msg, STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION, - &implementation_version) == STUN_MESSAGE_RETURN_SUCCESS) { - msg->agent->ms_ice2_send_legacy_connchecks = FALSE; - } - - if (stun_agent_find_unknowns (agent, msg, &unknown, 1) > 0) { - if (stun_message_get_class (msg) == STUN_REQUEST) - return STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE; - else - return STUN_VALIDATION_UNKNOWN_ATTRIBUTE; - } - return STUN_VALIDATION_SUCCESS; - -} - -bool stun_agent_forget_transaction (StunAgent *agent, StunTransactionId id) -{ - int i; - - for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) { - if (agent->sent_ids[i].valid == TRUE && - memcmp (id, agent->sent_ids[i].id, - sizeof(StunTransactionId)) == 0) { - agent->sent_ids[i].valid = FALSE; - return TRUE; - } - } - - return FALSE; -} - -bool stun_agent_init_request (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, StunMethod m) -{ - bool ret; - StunTransactionId id; - - msg->buffer = buffer; - msg->buffer_len = buffer_len; - msg->agent = agent; - msg->key = NULL; - msg->key_len = 0; - msg->long_term_valid = FALSE; - - stun_make_transid (id); - - ret = stun_message_init (msg, STUN_REQUEST, m, id); - - if (ret) { - if (agent->compatibility == STUN_COMPATIBILITY_RFC5389 || - agent->compatibility == STUN_COMPATIBILITY_MSICE2) { - uint32_t cookie = htonl (STUN_MAGIC_COOKIE); - memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie)); - } - if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 || - agent->compatibility == STUN_COMPATIBILITY_MSICE2) && - (agent->software_attribute != NULL || - agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE)) { - stun_message_append_software (msg, agent->software_attribute); - } - } - - return ret; -} - - -bool stun_agent_init_indication (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, StunMethod m) -{ - bool ret; - StunTransactionId id; - - msg->buffer = buffer; - msg->buffer_len = buffer_len; - msg->agent = agent; - msg->key = NULL; - msg->key_len = 0; - msg->long_term_valid = FALSE; - - stun_make_transid (id); - ret = stun_message_init (msg, STUN_INDICATION, m, id); - - if (ret) { - if (agent->compatibility == STUN_COMPATIBILITY_RFC5389 || - agent->compatibility == STUN_COMPATIBILITY_MSICE2) { - uint32_t cookie = htonl (STUN_MAGIC_COOKIE); - memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie)); - } - } - - return ret; -} - - -bool stun_agent_init_response (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, const StunMessage *request) -{ - - StunTransactionId id; - - if (stun_message_get_class (request) != STUN_REQUEST) { - return FALSE; - } - - msg->buffer = buffer; - msg->buffer_len = buffer_len; - msg->agent = agent; - msg->key = request->key; - msg->key_len = request->key_len; - memmove (msg->long_term_key, request->long_term_key, - sizeof(msg->long_term_key)); - msg->long_term_valid = request->long_term_valid; - - stun_message_id (request, id); - - if (stun_message_init (msg, STUN_RESPONSE, - stun_message_get_method (request), id)) { - - if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 || - agent->compatibility == STUN_COMPATIBILITY_MSICE2) && - (agent->software_attribute != NULL || - agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE)) { - stun_message_append_software (msg, agent->software_attribute); - } - return TRUE; - } - return FALSE; -} - - -bool stun_agent_init_error (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, const StunMessage *request, - StunError err) -{ - StunTransactionId id; - - if (stun_message_get_class (request) != STUN_REQUEST) { - return FALSE; - } - - msg->buffer = buffer; - msg->buffer_len = buffer_len; - msg->agent = agent; - msg->key = request->key; - msg->key_len = request->key_len; - memmove (msg->long_term_key, request->long_term_key, - sizeof(msg->long_term_key)); - msg->long_term_valid = request->long_term_valid; - - stun_message_id (request, id); - - - if (stun_message_init (msg, STUN_ERROR, - stun_message_get_method (request), id)) { - - if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 || - agent->compatibility == STUN_COMPATIBILITY_MSICE2) && - (agent->software_attribute != NULL || - agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE)) { - stun_message_append_software (msg, agent->software_attribute); - } - if (stun_message_append_error (msg, err) == STUN_MESSAGE_RETURN_SUCCESS) { - return TRUE; - } - } - return FALSE; -} - - -size_t stun_agent_build_unknown_attributes_error (StunAgent *agent, - StunMessage *msg, uint8_t *buffer, size_t buffer_len, - const StunMessage *request) -{ - - unsigned counter; - uint16_t ids[STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES]; - - counter = stun_agent_find_unknowns (agent, request, - ids, STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES); - - if (stun_agent_init_error (agent, msg, buffer, buffer_len, - request, STUN_ERROR_UNKNOWN_ATTRIBUTE) == FALSE) { - return 0; - } - - /* NOTE: Old RFC3489 compatibility: - * When counter is odd, duplicate one value for 32-bits padding. */ - if (!stun_message_has_cookie (request) && (counter & 1)) - ids[counter++] = ids[0]; - - if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES, - ids, counter * 2) == STUN_MESSAGE_RETURN_SUCCESS) { - return stun_agent_finish_message (agent, msg, request->key, request->key_len); - } - - return 0; -} - - -size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg, - const uint8_t *key, size_t key_len) -{ - uint8_t *ptr; - uint32_t fpr; - int saved_id_idx = 0; - uint8_t md5[16]; - bool remember_transaction; - - remember_transaction = (stun_message_get_class (msg) == STUN_REQUEST); - - if (agent->compatibility == STUN_COMPATIBILITY_OC2007 && - stun_message_get_method (msg) == STUN_SEND) { - /* As per [MS-TURN] Section 2.2.1, the TURN server doesn't send responses to - * STUN_SEND requests, so don't bother waiting for them. More details at - * https://msdn.microsoft.com/en-us/library/dd946797%28v=office.12%29.aspx. - */ - remember_transaction = FALSE; - } - - if (remember_transaction) { - for (saved_id_idx = 0; saved_id_idx < STUN_AGENT_MAX_SAVED_IDS; saved_id_idx++) { - if (agent->sent_ids[saved_id_idx].valid == FALSE) { - break; - } - } - } - if (saved_id_idx == STUN_AGENT_MAX_SAVED_IDS) { - stun_debug ("WARNING: Saved IDs full. STUN message dropped."); - return 0; - } - - if (msg->key != NULL) { - key = msg->key; - key_len = msg->key_len; - } - - if (key != NULL) { - bool skip = FALSE; - - if (msg->long_term_valid) { - memcpy (md5, msg->long_term_key, sizeof(msg->long_term_key)); - } else if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) { - uint8_t *realm = NULL; - uint8_t *username = NULL; - uint16_t realm_len; - uint16_t username_len; - - realm = (uint8_t *) stun_message_find (msg, - STUN_ATTRIBUTE_REALM, &realm_len); - username = (uint8_t *) stun_message_find (msg, - STUN_ATTRIBUTE_USERNAME, &username_len); - if (username == NULL || realm == NULL) { - skip = TRUE; - } else { - stun_hash_creds (realm, realm_len, - username, username_len, - key, key_len, md5); - memcpy (msg->long_term_key, md5, sizeof(msg->long_term_key)); - msg->long_term_valid = TRUE; - } - } - - /* If no realm/username and long term credentials, - then don't send the message integrity */ - if (skip == FALSE) { - ptr = stun_message_append (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, 20); - if (ptr == NULL) { - return 0; - } - if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) { - if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 || - agent->compatibility == STUN_COMPATIBILITY_OC2007) { - stun_sha1 (msg->buffer, stun_message_length (msg), - stun_message_length (msg) - 20, ptr, md5, sizeof(md5), TRUE); - } else if (agent->compatibility == STUN_COMPATIBILITY_MSICE2) { - size_t minus = 20; - if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) - minus -= 8; - - stun_sha1 (msg->buffer, stun_message_length (msg), - stun_message_length (msg) - minus, ptr, md5, sizeof(md5), TRUE); - } else { - stun_sha1 (msg->buffer, stun_message_length (msg), - stun_message_length (msg) - 20, ptr, md5, sizeof(md5), FALSE); - } - } else { - if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 || - agent->compatibility == STUN_COMPATIBILITY_OC2007) { - stun_sha1 (msg->buffer, stun_message_length (msg), - stun_message_length (msg) - 20, ptr, key, key_len, TRUE); - } else if (agent->compatibility == STUN_COMPATIBILITY_MSICE2) { - size_t minus = 20; - if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) - minus -= 8; - - stun_sha1 (msg->buffer, stun_message_length (msg), - stun_message_length (msg) - minus, ptr, key, key_len, TRUE); - } else { - stun_sha1 (msg->buffer, stun_message_length (msg), - stun_message_length (msg) - 20, ptr, key, key_len, FALSE); - } - } - - stun_debug (" Message HMAC-SHA1 message integrity:"); - stun_debug_bytes (" key : ", key, key_len); - stun_debug_bytes (" sent : ", ptr, 20); - } - } - - if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 || - agent->compatibility == STUN_COMPATIBILITY_MSICE2) && - agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) { - ptr = stun_message_append (msg, STUN_ATTRIBUTE_FINGERPRINT, 4); - if (ptr == NULL) { - return 0; - } - - fpr = stun_fingerprint (msg->buffer, stun_message_length (msg), FALSE); - memcpy (ptr, &fpr, sizeof (fpr)); - - stun_debug_bytes (" Message HMAC-SHA1 fingerprint: ", ptr, 4); - } - - - if (remember_transaction) { - stun_message_id (msg, agent->sent_ids[saved_id_idx].id); - agent->sent_ids[saved_id_idx].method = stun_message_get_method (msg); - agent->sent_ids[saved_id_idx].key = (uint8_t *) key; - agent->sent_ids[saved_id_idx].key_len = key_len; - memcpy (agent->sent_ids[saved_id_idx].long_term_key, msg->long_term_key, - sizeof(msg->long_term_key)); - agent->sent_ids[saved_id_idx].long_term_valid = msg->long_term_valid; - agent->sent_ids[saved_id_idx].valid = TRUE; - } - - msg->key = (uint8_t *) key; - msg->key_len = key_len; - return stun_message_length (msg); - -} - -static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type) -{ - - uint16_t *known_attr = agent->known_attributes; - - while(*known_attr != 0) { - if (*known_attr == type) { - return FALSE; - } - known_attr++; - } - - return TRUE; - -} - - -static unsigned -stun_agent_find_unknowns (StunAgent *agent, const StunMessage * msg, - uint16_t *list, unsigned max) -{ - unsigned count = 0; - uint16_t len = stun_message_length (msg); - size_t offset = 0; - - offset = STUN_MESSAGE_ATTRIBUTES_POS; - - while ((offset < len) && (count < max)) - { - size_t alen = stun_getw (msg->buffer + offset + STUN_ATTRIBUTE_TYPE_LEN); - uint16_t atype = stun_getw (msg->buffer + offset); - - if (!stun_optional (atype) && stun_agent_is_unknown (agent, atype)) - { - stun_debug ("STUN unknown: attribute 0x%04x(%u bytes)", - (unsigned)atype, (unsigned)alen); - list[count++] = htons (atype); - } - - if (!(agent->usage_flags & STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES)) - alen = stun_align (alen); - - offset += STUN_ATTRIBUTE_VALUE_POS + alen; - } - - stun_debug ("STUN unknown: %u mandatory attribute(s)!", count); - return count; -} - -void stun_agent_set_software (StunAgent *agent, const char *software) -{ - agent->software_attribute = software; -} diff --git a/stun/stunagent.h b/stun/stunagent.h deleted file mode 100644 index 95e89fd..0000000 --- a/stun/stunagent.h +++ /dev/null @@ -1,521 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _STUN_AGENT_H -#define _STUN_AGENT_H - -/** - * SECTION:stunagent - * @short_description: STUN agent for building and validating STUN messages - * @include: stun/stunagent.h - * @see_also: #StunMessage - * @stability: Stable - * - * The STUN Agent allows you to create and validate STUN messages easily. - * It's main purpose is to make sure the building and validation methods used - * are compatible with the RFC you create it with. It also tracks the transaction - * ids of the requests you send, so you can validate if a STUN response you - * received should be processed by that agent or not. - * - */ - - -#ifdef _WIN32 -#include "win32_common.h" -#else -#include -#endif - -#include -#include - -/** - * StunAgent: - * - * An opaque structure representing the STUN agent. - */ -typedef struct stun_agent_t StunAgent; - -#include "stunmessage.h" -#include "debug.h" - -/** - * StunCompatibility: - * @STUN_COMPATIBILITY_RFC3489: Use the STUN specifications compatible with - * RFC 3489 - * @STUN_COMPATIBILITY_RFC5389: Use the STUN specifications compatible with - * RFC 5389 - * @STUN_COMPATIBILITY_MSICE2: Use the STUN specifications compatible with - * [MS-ICE2] (a mix between RFC3489 and RFC5389) - * @STUN_COMPATIBILITY_OC2007: Use the STUN specifications compatible with - * Microsoft Office Communicator 2007 (basically RFC3489 with swapped - * REALM and NONCE attribute hex IDs, attributes are not aligned) - * @STUN_COMPATIBILITY_WLM2009: An alias for @STUN_COMPATIBILITY_MSICE2 - * @STUN_COMPATIBILITY_LAST: Dummy last compatibility mode - * - * Enum that specifies the STUN compatibility mode of the #StunAgent - * - * @STUN_COMPATIBILITY_WLM2009 is deprecated and should not be used - * in newly-written code. It is kept for compatibility reasons and represents - * the same compatibility as @STUN_COMPATIBILITY_MSICE2. - */ -typedef enum { - STUN_COMPATIBILITY_RFC3489, - STUN_COMPATIBILITY_RFC5389, - STUN_COMPATIBILITY_MSICE2, - STUN_COMPATIBILITY_OC2007, - STUN_COMPATIBILITY_WLM2009 = STUN_COMPATIBILITY_MSICE2, - STUN_COMPATIBILITY_LAST = STUN_COMPATIBILITY_OC2007 -} StunCompatibility; - - -/** - * StunValidationStatus: - * @STUN_VALIDATION_SUCCESS: The message is validated - * @STUN_VALIDATION_NOT_STUN: This is not a valid STUN message - * @STUN_VALIDATION_INCOMPLETE_STUN: The message seems to be valid but incomplete - * @STUN_VALIDATION_BAD_REQUEST: The message does not have the cookie or the - * fingerprint while the agent needs it with its usage - * @STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST: The message is valid but - * unauthorized with no username and message-integrity attributes. - * A BAD_REQUEST error must be generated - * @STUN_VALIDATION_UNAUTHORIZED: The message is valid but unauthorized as - * the username/password do not match. - * An UNAUTHORIZED error must be generated - * @STUN_VALIDATION_UNMATCHED_RESPONSE: The message is valid but this is a - * response/error that doesn't match a previously sent request - * @STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE: The message is valid but - * contains one or more unknown comprehension attributes. - * stun_agent_build_unknown_attributes_error() should be called - * @STUN_VALIDATION_UNKNOWN_ATTRIBUTE: The message is valid but contains one - * or more unknown comprehension attributes. This is a response, or error, - * or indication message and no error response should be sent - * - * This enum is used as the return value of stun_agent_validate() and represents - * the status result of the validation of a STUN message. - */ -typedef enum { - STUN_VALIDATION_SUCCESS, - STUN_VALIDATION_NOT_STUN, - STUN_VALIDATION_INCOMPLETE_STUN, - STUN_VALIDATION_BAD_REQUEST, - STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST, - STUN_VALIDATION_UNAUTHORIZED, - STUN_VALIDATION_UNMATCHED_RESPONSE, - STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE, - STUN_VALIDATION_UNKNOWN_ATTRIBUTE, -} StunValidationStatus; - -/** - * StunAgentUsageFlags: - * @STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS: The agent should be using the short - * term credentials mechanism for authenticating STUN messages - * @STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS: The agent should be using the long - * term credentials mechanism for authenticating STUN messages - * @STUN_AGENT_USAGE_USE_FINGERPRINT: The agent should add the FINGERPRINT - * attribute to the STUN messages it creates. - * @STUN_AGENT_USAGE_ADD_SOFTWARE: The agent should add the SOFTWARE attribute - * to the STUN messages it creates. Calling nice_agent_set_software() will have - * the same effect as enabling this Usage. STUN Indications do not have the - * SOFTWARE attributes added to them though. The SOFTWARE attribute is only - * added for the RFC5389 and MSICE2 compatibility modes. - * @STUN_AGENT_USAGE_IGNORE_CREDENTIALS: The agent should ignore any credentials - * in the STUN messages it receives (the MESSAGE-INTEGRITY attribute - * will never be validated by stun_agent_validate()) - * @STUN_AGENT_USAGE_NO_INDICATION_AUTH: The agent should ignore credentials - * in the STUN messages it receives if the #StunClass of the message is - * #STUN_INDICATION (some implementation require #STUN_INDICATION messages to - * be authenticated, while others never add a MESSAGE-INTEGRITY attribute to a - * #STUN_INDICATION message) - * @STUN_AGENT_USAGE_FORCE_VALIDATER: The agent should always try to validate - * the password of a STUN message, even if it already knows what the password - * should be (a response to a previously created request). This means that the - * #StunMessageIntegrityValidate callback will always be called when there is - * a MESSAGE-INTEGRITY attribute. - * @STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES: The agent should not assume STUN - * attributes are aligned on 32-bit boundaries when parsing messages and also - * do not add padding when creating messages. - * - * This enum defines a bitflag usages for a #StunAgent and they will define how - * the agent should behave, independently of the compatibility mode it uses. - * See also: stun_agent_init() - * See also: stun_agent_validate() - */ -typedef enum { - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS = (1 << 0), - STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS = (1 << 1), - STUN_AGENT_USAGE_USE_FINGERPRINT = (1 << 2), - STUN_AGENT_USAGE_ADD_SOFTWARE = (1 << 3), - STUN_AGENT_USAGE_IGNORE_CREDENTIALS = (1 << 4), - STUN_AGENT_USAGE_NO_INDICATION_AUTH = (1 << 5), - STUN_AGENT_USAGE_FORCE_VALIDATER = (1 << 6), - STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES = (1 << 7), -} StunAgentUsageFlags; - - -typedef struct { - StunTransactionId id; - StunMethod method; - uint8_t *key; - size_t key_len; - uint8_t long_term_key[16]; - bool long_term_valid; - bool valid; -} StunAgentSavedIds; - -struct stun_agent_t { - StunCompatibility compatibility; - StunAgentSavedIds sent_ids[STUN_AGENT_MAX_SAVED_IDS]; - uint16_t *known_attributes; - StunAgentUsageFlags usage_flags; - const char *software_attribute; - bool ms_ice2_send_legacy_connchecks; -}; - -/** - * StunDefaultValidaterData: - * @username: The username - * @username_len: The length of the @username - * @password: The password - * @password_len: The length of the @password - * - * This structure is used as an element of the user_data to the - * stun_agent_default_validater() function for authenticating a STUN - * message during validationg. - * See also: stun_agent_default_validater() - */ -typedef struct { - uint8_t *username; - size_t username_len; - uint8_t *password; - size_t password_len; -} StunDefaultValidaterData; - - -/** - * StunMessageIntegrityValidate: - * @agent: The #StunAgent - * @message: The #StunMessage being validated - * @username: The username found in the @message - * @username_len: The length of @username - * @password: The password associated with that username. This argument is a - * pointer to a byte array that must be set by the validater function. - * @password_len: The length of @password which must also be set by the - * validater function. - * @user_data: Data to give the function - * - * This is the prototype for the @validater argument of the stun_agent_validate() - * function. - * See also: stun_agent_validate() - * Returns: %TRUE if the authentication was successful, - * %FALSE if the authentication failed - */ -typedef bool (*StunMessageIntegrityValidate) (StunAgent *agent, - StunMessage *message, uint8_t *username, uint16_t username_len, - uint8_t **password, size_t *password_len, void *user_data); - -/** - * stun_agent_default_validater: - * @agent: The #StunAgent - * @message: The #StunMessage being validated - * @username: The username found in the @message - * @username_len: The length of @username - * @password: The password associated with that username. This argument is a - * pointer to a byte array that must be set by the validater function. - * @password_len: The length of @password which must also be set by the - * validater function. - * @user_data: This must be an array of #StunDefaultValidaterData structures. - * The last element in the array must have a username set to NULL - * - * This is a helper function to be used with stun_agent_validate(). If no - * complicated processing of the username needs to be done, this function can - * be used with stun_agent_validate() to quickly and easily match the username - * of a STUN message with its password. Its @user_data argument must be an array - * of #StunDefaultValidaterData which will allow us to map a username to a - * password - * See also: stun_agent_validate() - * Returns: %TRUE if the authentication was successful, - * %FALSE if the authentication failed - */ -bool stun_agent_default_validater (StunAgent *agent, - StunMessage *message, uint8_t *username, uint16_t username_len, - uint8_t **password, size_t *password_len, void *user_data); - -/** - * stun_agent_init: - * @agent: The #StunAgent to initialize - * @known_attributes: An array of #uint16_t specifying which attributes should - * be known by the agent. Any STUN message received that contains a mandatory - * attribute that is not in this array will yield a - * #STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE or a - * #STUN_VALIDATION_UNKNOWN_ATTRIBUTE error when calling stun_agent_validate() - * @compatibility: The #StunCompatibility to use for this agent. This will affect - * how the agent builds and validates the STUN messages - * @usage_flags: A bitflag using #StunAgentUsageFlags values to define which - * STUN usages the agent should use. - * - * This function must be called to initialize an agent before it is being used. - * - - - The @known_attributes data must exist in memory as long as the @agent is used - - - If the #STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS and - #STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS usage flags are not set, then the - agent will default in using the short term credentials mechanism - - - The #STUN_AGENT_USAGE_USE_FINGERPRINT and #STUN_AGENT_USAGE_ADD_SOFTWARE - usage flags are only valid if the #STUN_COMPATIBILITY_RFC5389 or - #STUN_COMPATIBILITY_MSICE2 @compatibility is used - - - */ -void stun_agent_init (StunAgent *agent, const uint16_t *known_attributes, - StunCompatibility compatibility, StunAgentUsageFlags usage_flags); - -/** - * stun_agent_validate: - * @agent: The #StunAgent - * @msg: The #StunMessage to build - * @buffer: The data buffer of the STUN message - * @buffer_len: The length of @buffer - * @validater: A #StunMessageIntegrityValidate function callback that will - * be called if the agent needs to validate a MESSAGE-INTEGRITY attribute. It - * will only be called if the agent finds a message that needs authentication - * and a USERNAME is present in the STUN message, but no password is known. - * The validater will not be called if the #STUN_AGENT_USAGE_IGNORE_CREDENTIALS - * usage flag is set on the agent, and it will always be called if the - * #STUN_AGENT_USAGE_FORCE_VALIDATER usage flag is set on the agent. - * @validater_data: A user data to give to the @validater callback when it gets - * called. - * - * This function is used to validate an inbound STUN message and transform its - * data buffer into a #StunMessage. It will take care of various validation - * algorithms to make sure that the STUN message is valid and correctly - * authenticated. - * See also: stun_agent_default_validater() - * Returns: A #StunValidationStatus - - - if the return value is different from #STUN_VALIDATION_NOT_STUN or - #STUN_VALIDATION_INCOMPLETE_STUN, then the @msg argument will contain a valid - STUN message that can be used. - This means that you can use the @msg variable as the @request argument to - functions like stun_agent_init_error() or - stun_agent_build_unknown_attributes_error(). - If the return value is #STUN_VALIDATION_BAD_REQUEST, - #STUN_VALIDATION_UNAUTHORIZED or #STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST - then the @key in the #StunMessage will not be set, so that error responses - will not have a MESSAGE-INTEGRITY attribute. - - - */ -StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg, - const uint8_t *buffer, size_t buffer_len, - StunMessageIntegrityValidate validater, void * validater_data); - -/** - * stun_agent_init_request: - * @agent: The #StunAgent - * @msg: The #StunMessage to build - * @buffer: The buffer to use in the #StunMessage - * @buffer_len: The length of the buffer - * @m: The #StunMethod of the request - * - * Creates a new STUN message of class #STUN_REQUEST and with the method @m - * Returns: %TRUE if the message was initialized correctly, %FALSE otherwise - */ -bool stun_agent_init_request (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, StunMethod m); - -/** - * stun_agent_init_indication: - * @agent: The #StunAgent - * @msg: The #StunMessage to build - * @buffer: The buffer to use in the #StunMessage - * @buffer_len: The length of the buffer - * @m: The #StunMethod of the indication - * - * Creates a new STUN message of class #STUN_INDICATION and with the method @m - * Returns: %TRUE if the message was initialized correctly, %FALSE otherwise - */ -bool stun_agent_init_indication (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, StunMethod m); - -/** - * stun_agent_init_response: - * @agent: The #StunAgent - * @msg: The #StunMessage to build - * @buffer: The buffer to use in the #StunMessage - * @buffer_len: The length of the buffer - * @request: The #StunMessage of class #STUN_REQUEST that this response is for - * - * Creates a new STUN message of class #STUN_RESPONSE and with the same method - * and transaction ID as the message @request. This will also copy the pointer - * to the key that was used to authenticate the request, so you won't need to - * specify the key with stun_agent_finish_message() - * Returns: %TRUE if the message was initialized correctly, %FALSE otherwise - */ -bool stun_agent_init_response (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, const StunMessage *request); - -/** - * stun_agent_init_error: - * @agent: The #StunAgent - * @msg: The #StunMessage to build - * @buffer: The buffer to use in the #StunMessage - * @buffer_len: The length of the buffer - * @request: The #StunMessage of class #STUN_REQUEST that this error response - * is for - * @err: The #StunError to put in the ERROR-CODE attribute of the error response - * - * Creates a new STUN message of class #STUN_ERROR and with the same method - * and transaction ID as the message @request. This will also copy the pointer - * to the key that was used to authenticate the request (if authenticated), - * so you won't need to specify the key with stun_agent_finish_message(). - * It will then add the ERROR-CODE attribute with code @err and the associated - * string. - * Returns: %TRUE if the message was initialized correctly, %FALSE otherwise - */ -bool stun_agent_init_error (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, const StunMessage *request, - StunError err); - -/** - * stun_agent_build_unknown_attributes_error: - * @agent: The #StunAgent - * @msg: The #StunMessage to build - * @buffer: The buffer to use in the #StunMessage - * @buffer_len: The length of the buffer - * @request: The #StunMessage of class #STUN_REQUEST that this response is for - * - * Creates a new STUN message of class #STUN_ERROR and with the same method - * and transaction ID as the message @request. It will then add the ERROR-CODE - * attribute with code #STUN_ERROR_UNKNOWN_ATTRIBUTE and add all the unknown - * mandatory attributes from the @request STUN message in the - * #STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES attribute, it will then finish the message - * by calling stun_agent_finish_message() - * Returns: The size of the message built - */ -size_t stun_agent_build_unknown_attributes_error (StunAgent *agent, - StunMessage *msg, uint8_t *buffer, size_t buffer_len, - const StunMessage *request); - - -/** - * stun_agent_finish_message: - * @agent: The #StunAgent - * @msg: The #StunMessage to finish - * @key: The key to use for the MESSAGE-INTEGRITY attribute - * @key_len: The length of the @key - * - * This function will 'finish' a message and make it ready to be sent. It will - * add the MESSAGE-INTEGRITY and FINGERPRINT attributes if necessary. If the - * STUN message has a #STUN_REQUEST class, it will save the transaction id of - * the message in the agent for future matching of the response. - * See also: stun_agent_forget_transaction() - * Returns: The final size of the message built or 0 if an error occured - * - - The return value must always be checked. a value of 0 means the either - the buffer's size is too small to contain the finishing attributes - (MESSAGE-INTEGRITY, FINGERPRINT), or that there is no more free slots - for saving the sent id in the agent's state. - - - Everytime stun_agent_finish_message() is called for a #STUN_REQUEST - message, you must make sure to call stun_agent_forget_transaction() in - case the response times out and is never received. This is to avoid - filling up the #StunAgent's sent ids state preventing any further - use of the stun_agent_finish_message() - - - */ -size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg, - const uint8_t *key, size_t key_len); - -/** - * stun_agent_forget_transaction: - * @agent: The #StunAgent - * @id: The #StunTransactionId of the transaction to forget - * - * This function is used to make the #StunAgent forget about a previously - * created transaction. - * - * This function should be called when a STUN request was previously - * created with stun_agent_finish_message() and for which no response was ever - * received (timed out). The #StunAgent keeps a list of the sent transactions - * in order to validate the responses received. If the response is never received - * this will allow the #StunAgent to forget about the timed out transaction and - * free its slot for future transactions. - * - * Since: 0.0.6 - * Returns: %TRUE if the transaction was found, %FALSE otherwise - */ -bool stun_agent_forget_transaction (StunAgent *agent, StunTransactionId id); - - -/** - * stun_agent_set_software: - * @agent: The #StunAgent - * @software: The value of the SOFTWARE attribute to add. - * - * This function will set the value of the SOFTWARE attribute to be added to - * STUN requests, responses and error responses. - * - * Calling this function will automatically enable the addition of the SOFTWARE - * attribute for RFC5389 and MSICE2 compatibility modes. - * - * - * - - The @software argument must be in UTF-8 encoding and only the first - 128 characters will be sent. - - - The value of the @software argument must stay valid throughout the life of - the StunAgent's life. Do not free its content. - - - * - * Since: 0.0.10 - * - */ -void stun_agent_set_software (StunAgent *agent, const char *software); - -#endif /* _STUN_AGENT_H */ diff --git a/stun/stuncrc32.c b/stun/stuncrc32.c deleted file mode 100644 index 288b7f2..0000000 --- a/stun/stuncrc32.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * COPYRIGHT (C) 1986 Gary S. Brown - * See documentation of the function crc32() below. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * Gary S. Brown - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/*- - * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or - * code or tables extracted from it, as desired without restriction. - * - * Extracted from FreeBSD CVS (src/sys/libkern/crc32.c) - * and adapted by Rémi Denis-Courmont, 2007. - */ - -/* - * First, the polynomial itself and its table of feedback terms. The - * polynomial is - * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 - * - * Note that we take it "backwards" and put the highest-order term in - * the lowest-order bit. The X^32 term is "implied"; the LSB is the - * X^31 term, etc. The X^0 term (usually shown as "+1") results in - * the MSB being 1 - * - * Note that the usual hardware shift register implementation, which - * is what we're using (we're merely optimizing it by doing eight-bit - * chunks at a time) shifts bits into the lowest-order term. In our - * implementation, that means shifting towards the right. Why do we - * do it this way? Because the calculated CRC must be transmitted in - * order from highest-order term to lowest-order term. UARTs transmit - * characters in order from LSB to MSB. By storing the CRC this way - * we hand it to the UART in the order low-byte to high-byte; the UART - * sends each low-bit to hight-bit; and the result is transmission bit - * by bit from highest- to lowest-order term without requiring any bit - * shuffling on our part. Reception works similarly - * - * The feedback terms table consists of 256, 32-bit entries. Notes - * - * The table can be generated at runtime if desired; code to do so - * is shown later. It might not be obvious, but the feedback - * terms simply represent the results of eight shift/xor opera - * tions for all combinations of data and CRC register values - * - * The values must be right-shifted by eight bits by the "updcrc - * logic; the shift must be unsigned (bring in zeroes). On some - * hardware you could probably optimize the shift in assembler by - * using byte-swap instructions - * polynomial $edb88320 - * - * - * CRC32 code derived from work by Gary S. Brown. - */ - - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "stuncrc32.h" - -static const uint32_t crc32_tab[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - - -uint32_t stun_crc32 (const crc_data *data, size_t n, bool wlm2009_stupid_crc32_typo) -{ - size_t i; - uint32_t crc = 0xffffffff; - - for (i = 0; i < n; i++) - { - const uint8_t *p = data[i].buf; - size_t size = data[i].len; - - while (size--) { - uint32_t lkp = crc32_tab[(crc ^ *p++) & 0xFF]; - if (lkp == 0x8bbeb8ea && wlm2009_stupid_crc32_typo) - lkp = 0x8bbe8ea; - crc = lkp ^ (crc >> 8); - } - } - - return crc ^ 0xffffffff; -} diff --git a/stun/stuncrc32.h b/stun/stuncrc32.h deleted file mode 100644 index 3ab3191..0000000 --- a/stun/stuncrc32.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2006-2007 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _CRC32_H -#define _CRC32_H - - -#ifdef _WIN32 -#include "win32_common.h" -#else -#include -#endif - -#include -#include - -typedef struct { - uint8_t *buf; - size_t len; -} crc_data; - - -uint32_t stun_crc32 (const crc_data *data, size_t n, bool wlm2009_stupid_crc32_typo); - -#endif /* _CRC32_H */ diff --git a/stun/stunhmac.c b/stun/stunhmac.c deleted file mode 100644 index c9d183f..0000000 --- a/stun/stunhmac.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "rand.h" - -#include "stunmessage.h" -#include "stunhmac.h" - -#include -#include - -#ifdef HAVE_OPENSSL -#include -#include -#else -#include -#include -#endif - -void stun_sha1 (const uint8_t *msg, size_t len, size_t msg_len, uint8_t *sha, - const void *key, size_t keylen, int padding) -{ - uint16_t fakelen = htons (msg_len); - uint8_t pad_char[64] = {0}; - - assert (len >= 44u); - -#ifdef HAVE_OPENSSL -{ -#ifdef NDEBUG -#define TRY(x) x; -#else - int ret; -#define TRY(x) \ - ret = x; \ - assert (ret == 1); -#endif - -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ - (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - HMAC_CTX stackctx; - HMAC_CTX *ctx = &stackctx; - HMAC_CTX_init (ctx); -#else - HMAC_CTX *ctx = HMAC_CTX_new (); -#endif /* OPENSSL_VERSION_NUMBER */ - - assert (SHA_DIGEST_LENGTH == 20); - - TRY (HMAC_Init_ex (ctx, key, keylen, EVP_sha1(), NULL)); - - TRY (HMAC_Update (ctx, msg, 2)); - TRY (HMAC_Update (ctx, (unsigned char *)&fakelen, 2)); - TRY (HMAC_Update (ctx, msg + 4, len - 28)); - - /* RFC 3489 specifies that the message's size should be 64 bytes, - and \x00 padding should be done */ - if (padding && ((len - 24) % 64) > 0) { - uint16_t pad_size = 64 - ((len - 24) % 64); - - TRY (HMAC_Update (ctx, pad_char, pad_size)); - } - - TRY (HMAC_Final (ctx, sha, NULL)); - -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ - (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - HMAC_CTX_cleanup (ctx); -#else - HMAC_CTX_free (ctx); -#endif /* OPENSSL_VERSION_NUMBER */ -} -#else -{ - gnutls_hmac_hd_t handle; - -#ifdef NDEBUG -#define TRY(x) x; -#else - int ret; -#define TRY(x) \ - ret = x; \ - assert (ret >= 0); -#endif - - assert (gnutls_hmac_get_len (GNUTLS_MAC_SHA1) == 20); - TRY (gnutls_hmac_init (&handle, GNUTLS_MAC_SHA1, key, keylen)); - - TRY (gnutls_hmac (handle, msg, 2)); - TRY (gnutls_hmac (handle, &fakelen, 2)); - TRY (gnutls_hmac (handle, msg + 4, len - 28)); - - /* RFC 3489 specifies that the message's size should be 64 bytes, - and \x00 padding should be done */ - if (padding && ((len - 24) % 64) > 0) { - uint16_t pad_size = 64 - ((len - 24) % 64); - - TRY (gnutls_hmac (handle, pad_char, pad_size)); - } - - gnutls_hmac_deinit (handle, sha); - -#undef TRY -} -#endif /* HAVE_OPENSSL */ -} - -static const uint8_t *priv_trim_var (const uint8_t *var, size_t *var_len) -{ - const uint8_t *ptr = var; - - while (*ptr == '"') { - ptr++; - (*var_len)--; - } - while(ptr[*var_len-1] == '"' || - ptr[*var_len-1] == 0) { - (*var_len)--; - } - - return ptr; -} - - -void stun_hash_creds (const uint8_t *realm, size_t realm_len, - const uint8_t *username, size_t username_len, - const uint8_t *password, size_t password_len, - unsigned char md5[16]) -{ - const uint8_t *username_trimmed = priv_trim_var (username, &username_len); - const uint8_t *password_trimmed = priv_trim_var (password, &password_len); - const uint8_t *realm_trimmed = priv_trim_var (realm, &realm_len); - const uint8_t *colon = (uint8_t *)":"; - -#ifdef HAVE_OPENSSL - EVP_MD_CTX *ctx; - -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ - (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - ctx = EVP_MD_CTX_create (); -#else - ctx = EVP_MD_CTX_new (); -#endif /* OPENSSL_VERSION_NUMBER */ - - EVP_DigestInit_ex (ctx, EVP_md5(), NULL); - EVP_DigestUpdate (ctx, username_trimmed, username_len); - EVP_DigestUpdate (ctx, colon, 1); - EVP_DigestUpdate (ctx, realm_trimmed, realm_len); - EVP_DigestUpdate (ctx, colon, 1); - EVP_DigestUpdate (ctx, password_trimmed, password_len); - EVP_DigestFinal_ex (ctx, md5, NULL); - -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ - (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - EVP_MD_CTX_destroy (ctx); -#else - EVP_MD_CTX_free (ctx); -#endif /* OPENSSL_VERSION_NUMBER */ - -#else - gnutls_hash_hd_t handle; - - gnutls_hash_init (&handle, GNUTLS_DIG_MD5); - gnutls_hash (handle, username_trimmed, username_len); - gnutls_hash (handle, colon, 1); - gnutls_hash (handle, realm_trimmed, realm_len); - gnutls_hash (handle, colon, 1); - gnutls_hash (handle, password_trimmed, password_len); - - gnutls_hash_deinit (handle, md5); -#endif /* HAVE_OPENSSL */ -} - - -void stun_make_transid (StunTransactionId id) -{ - nice_RAND_nonce (id, 16); -} diff --git a/stun/stunhmac.h b/stun/stunhmac.h deleted file mode 100644 index 1a28ac8..0000000 --- a/stun/stunhmac.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _STUN_HMAC_H -#define _STUN_HMAC_H - -#include "stunmessage.h" - -/* - * Computes the MESSAGE-INTEGRITY hash of a STUN message. - * @param msg pointer to the STUN message - * @param len size of the message from header (inclusive) and up to - * MESSAGE-INTEGRITY attribute (inclusive) - * @param sha output buffer for SHA1 hash (20 bytes) - * @param key HMAC key - * @param keylen HMAC key bytes length - * - * @return fingerprint value in host byte order. - */ -void stun_sha1 (const uint8_t *msg, size_t len, size_t msg_len, - uint8_t *sha, const void *key, size_t keylen, int padding); - -/* - * SIP H(A1) computation - */ - -void stun_hash_creds (const uint8_t *realm, size_t realm_len, - const uint8_t *username, size_t username_len, - const uint8_t *password, size_t password_len, - unsigned char md5[16]); -/* - * Generates a pseudo-random secure STUN transaction ID. - */ -void stun_make_transid (StunTransactionId id); - - -#endif /* _STUN_HMAC_H */ diff --git a/stun/stunmessage.c b/stun/stunmessage.c deleted file mode 100644 index 4cc3392..0000000 --- a/stun/stunmessage.c +++ /dev/null @@ -1,761 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "stunmessage.h" -#include "utils.h" - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#endif - - -#include -#include - -bool stun_message_init (StunMessage *msg, StunClass c, StunMethod m, - const StunTransactionId id) -{ - - if (msg->buffer_len < STUN_MESSAGE_HEADER_LENGTH) - return FALSE; - - memset (msg->buffer, 0, 4); - stun_set_type (msg->buffer, c, m); - - memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, - id, STUN_MESSAGE_TRANS_ID_LEN); - - return TRUE; -} - -uint16_t stun_message_length (const StunMessage *msg) -{ - return stun_getw (msg->buffer + STUN_MESSAGE_LENGTH_POS) + - STUN_MESSAGE_HEADER_LENGTH; -} - - - - -const void * -stun_message_find (const StunMessage *msg, StunAttribute type, - uint16_t *palen) -{ - size_t length = stun_message_length (msg); - size_t offset = 0; - - /* In MS-TURN, IDs of REALM and NONCE STUN attributes are swapped. */ - if (msg->agent && msg->agent->compatibility == STUN_COMPATIBILITY_OC2007) - { - if (type == STUN_ATTRIBUTE_REALM) - type = STUN_ATTRIBUTE_NONCE; - else if (type == STUN_ATTRIBUTE_NONCE) - type = STUN_ATTRIBUTE_REALM; - } - - offset = STUN_MESSAGE_ATTRIBUTES_POS; - - while (offset < length) - { - uint16_t atype = stun_getw (msg->buffer + offset); - size_t alen = stun_getw (msg->buffer + offset + STUN_ATTRIBUTE_TYPE_LEN); - - - offset += STUN_ATTRIBUTE_VALUE_POS; - - if (atype == type) - { - *palen = alen; - return msg->buffer + offset; - } - - /* Look for and ignore misordered attributes */ - switch (atype) - { - case STUN_ATTRIBUTE_MESSAGE_INTEGRITY: - /* Only fingerprint may come after M-I */ - if (type == STUN_ATTRIBUTE_FINGERPRINT) - break; - return NULL; - - case STUN_ATTRIBUTE_FINGERPRINT: - /* Nothing may come after FPR */ - return NULL; - - default: - /* Nothing misordered. */ - break; - } - - if (!(msg->agent && - (msg->agent->usage_flags & STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES))) - alen = stun_align (alen); - - offset += alen; - } - - return NULL; -} - - -StunMessageReturn -stun_message_find_flag (const StunMessage *msg, StunAttribute type) -{ - const void *ptr; - uint16_t len = 0; - - ptr = stun_message_find (msg, type, &len); - if (ptr == NULL) - return STUN_MESSAGE_RETURN_NOT_FOUND; - return (len == 0) ? STUN_MESSAGE_RETURN_SUCCESS : - STUN_MESSAGE_RETURN_INVALID; -} - - -StunMessageReturn -stun_message_find32 (const StunMessage *msg, StunAttribute type, - uint32_t *pval) -{ - const void *ptr; - uint16_t len = 0; - - ptr = stun_message_find (msg, type, &len); - if (ptr == NULL) - return STUN_MESSAGE_RETURN_NOT_FOUND; - - if (len == 4) - { - uint32_t val; - - memcpy (&val, ptr, sizeof (val)); - *pval = ntohl (val); - return STUN_MESSAGE_RETURN_SUCCESS; - } - return STUN_MESSAGE_RETURN_INVALID; -} - - -StunMessageReturn -stun_message_find64 (const StunMessage *msg, StunAttribute type, - uint64_t *pval) -{ - const void *ptr; - uint16_t len = 0; - - ptr = stun_message_find (msg, type, &len); - if (ptr == NULL) - return STUN_MESSAGE_RETURN_NOT_FOUND; - - if (len == 8) - { - uint32_t tab[2]; - - memcpy (tab, ptr, sizeof (tab)); - *pval = ((uint64_t)ntohl (tab[0]) << 32) | ntohl (tab[1]); - return STUN_MESSAGE_RETURN_SUCCESS; - } - return STUN_MESSAGE_RETURN_INVALID; -} - - -StunMessageReturn -stun_message_find_string (const StunMessage *msg, StunAttribute type, - char *buf, size_t buflen) -{ - const unsigned char *ptr; - uint16_t len = 0; - - ptr = stun_message_find (msg, type, &len); - if (ptr == NULL) - return STUN_MESSAGE_RETURN_NOT_FOUND; - - if (len >= buflen) - return STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE; - - memcpy (buf, ptr, len); - buf[len] = '\0'; - return STUN_MESSAGE_RETURN_SUCCESS; -} - - -StunMessageReturn -stun_message_find_addr (const StunMessage *msg, StunAttribute type, - struct sockaddr_storage *addr, socklen_t *addrlen) -{ - const uint8_t *ptr; - uint16_t len = 0; - - ptr = stun_message_find (msg, type, &len); - if (ptr == NULL) - return STUN_MESSAGE_RETURN_NOT_FOUND; - - if (len < 4) - return STUN_MESSAGE_RETURN_INVALID; - - switch (ptr[1]) - { - case 1: - { - struct sockaddr_in *ip4 = (struct sockaddr_in *)addr; - if (((size_t) *addrlen < sizeof (*ip4)) || (len != 8)) - { - *addrlen = sizeof (*ip4); - return STUN_MESSAGE_RETURN_INVALID; - } - - memset (ip4, 0, *addrlen); - ip4->sin_family = AF_INET; -#ifdef HAVE_SA_LEN - ip4->sin_len = -#endif - *addrlen = sizeof (*ip4); - memcpy (&ip4->sin_port, ptr + 2, 2); - memcpy (&ip4->sin_addr, ptr + 4, 4); - return STUN_MESSAGE_RETURN_SUCCESS; - } - - case 2: - { - struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)addr; - if (((size_t) *addrlen < sizeof (*ip6)) || (len != 20)) - { - *addrlen = sizeof (*ip6); - return STUN_MESSAGE_RETURN_INVALID; - } - - memset (ip6, 0, *addrlen); - ip6->sin6_family = AF_INET6; -#ifdef HAVE_SA_LEN - ip6->sin6_len = -#endif - *addrlen = sizeof (*ip6); - memcpy (&ip6->sin6_port, ptr + 2, 2); - memcpy (&ip6->sin6_addr, ptr + 4, 16); - return STUN_MESSAGE_RETURN_SUCCESS; - } - - default: - return STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS; - } -} - -StunMessageReturn -stun_message_find_xor_addr (const StunMessage *msg, StunAttribute type, - struct sockaddr_storage *addr, socklen_t *addrlen) -{ - StunMessageReturn val = stun_message_find_addr (msg, type, addr, addrlen); - if (val) - return val; - - return stun_xor_address (msg, addr, *addrlen, STUN_MAGIC_COOKIE); -} - -StunMessageReturn -stun_message_find_xor_addr_full (const StunMessage *msg, StunAttribute type, - struct sockaddr_storage *addr, socklen_t *addrlen, uint32_t magic_cookie) -{ - StunMessageReturn val = stun_message_find_addr (msg, type, addr, addrlen); - if (val) - return val; - - return stun_xor_address (msg, addr, *addrlen, magic_cookie); -} - -StunMessageReturn -stun_message_find_error (const StunMessage *msg, int *code) -{ - uint16_t alen = 0; - const uint8_t *ptr = stun_message_find (msg, STUN_ATTRIBUTE_ERROR_CODE, &alen); - uint8_t class, number; - - if (ptr == NULL) - return STUN_MESSAGE_RETURN_NOT_FOUND; - if (alen < 4) - return STUN_MESSAGE_RETURN_INVALID; - - class = ptr[2] & 0x7; - number = ptr[3]; - if ((class < 3) || (class > 6) || (number > 99)) - return STUN_MESSAGE_RETURN_INVALID; - - *code = (class * 100) + number; - return STUN_MESSAGE_RETURN_SUCCESS; -} - -void * -stun_message_append (StunMessage *msg, StunAttribute type, size_t length) -{ - uint8_t *a; - uint16_t mlen = stun_message_length (msg); - - /* In MS-TURN, IDs of REALM and NONCE STUN attributes are swapped. */ - if (msg->agent && msg->agent->compatibility == STUN_COMPATIBILITY_OC2007) - { - if (type == STUN_ATTRIBUTE_NONCE) - type = STUN_ATTRIBUTE_REALM; - else if (type == STUN_ATTRIBUTE_REALM) - type = STUN_ATTRIBUTE_NONCE; - } - - if ((size_t)mlen + STUN_ATTRIBUTE_HEADER_LENGTH + length > msg->buffer_len) - return NULL; - - - a = msg->buffer + mlen; - a = stun_setw (a, type); - if (msg->agent && - (msg->agent->usage_flags & STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES)) - { - a = stun_setw (a, length); - } else { - /* NOTE: If cookie is not present, we need to force the attribute length - * to a multiple of 4 for compatibility with old RFC3489 */ - a = stun_setw (a, stun_message_has_cookie (msg) ? length : stun_align (length)); - - /* Add padding if needed. Avoid a zero-length memset() call. */ - if (stun_padding (length) > 0) { - memset (a + length, ' ', stun_padding (length)); - mlen += stun_padding (length); - } - } - - mlen += 4 + length; - - stun_setw (msg->buffer + STUN_MESSAGE_LENGTH_POS, mlen - STUN_MESSAGE_HEADER_LENGTH); - return a; -} - - -StunMessageReturn -stun_message_append_bytes (StunMessage *msg, StunAttribute type, - const void *data, size_t len) -{ - void *ptr = stun_message_append (msg, type, len); - if (ptr == NULL) - return STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE; - - if (len > 0) - memcpy (ptr, data, len); - - return STUN_MESSAGE_RETURN_SUCCESS; -} - - -StunMessageReturn -stun_message_append_flag (StunMessage *msg, StunAttribute type) -{ - return stun_message_append_bytes (msg, type, NULL, 0); -} - - -StunMessageReturn -stun_message_append32 (StunMessage *msg, StunAttribute type, - uint32_t value) -{ - value = htonl (value); - return stun_message_append_bytes (msg, type, &value, 4); -} - - -StunMessageReturn -stun_message_append64 (StunMessage *msg, StunAttribute type, - uint64_t value) -{ - uint32_t tab[2]; - tab[0] = htonl ((uint32_t)(value >> 32)); - tab[1] = htonl ((uint32_t)value); - return stun_message_append_bytes (msg, type, tab, 8); -} - - -StunMessageReturn -stun_message_append_string (StunMessage * msg, StunAttribute type, - const char *str) -{ - return stun_message_append_bytes (msg, type, str, strlen (str)); -} - -StunMessageReturn -stun_message_append_addr (StunMessage *msg, StunAttribute type, - const struct sockaddr *addr, socklen_t addrlen) -{ - const void *pa; - uint8_t *ptr; - uint16_t alen, port; - uint8_t family; - - union { - const struct sockaddr *addr; - const struct sockaddr_in *in; - const struct sockaddr_in6 *in6; - } sa; - - if ((size_t) addrlen < sizeof (struct sockaddr)) - return STUN_MESSAGE_RETURN_INVALID; - - sa.addr = addr; - - switch (addr->sa_family) - { - case AF_INET: - { - const struct sockaddr_in *ip4 = sa.in; - family = 1; - port = ip4->sin_port; - alen = 4; - pa = &ip4->sin_addr; - break; - } - - case AF_INET6: - { - const struct sockaddr_in6 *ip6 = sa.in6; - if ((size_t) addrlen < sizeof (*ip6)) - return STUN_MESSAGE_RETURN_INVALID; - - family = 2; - port = ip6->sin6_port; - alen = 16; - pa = &ip6->sin6_addr; - break; - } - - default: - return STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS; - } - - ptr = stun_message_append (msg, type, 4 + alen); - if (ptr == NULL) - return STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE; - - ptr[0] = 0; - ptr[1] = family; - memcpy (ptr + 2, &port, 2); - memcpy (ptr + 4, pa, alen); - return STUN_MESSAGE_RETURN_SUCCESS; -} - - -StunMessageReturn -stun_message_append_xor_addr (StunMessage *msg, StunAttribute type, - const struct sockaddr_storage *addr, socklen_t addrlen) -{ - StunMessageReturn val; - /* Must be big enough to hold any supported address: */ - struct sockaddr_storage tmpaddr; - - if ((size_t) addrlen > sizeof (tmpaddr)) - addrlen = sizeof (tmpaddr); - memcpy (&tmpaddr, addr, addrlen); - - val = stun_xor_address (msg, &tmpaddr, addrlen, - STUN_MAGIC_COOKIE); - if (val) - return val; - - return stun_message_append_addr (msg, type, (struct sockaddr *) &tmpaddr, - addrlen); -} - -StunMessageReturn -stun_message_append_xor_addr_full (StunMessage *msg, StunAttribute type, - const struct sockaddr_storage *addr, socklen_t addrlen, - uint32_t magic_cookie) -{ - StunMessageReturn val; - /* Must be big enough to hold any supported address: */ - struct sockaddr_storage tmpaddr; - - if ((size_t) addrlen > sizeof (tmpaddr)) - addrlen = sizeof (tmpaddr); - memcpy (&tmpaddr, addr, addrlen); - - val = stun_xor_address (msg, &tmpaddr, addrlen, magic_cookie); - if (val) - return val; - - return stun_message_append_addr (msg, type, (struct sockaddr *) &tmpaddr, - addrlen); -} - - - -StunMessageReturn -stun_message_append_error (StunMessage *msg, StunError code) -{ - const char *str = stun_strerror (code); - size_t len = strlen (str); - - uint8_t *ptr = stun_message_append (msg, STUN_ATTRIBUTE_ERROR_CODE, 4 + len); - if (ptr == NULL) - return STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE; - - memset (ptr, 0, 2); - ptr[2] = code / 100; - ptr[3] = code % 100; - memcpy (ptr + 4, str, len); - return STUN_MESSAGE_RETURN_SUCCESS; -} - -/* Fast validity check for a potential STUN packet. Examines the type and - * length, but none of the attributes. Designed to allow vectored I/O on all - * incoming packets, filtering packets for closer inspection as to whether - * they’re STUN packets. If they look like they might be, their buffers are - * compacted to allow a more thorough check. */ -ssize_t stun_message_validate_buffer_length_fast (StunInputVector *buffers, - int n_buffers, size_t total_length, bool has_padding) -{ - size_t mlen; - - if (total_length < 1 || n_buffers == 0 || buffers[0].buffer == NULL) - { - stun_debug ("STUN error: No data!"); - return STUN_MESSAGE_BUFFER_INVALID; - } - - if (buffers[0].buffer[0] >> 6) - { - return STUN_MESSAGE_BUFFER_INVALID; // RTP or other non-STUN packet - } - - if (total_length < STUN_MESSAGE_LENGTH_POS + STUN_MESSAGE_LENGTH_LEN) - { - stun_debug ("STUN error: Incomplete STUN message header!"); - return STUN_MESSAGE_BUFFER_INCOMPLETE; - } - - if (buffers[0].size >= STUN_MESSAGE_LENGTH_POS + STUN_MESSAGE_LENGTH_LEN) { - /* Fast path. */ - mlen = stun_getw (buffers[0].buffer + STUN_MESSAGE_LENGTH_POS); - } else { - /* Slow path. Tiny buffers abound. */ - size_t skip_remaining = STUN_MESSAGE_LENGTH_POS; - unsigned int i; - - /* Skip bytes. */ - for (i = 0; (n_buffers >= 0 && i < (unsigned int) n_buffers) || - (n_buffers < 0 && buffers[i].buffer != NULL); i++) { - if (buffers[i].size <= skip_remaining) - skip_remaining -= buffers[i].size; - else - break; - } - - /* Read bytes. May be split over two buffers. We’ve already checked that - * @total_length is long enough, so @n_buffers should be too. */ - if (buffers[i].size - skip_remaining > 1) { - mlen = stun_getw (buffers[i].buffer + skip_remaining); - } else { - mlen = (*(buffers[i].buffer + skip_remaining) << 8) | - (*(buffers[i + 1].buffer)); - } - } - - mlen += STUN_MESSAGE_HEADER_LENGTH; - - if (has_padding && stun_padding (mlen)) { - stun_debug ("STUN error: Invalid message length: %u!", (unsigned)mlen); - return STUN_MESSAGE_BUFFER_INVALID; // wrong padding - } - - if (total_length < mlen) { - stun_debug ("STUN error: Incomplete message: %u of %u bytes!", - (unsigned) total_length, (unsigned) mlen); - return STUN_MESSAGE_BUFFER_INCOMPLETE; // partial message - } - - return mlen; -} - -int stun_message_validate_buffer_length (const uint8_t *msg, size_t length, - bool has_padding) -{ - ssize_t fast_retval; - size_t mlen; - size_t len; - StunInputVector input_buffer = { msg, length }; - - /* Fast pre-check first. */ - fast_retval = stun_message_validate_buffer_length_fast (&input_buffer, 1, - length, has_padding); - if (fast_retval <= 0) - return fast_retval; - - mlen = fast_retval; - - /* Skip past the header (validated above). */ - msg += 20; - len = mlen - 20; - - /* from then on, we know we have the entire packet in buffer */ - while (len > 0) - { - size_t alen; - - if (len < 4) - { - stun_debug ("STUN error: Incomplete STUN attribute header of length " - "%u bytes!", (unsigned)len); - return STUN_MESSAGE_BUFFER_INVALID; - } - - alen = stun_getw (msg + STUN_ATTRIBUTE_TYPE_LEN); - if (has_padding) - alen = stun_align (alen); - - /* thanks to padding check, if (end > msg) then there is not only one - * but at least 4 bytes left */ - len -= 4; - - if (len < alen) - { - stun_debug ("STUN error: %u instead of %u bytes for attribute!", - (unsigned)len, (unsigned)alen); - return STUN_MESSAGE_BUFFER_INVALID; // no room for attribute value + padding - } - - len -= alen; - msg += 4 + alen; - } - - return mlen; -} - -void stun_message_id (const StunMessage *msg, StunTransactionId id) -{ - memcpy (id, msg->buffer + STUN_MESSAGE_TRANS_ID_POS, STUN_MESSAGE_TRANS_ID_LEN); -} - -StunMethod stun_message_get_method (const StunMessage *msg) -{ - uint16_t t = stun_getw (msg->buffer); - /* HACK HACK HACK - A google/msn data indication is 0x0115 which is contrary to the RFC 5389 - which states that 8th and 12th bits are for the class and that 0x01 is - for indications... - So 0x0115 is reported as a "connect error response", while it should be - a data indication, which message type should actually be 0x0017 - This should fix the issue, and it's considered safe since the "connect" - method doesn't exist anymore */ - if (t == 0x0115) - t = 0x0017; - return (StunMethod)(((t & 0x3e00) >> 2) | ((t & 0x00e0) >> 1) | - (t & 0x000f)); -} - - -StunClass stun_message_get_class (const StunMessage *msg) -{ - uint16_t t = stun_getw (msg->buffer); - /* HACK HACK HACK - A google/msn data indication is 0x0115 which is contrary to the RFC 5389 - which states that 8th and 12th bits are for the class and that 0x01 is - for indications... - So 0x0115 is reported as a "connect error response", while it should be - a data indication, which message type should actually be 0x0017 - This should fix the issue, and it's considered safe since the "connect" - method doesn't exist anymore */ - if (t == 0x0115) - t = 0x0017; - return (StunClass)(((t & 0x0100) >> 7) | ((t & 0x0010) >> 4)); -} - -bool stun_message_has_attribute (const StunMessage *msg, StunAttribute type) -{ - uint16_t dummy; - return stun_message_find (msg, type, &dummy) != NULL; -} - - -bool stun_optional (uint16_t t) -{ - return (t >> 15) == 1; -} - -const char *stun_strerror (StunError code) -{ - static const struct - { - StunError code; - char phrase[32]; - } tab[] = - { - { STUN_ERROR_TRY_ALTERNATE, "Try alternate server" }, - { STUN_ERROR_BAD_REQUEST, "Bad request" }, - { STUN_ERROR_UNAUTHORIZED, "Unauthorized" }, - { STUN_ERROR_UNKNOWN_ATTRIBUTE, "Unknown Attribute" }, - { STUN_ERROR_ALLOCATION_MISMATCH, "Allocation Mismatch" }, - { STUN_ERROR_STALE_NONCE, "Stale Nonce" }, - { STUN_ERROR_ACT_DST_ALREADY, "Active Destination Already Set" }, - { STUN_ERROR_UNSUPPORTED_FAMILY, "Address Family not Supported" }, - { STUN_ERROR_UNSUPPORTED_TRANSPORT, "Unsupported Transport Protocol" }, - { STUN_ERROR_INVALID_IP, "Invalid IP Address" }, - { STUN_ERROR_INVALID_PORT, "Invalid Port" }, - { STUN_ERROR_OP_TCP_ONLY, "Operation for TCP Only" }, - { STUN_ERROR_CONN_ALREADY, "Connection Already Exists" }, - { STUN_ERROR_ALLOCATION_QUOTA_REACHED, "Allocation Quota Reached" }, - { STUN_ERROR_ROLE_CONFLICT, "Role conflict" }, - { STUN_ERROR_SERVER_ERROR, "Server Error" }, - { STUN_ERROR_SERVER_CAPACITY, "Insufficient Capacity" }, - { STUN_ERROR_INSUFFICIENT_CAPACITY, "Insufficient Capacity" }, - }; - const char *str = "Unknown error"; - size_t i; - - for (i = 0; i < (sizeof (tab) / sizeof (tab[0])); i++) - { - if (tab[i].code == code) - { - str = tab[i].phrase; - break; - } - } - - /* Maximum allowed error message length */ - // assert (strlen (str) < 128); - return str; -} diff --git a/stun/stunmessage.h b/stun/stunmessage.h deleted file mode 100644 index 0ac9977..0000000 --- a/stun/stunmessage.h +++ /dev/null @@ -1,1017 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef _STUN_MESSAGE_H -#define _STUN_MESSAGE_H - - -/** - * SECTION:stunmessage - * @short_description: STUN messages parsing and formatting functions - * @include: stun/stunmessage.h - * @see_also: #StunAgent - * @stability: Stable - * - * The STUN Messages API allows you to create STUN messages easily as well as to - * parse existing messages. - * - */ - - -#ifdef _WIN32 -#include "win32_common.h" -#else -#include -#include -#endif - -#include - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#endif - -#include "constants.h" - -typedef struct _StunMessage StunMessage; - -/** - * StunClass: - * @STUN_REQUEST: A STUN Request message - * @STUN_INDICATION: A STUN indication message - * @STUN_RESPONSE: A STUN Response message - * @STUN_ERROR: A STUN Error message - * - * This enum is used to represent the class of - * a STUN message, as defined in RFC5389 - */ - -/* Message classes */ -typedef enum -{ - STUN_REQUEST=0, - STUN_INDICATION=1, - STUN_RESPONSE=2, - STUN_ERROR=3 -} StunClass; - - -/** - * StunMethod: - * @STUN_BINDING: The Binding method as defined by the RFC5389 - * @STUN_SHARED_SECRET: The Shared-Secret method as defined by the RFC3489 - * @STUN_ALLOCATE: The Allocate method as defined by the TURN draft 12 - * @STUN_SET_ACTIVE_DST: The Set-Active-Destination method as defined by - * the TURN draft 4 - * @STUN_REFRESH: The Refresh method as defined by the TURN draft 12 - * @STUN_SEND: The Send method as defined by the TURN draft 00 - * @STUN_CONNECT: The Connect method as defined by the TURN draft 4 - * @STUN_OLD_SET_ACTIVE_DST: The older Set-Active-Destination method as - * defined by the TURN draft 0 - * @STUN_IND_SEND: The Send method used in indication messages as defined - * by the TURN draft 12 - * @STUN_IND_DATA: The Data method used in indication messages as defined - * by the TURN draft 12 - * @STUN_IND_CONNECT_STATUS: The Connect-Status method used in indication - * messages as defined by the TURN draft 4 - * @STUN_CREATEPERMISSION: The CreatePermission method as defined by - * the TURN draft 12 - * @STUN_CHANNELBIND: The ChannelBind method as defined by the TURN draft 12 - * - * This enum is used to represent the method of - * a STUN message, as defined by various RFCs - */ -/* Message methods */ -typedef enum -{ - STUN_BINDING=0x001, /* RFC5389 */ - STUN_SHARED_SECRET=0x002, /* old RFC3489 */ - STUN_ALLOCATE=0x003, /* TURN-12 */ - STUN_SET_ACTIVE_DST=0x004, /* TURN-04 */ - STUN_REFRESH=0x004, /* TURN-12 */ - STUN_SEND=0x004, /* TURN-00 */ - STUN_CONNECT=0x005, /* TURN-04 */ - STUN_OLD_SET_ACTIVE_DST=0x006, /* TURN-00 */ - STUN_IND_SEND=0x006, /* TURN-12 */ - STUN_IND_DATA=0x007, /* TURN-12 */ - STUN_IND_CONNECT_STATUS=0x008, /* TURN-04 */ - STUN_CREATEPERMISSION= 0x008, /* TURN-12 */ - STUN_CHANNELBIND= 0x009 /* TURN-12 */ -} StunMethod; - -/** - * StunAttribute: - * @STUN_ATTRIBUTE_MAPPED_ADDRESS: The MAPPED-ADDRESS attribute as defined - * by RFC5389 - * @STUN_ATTRIBUTE_RESPONSE_ADDRESS: The RESPONSE-ADDRESS attribute as defined - * by RFC3489 - * @STUN_ATTRIBUTE_CHANGE_REQUEST: The CHANGE-REQUEST attribute as defined by - * RFC3489 - * @STUN_ATTRIBUTE_SOURCE_ADDRESS: The SOURCE-ADDRESS attribute as defined by - * RFC3489 - * @STUN_ATTRIBUTE_CHANGED_ADDRESS: The CHANGED-ADDRESS attribute as defined - * by RFC3489 - * @STUN_ATTRIBUTE_USERNAME: The USERNAME attribute as defined by RFC5389 - * @STUN_ATTRIBUTE_PASSWORD: The PASSWORD attribute as defined by RFC3489 - * @STUN_ATTRIBUTE_MESSAGE_INTEGRITY: The MESSAGE-INTEGRITY attribute as defined - * by RFC5389 - * @STUN_ATTRIBUTE_ERROR_CODE: The ERROR-CODE attribute as defined by RFC5389 - * @STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES: The UNKNOWN-ATTRIBUTES attribute as - * defined by RFC5389 - * @STUN_ATTRIBUTE_REFLECTED_FROM: The REFLECTED-FROM attribute as defined - * by RFC3489 - * @STUN_ATTRIBUTE_CHANNEL_NUMBER: The CHANNEL-NUMBER attribute as defined by - * TURN draft 09 and 12 - * @STUN_ATTRIBUTE_LIFETIME: The LIFETIME attribute as defined by TURN - * draft 04, 09 and 12 - * @STUN_ATTRIBUTE_MS_ALTERNATE_SERVER: The ALTERNATE-SERVER attribute as - * defined by [MS-TURN] - * @STUN_ATTRIBUTE_MAGIC_COOKIE: The MAGIC-COOKIE attribute as defined by - * the rosenberg-midcom TURN draft 08 - * @STUN_ATTRIBUTE_BANDWIDTH: The BANDWIDTH attribute as defined by TURN draft 04 - * @STUN_ATTRIBUTE_DESTINATION_ADDRESS: The DESTINATION-ADDRESS attribute as - * defined by the rosenberg-midcom TURN draft 08 - * @STUN_ATTRIBUTE_REMOTE_ADDRESS: The REMOTE-ADDRESS attribute as defined by - * TURN draft 04 - * @STUN_ATTRIBUTE_PEER_ADDRESS: The PEER-ADDRESS attribute as defined by - * TURN draft 09 - * @STUN_ATTRIBUTE_XOR_PEER_ADDRESS: The XOR-PEER-ADDRESS attribute as defined - * by TURN draft 12 - * @STUN_ATTRIBUTE_DATA: The DATA attribute as defined by TURN draft 04, - * 09 and 12 - * @STUN_ATTRIBUTE_REALM: The REALM attribute as defined by RFC5389 - * @STUN_ATTRIBUTE_NONCE: The NONCE attribute as defined by RFC5389 - * @STUN_ATTRIBUTE_RELAY_ADDRESS: The RELAY-ADDRESS attribute as defined by - * TURN draft 04 - * @STUN_ATTRIBUTE_RELAYED_ADDRESS: The RELAYED-ADDRESS attribute as defined by - * TURN draft 09 - * @STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS: The XOR-RELAYED-ADDRESS attribute as - * defined by TURN draft 12 - * @STUN_ATTRIBUTE_REQUESTED_ADDRESS_TYPE: The REQUESTED-ADDRESS-TYPE attribute - * as defined by TURN-IPV6 draft 05 - * @STUN_ATTRIBUTE_REQUESTED_PORT_PROPS: The REQUESTED-PORT-PROPS attribute - * as defined by TURN draft 04 - * @STUN_ATTRIBUTE_REQUESTED_PROPS: The REQUESTED-PROPS attribute as defined - * by TURN draft 09 - * @STUN_ATTRIBUTE_EVEN_PORT: The EVEN-PORT attribute as defined by TURN draft 12 - * @STUN_ATTRIBUTE_REQUESTED_TRANSPORT: The REQUESTED-TRANSPORT attribute as - * defined by TURN draft 12 - * @STUN_ATTRIBUTE_DONT_FRAGMENT: The DONT-FRAGMENT attribute as defined - * by TURN draft 12 - * @STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS: The XOR-MAPPED-ADDRESS attribute as - * defined by RFC5389 - * @STUN_ATTRIBUTE_TIMER_VAL: The TIMER-VAL attribute as defined by TURN draft 04 - * @STUN_ATTRIBUTE_REQUESTED_IP: The REQUESTED-IP attribute as defined by - * TURN draft 04 - * @STUN_ATTRIBUTE_RESERVATION_TOKEN: The RESERVATION-TOKEN attribute as defined - * by TURN draft 09 and 12 - * @STUN_ATTRIBUTE_CONNECT_STAT: The CONNECT-STAT attribute as defined by TURN - * draft 04 - * @STUN_ATTRIBUTE_PRIORITY: The PRIORITY attribute as defined by ICE draft 19 - * @STUN_ATTRIBUTE_USE_CANDIDATE: The USE-CANDIDATE attribute as defined by - * ICE draft 19 - * @STUN_ATTRIBUTE_OPTIONS: The OPTIONS optional attribute as defined by - * libjingle - * @STUN_ATTRIBUTE_MS_VERSION: The MS-VERSION optional attribute as defined - * by [MS-TURN] - * @STUN_ATTRIBUTE_MS_XOR_MAPPED_ADDRESS: The XOR-MAPPED-ADDRESS optional - * attribute as defined by [MS-TURN] - * @STUN_ATTRIBUTE_SOFTWARE: The SOFTWARE optional attribute as defined by RFC5389 - * @STUN_ATTRIBUTE_ALTERNATE_SERVER: The ALTERNATE-SERVER optional attribute as - * defined by RFC5389 - * @STUN_ATTRIBUTE_FINGERPRINT: The FINGERPRINT optional attribute as defined - * by RFC5389 - * @STUN_ATTRIBUTE_ICE_CONTROLLED: The ICE-CONTROLLED optional attribute as - * defined by ICE draft 19 - * @STUN_ATTRIBUTE_ICE_CONTROLLING: The ICE-CONTROLLING optional attribute as - * defined by ICE draft 19 - * @STUN_ATTRIBUTE_MS_SEQUENCE_NUMBER: The MS-SEQUENCE NUMBER optional attribute - * as defined by [MS-TURN] - * @STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER: The CANDIDATE-IDENTIFIER optional - * attribute as defined by [MS-ICE2] - * @STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION: The IMPLEMENTATION-VERSION - * optional attribute as defined by [MS-ICE2] - * @STUN_ATTRIBUTE_NOMINATION: The NOMINATION attribute as defined by - * draft-thatcher-ice-renomination-00 and deployed in Google Chrome - * - * Known STUN attribute types as defined by various RFCs and drafts - */ -/* Should be in sync with stun_is_unknown() */ -typedef enum -{ - /* Mandatory attributes */ - /* 0x0000 */ /* reserved */ - STUN_ATTRIBUTE_MAPPED_ADDRESS=0x0001, /* RFC5389 */ - STUN_ATTRIBUTE_RESPONSE_ADDRESS=0x0002, /* old RFC3489 */ - STUN_ATTRIBUTE_CHANGE_REQUEST=0x0003, /* old RFC3489 */ - STUN_ATTRIBUTE_SOURCE_ADDRESS=0x0004, /* old RFC3489 */ - STUN_ATTRIBUTE_CHANGED_ADDRESS=0x0005, /* old RFC3489 */ - STUN_ATTRIBUTE_USERNAME=0x0006, /* RFC5389 */ - STUN_ATTRIBUTE_PASSWORD=0x0007, /* old RFC3489 */ - STUN_ATTRIBUTE_MESSAGE_INTEGRITY=0x0008, /* RFC5389 */ - STUN_ATTRIBUTE_ERROR_CODE=0x0009, /* RFC5389 */ - STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES=0x000A, /* RFC5389 */ - STUN_ATTRIBUTE_REFLECTED_FROM=0x000B, /* old RFC3489 */ - STUN_ATTRIBUTE_CHANNEL_NUMBER=0x000C, /* TURN-12 */ - STUN_ATTRIBUTE_LIFETIME=0x000D, /* TURN-12 */ - /* MS_ALTERNATE_SERVER is only used by Microsoft's dialect, probably should - * not to be placed in STUN_ALL_KNOWN_ATTRIBUTES */ - STUN_ATTRIBUTE_MS_ALTERNATE_SERVER=0x000E, /* MS-TURN */ - STUN_ATTRIBUTE_MAGIC_COOKIE=0x000F, /* midcom-TURN 08 */ - STUN_ATTRIBUTE_BANDWIDTH=0x0010, /* TURN-04 */ - STUN_ATTRIBUTE_DESTINATION_ADDRESS=0x0011, /* midcom-TURN 08 */ - STUN_ATTRIBUTE_REMOTE_ADDRESS=0x0012, /* TURN-04 */ - STUN_ATTRIBUTE_PEER_ADDRESS=0x0012, /* TURN-09 */ - STUN_ATTRIBUTE_XOR_PEER_ADDRESS=0x0012, /* TURN-12 */ - STUN_ATTRIBUTE_DATA=0x0013, /* TURN-12 */ - STUN_ATTRIBUTE_REALM=0x0014, /* RFC5389 */ - STUN_ATTRIBUTE_NONCE=0x0015, /* RFC5389 */ - STUN_ATTRIBUTE_RELAY_ADDRESS=0x0016, /* TURN-04 */ - STUN_ATTRIBUTE_RELAYED_ADDRESS=0x0016, /* TURN-09 */ - STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS=0x0016, /* TURN-12 */ - STUN_ATTRIBUTE_REQUESTED_ADDRESS_TYPE=0x0017, /* TURN-IPv6-05 */ - STUN_ATTRIBUTE_REQUESTED_PORT_PROPS=0x0018, /* TURN-04 */ - STUN_ATTRIBUTE_REQUESTED_PROPS=0x0018, /* TURN-09 */ - STUN_ATTRIBUTE_EVEN_PORT=0x0018, /* TURN-12 */ - STUN_ATTRIBUTE_REQUESTED_TRANSPORT=0x0019, /* TURN-12 */ - STUN_ATTRIBUTE_DONT_FRAGMENT=0x001A, /* TURN-12 */ - /* 0x001B */ /* reserved */ - /* 0x001C */ /* reserved */ - /* 0x001D */ /* reserved */ - /* 0x001E */ /* reserved */ - /* 0x001F */ /* reserved */ - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS=0x0020, /* RFC5389 */ - STUN_ATTRIBUTE_TIMER_VAL=0x0021, /* TURN-04 */ - STUN_ATTRIBUTE_REQUESTED_IP=0x0022, /* TURN-04 */ - STUN_ATTRIBUTE_RESERVATION_TOKEN=0x0022, /* TURN-09 */ - STUN_ATTRIBUTE_CONNECT_STAT=0x0023, /* TURN-04 */ - STUN_ATTRIBUTE_PRIORITY=0x0024, /* ICE-19 */ - STUN_ATTRIBUTE_USE_CANDIDATE=0x0025, /* ICE-19 */ - /* 0x0026 */ /* reserved */ - /* 0x0027 */ /* reserved */ - /* 0x0028 */ /* reserved */ - /* 0x0029 */ /* reserved */ - /* 0x002A-0x7fff */ /* reserved */ - - /* Optional attributes */ - /* 0x8000-0x8021 */ /* reserved */ - STUN_ATTRIBUTE_OPTIONS=0x8001, /* libjingle */ - STUN_ATTRIBUTE_MS_VERSION=0x8008, /* MS-TURN */ - STUN_ATTRIBUTE_MS_XOR_MAPPED_ADDRESS=0x8020, /* MS-TURN */ - STUN_ATTRIBUTE_SOFTWARE=0x8022, /* RFC5389 */ - STUN_ATTRIBUTE_ALTERNATE_SERVER=0x8023, /* RFC5389 */ - /* 0x8024 */ /* reserved */ - /* 0x8025 */ /* reserved */ - /* 0x8026 */ /* reserved */ - /* 0x8027 */ /* reserved */ - STUN_ATTRIBUTE_FINGERPRINT=0x8028, /* RFC5389 */ - STUN_ATTRIBUTE_ICE_CONTROLLED=0x8029, /* ICE-19 */ - STUN_ATTRIBUTE_ICE_CONTROLLING=0x802A, /* ICE-19 */ - /* 0x802B-0x804F */ /* reserved */ - STUN_ATTRIBUTE_MS_SEQUENCE_NUMBER=0x8050, /* MS-TURN */ - /* 0x8051-0x8053 */ /* reserved */ - STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER=0x8054, /* MS-ICE2 */ - /* 0x8055-0x806F */ /* reserved */ - STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION=0x8070, /* MS-ICE2 */ - /* 0x8071-0xC000 */ /* reserved */ - STUN_ATTRIBUTE_NOMINATION=0xC001 /* https://tools.ietf.org/html/draft-thatcher-ice-renomination-00 */ - /* 0xC002-0xFFFF */ /* reserved */ -} StunAttribute; - - -/** - * STUN_ALL_KNOWN_ATTRIBUTES: - * - * An array containing all the currently known and defined mandatory attributes - * from StunAttribute - */ -/* Should be in sync with StunAttribute */ -static const uint16_t STUN_ALL_KNOWN_ATTRIBUTES[] = - { - STUN_ATTRIBUTE_MAPPED_ADDRESS, - STUN_ATTRIBUTE_RESPONSE_ADDRESS, - STUN_ATTRIBUTE_CHANGE_REQUEST, - STUN_ATTRIBUTE_SOURCE_ADDRESS, - STUN_ATTRIBUTE_CHANGED_ADDRESS, - STUN_ATTRIBUTE_USERNAME, - STUN_ATTRIBUTE_PASSWORD, - STUN_ATTRIBUTE_MESSAGE_INTEGRITY, - STUN_ATTRIBUTE_ERROR_CODE, - STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES, - STUN_ATTRIBUTE_REFLECTED_FROM, - STUN_ATTRIBUTE_CHANNEL_NUMBER, - STUN_ATTRIBUTE_LIFETIME, - STUN_ATTRIBUTE_MAGIC_COOKIE, - STUN_ATTRIBUTE_BANDWIDTH, - STUN_ATTRIBUTE_DESTINATION_ADDRESS, - STUN_ATTRIBUTE_REMOTE_ADDRESS, - STUN_ATTRIBUTE_PEER_ADDRESS, - STUN_ATTRIBUTE_XOR_PEER_ADDRESS, - STUN_ATTRIBUTE_DATA, - STUN_ATTRIBUTE_REALM, - STUN_ATTRIBUTE_NONCE, - STUN_ATTRIBUTE_RELAY_ADDRESS, - STUN_ATTRIBUTE_RELAYED_ADDRESS, - STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, - STUN_ATTRIBUTE_REQUESTED_ADDRESS_TYPE, - STUN_ATTRIBUTE_REQUESTED_PORT_PROPS, - STUN_ATTRIBUTE_REQUESTED_PROPS, - STUN_ATTRIBUTE_EVEN_PORT, - STUN_ATTRIBUTE_REQUESTED_TRANSPORT, - STUN_ATTRIBUTE_DONT_FRAGMENT, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - STUN_ATTRIBUTE_TIMER_VAL, - STUN_ATTRIBUTE_REQUESTED_IP, - STUN_ATTRIBUTE_RESERVATION_TOKEN, - STUN_ATTRIBUTE_CONNECT_STAT, - STUN_ATTRIBUTE_PRIORITY, - STUN_ATTRIBUTE_USE_CANDIDATE, - 0 - }; - -/** - * STUN_MSOC_KNOWN_ATTRIBUTES: - * - * An array containing all the currently known mandatory attributes used by - * Microsoft Office Communicator as defined in [MS-TURN] - */ -static const uint16_t STUN_MSOC_KNOWN_ATTRIBUTES[] = - { - STUN_ATTRIBUTE_MAPPED_ADDRESS, - STUN_ATTRIBUTE_USERNAME, - STUN_ATTRIBUTE_MESSAGE_INTEGRITY, - STUN_ATTRIBUTE_ERROR_CODE, - STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES, - STUN_ATTRIBUTE_LIFETIME, - STUN_ATTRIBUTE_MS_ALTERNATE_SERVER, - STUN_ATTRIBUTE_MAGIC_COOKIE, - STUN_ATTRIBUTE_BANDWIDTH, - STUN_ATTRIBUTE_DESTINATION_ADDRESS, - STUN_ATTRIBUTE_REMOTE_ADDRESS, - STUN_ATTRIBUTE_DATA, - /* REALM and NONCE have swapped hexadecimal IDs in [MS-TURN]. Libnice users - * or developers can still use these enumeration values in their original - * meanings from StunAttribute anywhere in the code, as stun_message_find() - * and stun_message_append() will choose correct ID in MSOC compatibility - * modes. */ - STUN_ATTRIBUTE_NONCE, - STUN_ATTRIBUTE_REALM, - 0 - }; - -/** - * StunTransactionId: - * - * A type that holds a STUN transaction id. - */ -typedef uint8_t StunTransactionId[STUN_MESSAGE_TRANS_ID_LEN]; - - -/** - * StunError: - * @STUN_ERROR_TRY_ALTERNATE: The ERROR-CODE value for the - * "Try Alternate" error as defined in RFC5389 - * @STUN_ERROR_BAD_REQUEST: The ERROR-CODE value for the - * "Bad Request" error as defined in RFC5389 - * @STUN_ERROR_UNAUTHORIZED: The ERROR-CODE value for the - * "Unauthorized" error as defined in RFC5389 - * @STUN_ERROR_UNKNOWN_ATTRIBUTE: The ERROR-CODE value for the - * "Unknown Attribute" error as defined in RFC5389 - * @STUN_ERROR_ALLOCATION_MISMATCH:The ERROR-CODE value for the - * "Allocation Mismatch" error as defined in TURN draft 12. - * Equivalent to the "No Binding" error defined in TURN draft 04. - * @STUN_ERROR_STALE_NONCE: The ERROR-CODE value for the - * "Stale Nonce" error as defined in RFC5389 - * @STUN_ERROR_ACT_DST_ALREADY: The ERROR-CODE value for the - * "Active Destination Already Set" error as defined in TURN draft 04. - * @STUN_ERROR_UNSUPPORTED_FAMILY: The ERROR-CODE value for the - * "Address Family not Supported" error as defined in TURN IPV6 Draft 05. - * @STUN_ERROR_WRONG_CREDENTIALS: The ERROR-CODE value for the - * "Wrong Credentials" error as defined in TURN Draft 12. - * @STUN_ERROR_UNSUPPORTED_TRANSPORT:he ERROR-CODE value for the - * "Unsupported Transport Protocol" error as defined in TURN Draft 12. - * @STUN_ERROR_INVALID_IP: The ERROR-CODE value for the - * "Invalid IP Address" error as defined in TURN draft 04. - * @STUN_ERROR_INVALID_PORT: The ERROR-CODE value for the - * "Invalid Port" error as defined in TURN draft 04. - * @STUN_ERROR_OP_TCP_ONLY: The ERROR-CODE value for the - * "Operation for TCP Only" error as defined in TURN draft 04. - * @STUN_ERROR_CONN_ALREADY: The ERROR-CODE value for the - * "Connection Already Exists" error as defined in TURN draft 04. - * @STUN_ERROR_ALLOCATION_QUOTA_REACHED: The ERROR-CODE value for the - * "Allocation Quota Reached" error as defined in TURN draft 12. - * @STUN_ERROR_ROLE_CONFLICT:The ERROR-CODE value for the - * "Role Conflict" error as defined in ICE draft 19. - * @STUN_ERROR_SERVER_ERROR: The ERROR-CODE value for the - * "Server Error" error as defined in RFC5389 - * @STUN_ERROR_SERVER_CAPACITY: The ERROR-CODE value for the - * "Insufficient Capacity" error as defined in TURN draft 04. - * @STUN_ERROR_INSUFFICIENT_CAPACITY: The ERROR-CODE value for the - * "Insufficient Capacity" error as defined in TURN draft 12. - * @STUN_ERROR_MAX: The maximum possible ERROR-CODE value as defined by RFC 5389. - * - * STUN error codes as defined by various RFCs and drafts - */ -/* Should be in sync with stun_strerror() */ -typedef enum -{ - STUN_ERROR_TRY_ALTERNATE=300, /* RFC5389 */ - STUN_ERROR_BAD_REQUEST=400, /* RFC5389 */ - STUN_ERROR_UNAUTHORIZED=401, /* RFC5389 */ - STUN_ERROR_UNKNOWN_ATTRIBUTE=420, /* RFC5389 */ - STUN_ERROR_ALLOCATION_MISMATCH=437, /* TURN-12 */ - STUN_ERROR_STALE_NONCE=438, /* RFC5389 */ - STUN_ERROR_ACT_DST_ALREADY=439, /* TURN-04 */ - STUN_ERROR_UNSUPPORTED_FAMILY=440, /* TURN-IPv6-05 */ - STUN_ERROR_WRONG_CREDENTIALS=441, /* TURN-12 */ - STUN_ERROR_UNSUPPORTED_TRANSPORT=442, /* TURN-12 */ - STUN_ERROR_INVALID_IP=443, /* TURN-04 */ - STUN_ERROR_INVALID_PORT=444, /* TURN-04 */ - STUN_ERROR_OP_TCP_ONLY=445, /* TURN-04 */ - STUN_ERROR_CONN_ALREADY=446, /* TURN-04 */ - STUN_ERROR_ALLOCATION_QUOTA_REACHED=486, /* TURN-12 */ - STUN_ERROR_ROLE_CONFLICT=487, /* ICE-19 */ - STUN_ERROR_SERVER_ERROR=500, /* RFC5389 */ - STUN_ERROR_SERVER_CAPACITY=507, /* TURN-04 */ - STUN_ERROR_INSUFFICIENT_CAPACITY=508, /* TURN-12 */ - STUN_ERROR_MAX=699 -} StunError; - - -/** - * StunMessageReturn: - * @STUN_MESSAGE_RETURN_SUCCESS: The operation was successful - * @STUN_MESSAGE_RETURN_NOT_FOUND: The attribute was not found - * @STUN_MESSAGE_RETURN_INVALID: The argument or data is invalid - * @STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE: There is not enough space in the - * message to append data to it, or not enough in an argument to fill it with - * the data requested. - * @STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS: The address in the arguments or in - * the STUN message is not supported. - * - * The return value of most stun_message_* functions. - * This enum will report on whether an operation was successful or not - * and what error occured if any. - */ -typedef enum -{ - STUN_MESSAGE_RETURN_SUCCESS, - STUN_MESSAGE_RETURN_NOT_FOUND, - STUN_MESSAGE_RETURN_INVALID, - STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE, - STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS -} StunMessageReturn; - -#include "stunagent.h" - -/** - * STUN_MAX_MESSAGE_SIZE: - * - * The Maximum size of a STUN message - */ -#define STUN_MAX_MESSAGE_SIZE 65552 - -/** - * StunMessage: - * @agent: The agent that created or validated this message - * @buffer: The buffer containing the STUN message - * @buffer_len: The length of the buffer (not the size of the message) - * @key: The short term credentials key to use for authentication validation - * or that was used to finalize this message - * @key_len: The length of the associated key - * @long_term_key: The long term credential key to use for authentication - * validation or that was used to finalize this message - * @long_term_valid: Whether or not the #long_term_key variable contains valid - * data - * - * This structure represents a STUN message - */ -struct _StunMessage { - StunAgent *agent; - uint8_t *buffer; - size_t buffer_len; - uint8_t *key; - size_t key_len; - uint8_t long_term_key[16]; - bool long_term_valid; -}; - -/** - * stun_message_init: - * @msg: The #StunMessage to initialize - * @c: STUN message class (host byte order) - * @m: STUN message method (host byte order) - * @id: 16-bytes transaction ID - * - * Initializes a STUN message buffer, with no attributes. - * Returns: %TRUE if the initialization was successful - */ -bool stun_message_init (StunMessage *msg, StunClass c, StunMethod m, - const StunTransactionId id); - -/** - * stun_message_length: - * @msg: The #StunMessage - * - * Get the length of the message (including the header) - * - * Returns: The length of the message - */ -uint16_t stun_message_length (const StunMessage *msg); - -/** - * stun_message_find: - * @msg: The #StunMessage - * @type: The #StunAttribute to find - * @palen: A pointer to store the length of the attribute - * - * Finds an attribute in a STUN message and fetches its content - * - * Returns: A pointer to the start of the attribute payload if found, - * otherwise NULL. - */ -const void * stun_message_find (const StunMessage * msg, StunAttribute type, - uint16_t *palen); - - -/** - * stun_message_find_flag: - * @msg: The #StunMessage - * @type: The #StunAttribute to find - * - * Looks for a flag attribute within a valid STUN message. - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute's size is not zero. - */ -StunMessageReturn stun_message_find_flag (const StunMessage *msg, - StunAttribute type); - -/** - * stun_message_find32: - * @msg: The #StunMessage - * @type: The #StunAttribute to find - * @pval: A pointer where to store the value (host byte order) - * - * Extracts a 32-bits attribute from a STUN message. - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute's size is not - * 4 bytes. - */ -StunMessageReturn stun_message_find32 (const StunMessage *msg, - StunAttribute type, uint32_t *pval); - -/** - * stun_message_find64: - * @msg: The #StunMessage - * @type: The #StunAttribute to find - * @pval: A pointer where to store the value (host byte order) - * - * Extracts a 64-bits attribute from a STUN message. - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute's size is not - * 8 bytes. - */ -StunMessageReturn stun_message_find64 (const StunMessage *msg, - StunAttribute type, uint64_t *pval); - -/** - * stun_message_find_string: - * @msg: The #StunMessage - * @type: The #StunAttribute to find - * @buf: A pointer where to store the data - * @buflen: The length of the buffer - * - * Extracts an UTF-8 string from a valid STUN message. - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute is improperly - * encoded - * %STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE is return if the buffer size is too - * small to hold the string - * - - - The string will be nul-terminated. - - - * - */ -StunMessageReturn stun_message_find_string (const StunMessage *msg, - StunAttribute type, char *buf, size_t buflen); - -/** - * stun_message_find_addr: - * @msg: The #StunMessage - * @type: The #StunAttribute to find - * @addr: The #sockaddr to be filled - * @addrlen: The size of the @addr variable. Must be set to the size of the - * @addr socket address and will be set to the size of the extracted socket - * address. - * - * Extracts a network address attribute from a STUN message. - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute payload size is - * wrong or if the @addrlen is too small - * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. - */ -StunMessageReturn stun_message_find_addr (const StunMessage *msg, - StunAttribute type, struct sockaddr_storage *addr, socklen_t *addrlen); - -/** - * stun_message_find_xor_addr: - * @msg: The #StunMessage - * @type: The #StunAttribute to find - * @addr: The #sockaddr to be filled - * @addrlen: The size of the @addr variable. Must be set to the size of the - * @addr socket address and will be set to the size of the - * extracted socket address. - * - * Extracts an obfuscated network address attribute from a STUN message. - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute payload size is - * wrong or if the @addrlen is too small - * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. - */ -StunMessageReturn stun_message_find_xor_addr (const StunMessage *msg, - StunAttribute type, struct sockaddr_storage *addr, socklen_t *addrlen); - -/** - * stun_message_find_xor_addr_full: - * @msg: The #StunMessage - * @type: The #StunAttribute to find - * @addr: The #sockaddr to be filled - * @addrlen: The size of the @addr variable. Must be set to the size of the - * @addr socket address and will be set to the size of the - * extracted socket address. - * @magic_cookie: The magic cookie to use to XOR the address. - * - * Extracts an obfuscated network address attribute from a STUN message. - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute payload size is - * wrong or if the @addrlen is too small - * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. - */ -StunMessageReturn stun_message_find_xor_addr_full (const StunMessage *msg, - StunAttribute type, struct sockaddr_storage *addr, - socklen_t *addrlen, uint32_t magic_cookie); - - -/** - * stun_message_find_error: - * @msg: The #StunMessage - * @code: A pointer where to store the value - * - * Extract the error response code from a STUN message - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the value is invalid - */ -StunMessageReturn stun_message_find_error (const StunMessage *msg, int *code); - - -/** - * stun_message_append: - * @msg: The #StunMessage - * @type: The #StunAttribute to append - * @length: The length of the attribute - * - * Reserves room for appending an attribute to an unfinished STUN message. - * - * Returns: A pointer to an unitialized buffer of @length bytes to - * where the attribute payload must be written, or NULL if there is not - * enough room in the STUN message buffer. - */ -void *stun_message_append (StunMessage *msg, StunAttribute type, - size_t length); - -/** - * stun_message_append_bytes: - * @msg: The #StunMessage - * @type: The #StunAttribute to append - * @data: The data to append - * @len: The length of the attribute - * - * Appends a binary value to a STUN message - * - * Returns: A #StunMessageReturn value. - */ -StunMessageReturn stun_message_append_bytes (StunMessage *msg, - StunAttribute type, const void *data, size_t len); - -/** - * stun_message_append_flag: - * @msg: The #StunMessage - * @type: The #StunAttribute to append - * - * Appends an empty flag attribute to a STUN message - * - * Returns: A #StunMessageReturn value. - */ -StunMessageReturn stun_message_append_flag (StunMessage *msg, - StunAttribute type); - -/** - * stun_message_append32: - * @msg: The #StunMessage - * @type: The #StunAttribute to append - * @value: The value to append (host byte order) - * - * Appends a 32-bits value attribute to a STUN message - * - * Returns: A #StunMessageReturn value. - */ -StunMessageReturn stun_message_append32 (StunMessage *msg, - StunAttribute type, uint32_t value); - -/** - * stun_message_append64: - * @msg: The #StunMessage - * @type: The #StunAttribute to append - * @value: The value to append (host byte order) - * - * Appends a 64-bits value attribute to a STUN message - * - * Returns: A #StunMessageReturn value. - */ -StunMessageReturn stun_message_append64 (StunMessage *msg, - StunAttribute type, uint64_t value); - -/** - * stun_message_append_string: - * @msg: The #StunMessage - * @type: The #StunAttribute to append - * @str: The string to append - * - * Adds an attribute from a nul-terminated string to a STUN message - * - * Returns: A #StunMessageReturn value. - */ -StunMessageReturn stun_message_append_string (StunMessage *msg, - StunAttribute type, const char *str); - -/** - * stun_message_append_addr: - * @msg: The #StunMessage - * @type: The #StunAttribute to append - * @addr: The #sockaddr to be append - * @addrlen: The size of the @addr variable. - * - * Append a network address attribute to a STUN message - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the @addrlen is too small - * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. - */ -StunMessageReturn stun_message_append_addr (StunMessage * msg, - StunAttribute type, const struct sockaddr *addr, socklen_t addrlen); - -/** - * stun_message_append_xor_addr: - * @msg: The #StunMessage - * @type: The #StunAttribute to append - * @addr: The #sockaddr to be append - * @addrlen: The size of the @addr variable. - * - * Append an obfuscated network address attribute to a STUN message - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the @addrlen is too small - * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. - */ -StunMessageReturn stun_message_append_xor_addr (StunMessage * msg, - StunAttribute type, const struct sockaddr_storage *addr, socklen_t addrlen); - -/** - * stun_message_append_xor_addr_full: - * @msg: The #StunMessage - * @type: The #StunAttribute to append - * @addr: The #sockaddr to be append - * @addrlen: The size of the @addr variable. - * @magic_cookie: The magic cookie to use to XOR the address. - * - * Append an obfuscated network address attribute from a STUN message. - * - * Returns: A #StunMessageReturn value. - * %STUN_MESSAGE_RETURN_INVALID is returned if the @addrlen is too small - * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. - */ -StunMessageReturn stun_message_append_xor_addr_full (StunMessage * msg, - StunAttribute type, const struct sockaddr_storage *addr, socklen_t addrlen, - uint32_t magic_cookie); - -/** - * stun_message_append_error: - * @msg: The #StunMessage - * @code: The error code value - * - * Appends the ERROR-CODE attribute to the STUN message and fills it according - * to #code - * - * Returns: A #StunMessageReturn value. - */ -StunMessageReturn stun_message_append_error (StunMessage * msg, - StunError code); - -/** - * STUN_MESSAGE_BUFFER_INCOMPLETE: - * - * Convenience macro for stun_message_validate_buffer_length() meaning that the - * data to validate does not hold a complete STUN message - */ -#define STUN_MESSAGE_BUFFER_INCOMPLETE 0 - -/** - * STUN_MESSAGE_BUFFER_INVALID: - * - * Convenience macro for stun_message_validate_buffer_length() meaning that the - * data to validate is not a valid STUN message - */ -#define STUN_MESSAGE_BUFFER_INVALID -1 - - -/** - * stun_message_validate_buffer_length: - * @msg: The buffer to validate - * @length: The length of the buffer - * @has_padding: Set TRUE if attributes should be padded to multiple of 4 bytes - * - * This function will take a data buffer and will try to validate whether it is - * a STUN message or if it's not or if it's an incomplete STUN message and will - * provide us with the length of the STUN message. - * - * Returns: The length of the valid STUN message in the buffer. - * See also: #STUN_MESSAGE_BUFFER_INCOMPLETE - * See also: #STUN_MESSAGE_BUFFER_INVALID - */ -int stun_message_validate_buffer_length (const uint8_t *msg, size_t length, - bool has_padding); - -/** - * StunInputVector: - * @buffer: a buffer containing already-received binary data - * @size: length of @buffer, in bytes - * - * Container for a single buffer which also stores its length. This is designed - * for vectored I/O: typically an array of #StunInputVectors is passed to - * functions, providing multiple buffers which store logically contiguous - * received data. - * - * This is guaranteed to be layed out identically in memory to #GInputVector. - * - * Since: 0.1.5 - */ -typedef struct { - const uint8_t *buffer; - size_t size; -} StunInputVector; - -/** - * stun_message_validate_buffer_length_fast: - * @buffers: (array length=n_buffers) (in caller-allocated): array of contiguous - * #StunInputVectors containing already-received message data - * @n_buffers: number of entries in @buffers or if -1 , then buffers is - * terminated by a #StunInputVector with the buffer pointer being %NULL. - * @total_length: total number of valid bytes stored consecutively in @buffers - * @has_padding: %TRUE if attributes should be padded to 4-byte boundaries - * - * Quickly validate whether the message in the given @buffers is potentially a - * valid STUN message, an incomplete STUN message, or if it’s definitely not one - * at all. - * - * This is designed as a first-pass validation only, and does not check the - * message’s attributes for validity. If this function returns success, the - * buffers can be compacted and a more thorough validation can be performed - * using stun_message_validate_buffer_length(). If it fails, the buffers - * definitely do not contain a complete, valid STUN message. - * - * Returns: The length of the valid STUN message in the buffer, or zero or -1 on - * failure - * See also: #STUN_MESSAGE_BUFFER_INCOMPLETE - * See also: #STUN_MESSAGE_BUFFER_INVALID - * - * Since: 0.1.5 - */ -ssize_t stun_message_validate_buffer_length_fast (StunInputVector *buffers, - int n_buffers, size_t total_length, bool has_padding); - -/** - * stun_message_id: - * @msg: The #StunMessage - * @id: The #StunTransactionId to fill - * - * Retreive the STUN transaction id from a STUN message - */ -void stun_message_id (const StunMessage *msg, StunTransactionId id); - -/** - * stun_message_get_class: - * @msg: The #StunMessage - * - * Retreive the STUN class from a STUN message - * - * Returns: The #StunClass - */ -StunClass stun_message_get_class (const StunMessage *msg); - -/** - * stun_message_get_method: - * @msg: The #StunMessage - * - * Retreive the STUN method from a STUN message - * - * Returns: The #StunMethod - */ -StunMethod stun_message_get_method (const StunMessage *msg); - -/** - * stun_message_has_attribute: - * @msg: The #StunMessage - * @type: The #StunAttribute to look for - * - * Checks if an attribute is present within a STUN message. - * - * Returns: %TRUE if the attribute is found, %FALSE otherwise - */ -bool stun_message_has_attribute (const StunMessage *msg, StunAttribute type); - - -/* Defined in stun5389.c */ -/** - * stun_message_has_cookie: - * @msg: The #StunMessage - * - * Checks if the STUN message has a RFC5389 compatible cookie - * - * Returns: %TRUE if the cookie is present, %FALSE otherwise - */ -bool stun_message_has_cookie (const StunMessage *msg); - - -/** - * stun_optional: - * @t: An attribute type - * - * Helper function that checks whether a STUN attribute is a mandatory - * or an optional attribute - * - * Returns: %TRUE if the attribute is an optional one - */ -bool stun_optional (uint16_t t); - -/** - * stun_strerror: - * @code: host-byte order error code - * - * Transforms a STUN error-code into a human readable string - * - * Returns: A static pointer to a nul-terminated error message string. - */ -const char *stun_strerror (StunError code); - - -#endif /* _STUN_MESSAGE_H */ diff --git a/stun/tests/Makefile.am b/stun/tests/Makefile.am deleted file mode 100644 index c660ed6..0000000 --- a/stun/tests/Makefile.am +++ /dev/null @@ -1,30 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. - -include $(top_srcdir)/common.mk -AM_CPPFLAGS = -I$(top_srcdir) -AM_CFLAGS = -std=gnu99 -LDADD = $(top_builddir)/stun/libstun.la - -check_PROGRAMS = \ - test-parse \ - test-format \ - test-bind \ - test-conncheck \ - test-hmac - -if WINDOWS - AM_CFLAGS += -DWINVER=0x0501 # _WIN32_WINNT_WINXP - LDADD += -lws2_32 -endif - -dist_check_SCRIPTS = check-bind.sh - -TESTS = $(check_PROGRAMS) -#$(dist_check_SCRIPTS) - -EXTRA_DIST = meson.build diff --git a/stun/tests/check-bind.sh b/stun/tests/check-bind.sh deleted file mode 100755 index f1c9512..0000000 --- a/stun/tests/check-bind.sh +++ /dev/null @@ -1,57 +0,0 @@ -#! /bin/sh - -if test -n "${BUILT_WITH_MESON}"; then - STUNC=$1 - STUND=$2 -else - STUNC=../tools/stunbdc - STUND=../tools/stund -fi - -cleanup() { - rm -f stund?.pid stund?.fail stunc?.log -} - -trap cleanup EXIT - -set -xe - -# Dummy command line parsing tests -$STUNC -h -$STUNC -V -! $STUNC server port dummy - -# Timeout tests -! $STUNC -4 127.0.0.1 1 -! $STUNC -6 ::1 1 - -# Allocate a likely unused port number -PORT=$((32768+$$)) -if test $PORT -le 1024; then - PORT=$(($PORT+1024)) -fi - -echo "Using local UDP port number $PORT ..." - -# Start the STUN test daemon if needed -cleanup() - -for v in 4 6; do - (($SHELL -c "echo \$\$ > stund$v.pid ; exec $STUND -$v $PORT") || \ - touch stund$v.fail) & -done - -# Run the test client -$STUNC -4 127.0.0.1 $PORT > stunc4.log || test -f stund4.fail -$STUNC -6 ::1 $PORT > stunc6.log || test -f stund6.fail - -# Terminate the test daemon -for v in 4 6; do kill -INT $(cat stund$v.pid) || true; done -wait - -# Check client results -if test -f stund4.fail; then exit 77; fi -grep -e "^Mapped address: 127.0.0.1" stunc4.log || exit 4 - -if test -f stund6.fail; then exit 77; fi -grep -e "^Mapped address: ::1" stunc6.log || exit 6 diff --git a/stun/tests/meson.build b/stun/tests/meson.build deleted file mode 100644 index 6018073..0000000 --- a/stun/tests/meson.build +++ /dev/null @@ -1,18 +0,0 @@ -foreach t : ['parse', 'format', 'bind', 'conncheck', 'hmac'] - test_name = 'test-@0@'.format(t) - exe = executable(test_name, test_name + '.c', - include_directories: nice_incs, - dependencies: [syslibs, crypto_dep], - link_with: libstun) - test(test_name, exe) -endforeach - -# XXX: This test is broken and unused since 2007, ocrete knows about it -# If we enable it, we may want to put it in a separate suite that's only run on -# dist because it takes a long time to run since it tests stun timeouts. -if false and find_program('sh', required : false).found() - test('test-check-bind', find_program('check-bind.sh'), - timeout: 600, - env: 'BUILT_WITH_MESON=1', - args: [stunbdc_exe, stund_exe]) -endif diff --git a/stun/tests/test-bind.c b/stun/tests/test-bind.c deleted file mode 100644 index 7df9b3c..0000000 --- a/stun/tests/test-bind.c +++ /dev/null @@ -1,472 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include "stun/stunagent.h" -#include "stun/usages/bind.h" - -#include -#include -#include - -#ifdef _WIN32 -#include -#include - -#define MSG_DONTWAIT 0 - -#define alarm(...) -#define close closesocket -#else -#include -#include -#include -#include -#include -#endif - -#undef NDEBUG /* ensure assertions are built-in */ -#include - -#ifndef MSG_NOSIGNAL -#define MSG_NOSIGNAL 0 -#endif - -static int listen_dgram (void) -{ - struct addrinfo hints, *res; - const struct addrinfo *ptr; - int val = -1; - - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = SOCK_DGRAM; - - if (getaddrinfo (NULL, "0", &hints, &res)) - return -1; - - for (ptr = res; ptr != NULL; ptr = ptr->ai_next) - { - int fd = socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); - if (fd == -1) - continue; - - if (bind (fd, ptr->ai_addr, ptr->ai_addrlen)) - { - close (fd); - continue; - } - - val = fd; - break; - } - - freeaddrinfo (res); - return val; -} - - -/** Incorrect socket family test */ -static void bad_family (void) -{ - struct sockaddr addr; - struct sockaddr_storage dummy; - int val; - socklen_t dummylen = sizeof(dummy); - - memset (&addr, 0, sizeof (addr)); - addr.sa_family = AF_UNSPEC; -#ifdef HAVE_SA_LEN - addr.sa_len = sizeof (addr); -#endif - - val = stun_usage_bind_run (&addr, sizeof (addr), - &dummy, &dummylen); - assert (val != 0); -} - - -/** Too small socket address test */ -static void small_srv_addr (void) -{ - struct sockaddr addr; - struct sockaddr_storage dummy; - int val; - socklen_t dummylen = sizeof(dummy); - - memset (&addr, 0, sizeof (addr)); - addr.sa_family = AF_INET; -#ifdef HAVE_SA_LEN - addr.sa_len = sizeof (addr); -#endif - - val = stun_usage_bind_run (&addr, 1, - &dummy, &dummylen); - assert (val == STUN_USAGE_BIND_RETURN_ERROR); -} - - -/** Too big socket address test */ -static void big_srv_addr (void) -{ - uint8_t buf[sizeof (struct sockaddr_storage) + 16]; - struct sockaddr_storage dummy; - int val; - socklen_t dummylen = sizeof(dummy); - - - memset (buf, 0, sizeof (buf)); - val = stun_usage_bind_run ((struct sockaddr *)buf, sizeof (buf), - &dummy, &dummylen); - assert (val == STUN_USAGE_BIND_RETURN_ERROR); -} - - -#ifdef HAVE_POLL -/** Timeout test */ -static void timeout (void) -{ - struct sockaddr_storage srv, dummy; - socklen_t srvlen = sizeof (srv); - socklen_t dummylen = sizeof(dummy); - int val; - - /* Allocate a local UDP port, so we are 100% sure nobody responds there */ - int servfd = listen_dgram (); - assert (servfd != -1); - - val = getsockname (servfd, (struct sockaddr *)&srv, &srvlen); - assert (val == 0); - - val = stun_usage_bind_run ((struct sockaddr *)&srv, srvlen, - &dummy, &dummylen); - assert (val == STUN_USAGE_BIND_RETURN_TIMEOUT); - - close (servfd); -} -#endif - -/** Malformed responses test */ -static void bad_responses (void) -{ - struct sockaddr_storage addr; - socklen_t addrlen = sizeof (addr); - ssize_t val, len; - uint8_t buf[STUN_MAX_MESSAGE_SIZE]; - uint8_t req[STUN_MAX_MESSAGE_SIZE]; - size_t req_len; - StunAgent agent; - StunMessage msg; - StunMessage req_msg; - int servfd, fd; - - uint16_t known_attributes[] = { - STUN_ATTRIBUTE_MAPPED_ADDRESS, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - STUN_ATTRIBUTE_PRIORITY, - STUN_ATTRIBUTE_USERNAME, - STUN_ATTRIBUTE_MESSAGE_INTEGRITY, - STUN_ATTRIBUTE_ERROR_CODE, 0}; - - stun_agent_init (&agent, known_attributes, - STUN_COMPATIBILITY_RFC5389, 0); - - /* Allocate a local UDP port */ - servfd = listen_dgram (); - assert (servfd != -1); - - val = getsockname (servfd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - - fd = socket (addr.ss_family, SOCK_DGRAM, 0); - assert (fd != -1); - - req_len = stun_usage_bind_create (&agent, &req_msg, req, sizeof(req)); - assert (req_len > 0); - - val = sendto (fd, req, req_len, MSG_DONTWAIT | MSG_NOSIGNAL, - (struct sockaddr *)&addr, addrlen); - assert (val >= 0); - - /* Send to/receive from our client instance only */ - val = getsockname (fd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - - /* Send request instead of response */ - val = getsockname (servfd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - len = recvfrom (servfd, buf, 1000, MSG_DONTWAIT, NULL, 0); - assert (len >= 20); - - assert (stun_agent_validate (&agent, &msg, buf, len, NULL, NULL) - == STUN_VALIDATION_SUCCESS); - - val = stun_usage_bind_process (&msg, (struct sockaddr *) &addr, &addrlen, - (struct sockaddr *) &addr, &addrlen); - assert (val == STUN_USAGE_BIND_RETURN_INVALID); - - /* Send response with wrong request type */ - buf[0] |= 0x03; - buf[0] ^= 0x02; - - /* Send error response without ERROR-CODE */ - buf[1] |= 0x10; - val = stun_usage_bind_process (&msg, (struct sockaddr *) &addr, &addrlen, - (struct sockaddr *) &addr, &addrlen); - assert (val == STUN_USAGE_BIND_RETURN_INVALID); - - close (fd); - close (servfd); -} - -/** Various responses test */ -static void responses (void) -{ - struct sockaddr_storage addr; - socklen_t addrlen = sizeof (addr); - ssize_t val; - size_t len; - int servfd, fd; - uint8_t buf[STUN_MAX_MESSAGE_SIZE]; - uint8_t req[STUN_MAX_MESSAGE_SIZE]; - size_t req_len; - StunAgent agent; - StunMessage msg; - StunMessage req_msg; - - uint16_t known_attributes[] = { - STUN_ATTRIBUTE_MAPPED_ADDRESS, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - STUN_ATTRIBUTE_PRIORITY, - STUN_ATTRIBUTE_USERNAME, - STUN_ATTRIBUTE_MESSAGE_INTEGRITY, - STUN_ATTRIBUTE_ERROR_CODE, 0}; - - stun_agent_init (&agent, known_attributes, - STUN_COMPATIBILITY_RFC5389, 0); - - /* Allocate a local UDP port for server */ - servfd = listen_dgram (); - assert (servfd != -1); - - val = getsockname (servfd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - - /* Allocate a client socket and connect to server */ - fd = socket (addr.ss_family, SOCK_DGRAM, 0); - assert (fd != -1); - - /* Send error response */ - req_len = stun_usage_bind_create (&agent, &req_msg, req, sizeof(req)); - assert (req_len > 0); - - val = getsockname (servfd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - - val = sendto (fd, req, req_len, MSG_DONTWAIT | MSG_NOSIGNAL, - (struct sockaddr *)&addr, addrlen); - assert (val >= 0); - - val = recvfrom (servfd, buf, 1000, MSG_DONTWAIT, NULL, 0); - assert (val >= 0); - - assert (stun_agent_validate (&agent, &msg, buf, val, NULL, NULL) - == STUN_VALIDATION_SUCCESS); - - stun_agent_init_error (&agent, &msg, buf, sizeof (buf), - &msg, STUN_ERROR_SERVER_ERROR); - len = stun_agent_finish_message (&agent, &msg, NULL, 0); - assert (len > 0); - - val = getsockname (servfd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - - val = stun_usage_bind_process (&msg, (struct sockaddr *) &addr, &addrlen, - (struct sockaddr *) &addr, &addrlen); - assert (val == STUN_USAGE_BIND_RETURN_ERROR); - - /* Send response with a no mapped address at all */ - req_len = stun_usage_bind_create (&agent, &req_msg, req, sizeof(req)); - assert (req_len > 0); - - val = getsockname (servfd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - - val = sendto (fd, req, req_len, MSG_DONTWAIT | MSG_NOSIGNAL, - (struct sockaddr *)&addr, addrlen); - assert (val >= 0); - - val = recvfrom (servfd, buf, 1000, MSG_DONTWAIT, NULL, 0); - assert (val >= 0); - - assert (stun_agent_validate (&agent, &msg, buf, val, NULL, NULL) - == STUN_VALIDATION_SUCCESS); - - stun_agent_init_response (&agent, &msg, buf, sizeof (buf), &msg); - len = stun_agent_finish_message (&agent, &msg, NULL, 0); - assert (len > 0); - - assert (stun_agent_validate (&agent, &msg, buf, len, NULL, NULL) - == STUN_VALIDATION_SUCCESS); - - val = getsockname (servfd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - - val = stun_usage_bind_process (&msg, (struct sockaddr *) &addr, &addrlen, - (struct sockaddr *) &addr, &addrlen); - assert (val == STUN_USAGE_BIND_RETURN_ERROR); - - /* Send old-style response */ - req_len = stun_usage_bind_create (&agent, &req_msg, req, sizeof(req)); - assert (req_len > 0); - - val = getsockname (servfd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - - val = sendto (fd, req, req_len, MSG_DONTWAIT | MSG_NOSIGNAL, - (struct sockaddr *)&addr, addrlen); - assert (val >= 0); - - val = recvfrom (servfd, buf, 1000, MSG_DONTWAIT, NULL, 0); - assert (val >= 0); - - assert (stun_agent_validate (&agent, &msg, buf, val, NULL, NULL) - == STUN_VALIDATION_SUCCESS); - - stun_agent_init_response (&agent, &msg, buf, sizeof (buf), &msg); - assert (stun_message_append_addr (&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, - (struct sockaddr *) &addr, addrlen) == STUN_MESSAGE_RETURN_SUCCESS); - len = stun_agent_finish_message (&agent, &msg, NULL, 0); - assert (len > 0); - - assert (stun_agent_validate (&agent, &msg, buf, len, NULL, NULL) - == STUN_VALIDATION_SUCCESS); - - val = getsockname (servfd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - - val = stun_usage_bind_process (&msg, (struct sockaddr *) &addr, &addrlen, - (struct sockaddr *) &addr, &addrlen); - assert (val == STUN_USAGE_BIND_RETURN_SUCCESS); - - /* End */ - close (servfd); - - val = close (fd); - assert (val == 0); -} - -static void keepalive (void) -{ - struct sockaddr_storage addr = {0}; - socklen_t addrlen = sizeof (addr); - int val, servfd, fd; - - uint8_t buf[STUN_MAX_MESSAGE_SIZE]; - size_t len; - StunAgent agent; - StunMessage msg; - - uint16_t known_attributes[] = { - STUN_ATTRIBUTE_MAPPED_ADDRESS, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - STUN_ATTRIBUTE_PRIORITY, - STUN_ATTRIBUTE_USERNAME, - STUN_ATTRIBUTE_MESSAGE_INTEGRITY, - STUN_ATTRIBUTE_ERROR_CODE, 0}; - - stun_agent_init (&agent, known_attributes, - STUN_COMPATIBILITY_RFC5389, 0); - - /* Allocate a local UDP port for server */ - servfd = listen_dgram (); - assert (servfd != -1); - - val = getsockname (servfd, (struct sockaddr *)&addr, &addrlen); - assert (val == 0); - - /* Allocate a client socket and connect to server */ - fd = socket (addr.ss_family, SOCK_DGRAM, 0); - assert (fd != -1); - - /* Keep alive sending smoke test */ - len = stun_usage_bind_keepalive (&agent, &msg, buf, sizeof(buf)); - assert (len == 20); - - val = sendto (fd, buf, len, MSG_DONTWAIT | MSG_NOSIGNAL, - (struct sockaddr *)&addr, addrlen); - assert (val >= 0); - - /* End */ - close (servfd); - - val = close (fd); - assert (val == 0); -} - - -static void test (void (*func) (void), const char *name) -{ - alarm (30); - - printf ("%s test... ", name); - func (); - puts ("OK"); -} - - -int main (void) -{ -#ifdef _WIN32 - WSADATA w; - WSAStartup(0x0202, &w); -#endif - test (bad_family, "Bad socket family"); - test (small_srv_addr, "Too small server address"); - test (big_srv_addr, "Too big server address"); - test (bad_responses, "Bad responses"); - test (responses, "Error responses"); - test (keepalive, "Keep alives"); -#ifdef HAVE_POLL - test (timeout, "Binding discovery timeout"); -#endif -#ifdef _WIN32 - WSACleanup(); -#endif - return 0; -} diff --git a/stun/tests/test-conncheck.c b/stun/tests/test-conncheck.c deleted file mode 100644 index cf3693f..0000000 --- a/stun/tests/test-conncheck.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include "stun/stunagent.h" -#include "stun/usages/ice.h" - -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef _WIN32 -#include -#include -#define MSG_DONTWAIT 0 -#define MSG_NOSIGNAL 0 - -#define alarm(...) -#else -#include -#include -#include -#include -#include -#endif - -#undef NDEBUG /* ensure assertions are built-in */ -#include - - -int main (void) -{ - union { - struct sockaddr sa; - struct sockaddr_storage storage; - struct sockaddr_in ip4; - } addr; - uint8_t req_buf[STUN_MAX_MESSAGE_SIZE]; - uint8_t resp_buf[STUN_MAX_MESSAGE_SIZE]; - const uint64_t tie = 0x8000000000000000LL; - StunMessageReturn val; - StunUsageIceReturn val2; - size_t len; - size_t rlen; - static char username[] = "L:R"; - static uint8_t ufrag[] = "L", pass[] = "secret"; - size_t ufrag_len = strlen ((char*) ufrag); - size_t pass_len = strlen ((char*) pass); - int code; - bool control = false; - StunAgent agent; - StunMessage req; - StunMessage resp; - StunDefaultValidaterData validater_data[] = { - {ufrag, ufrag_len, pass, pass_len}, - {(uint8_t *) username, strlen (username), pass, pass_len}, - {NULL, 0, NULL, 0}}; - StunValidationStatus valid; - - stun_agent_init (&agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC5389, - STUN_AGENT_USAGE_USE_FINGERPRINT | - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS); - - memset (&addr, 0, sizeof (addr)); - addr.ip4.sin_family = AF_INET; -#ifdef HAVE_SA_LEN - addr.ip4.sin_len = sizeof (addr); -#endif - addr.ip4.sin_port = htons (12345); - addr.ip4.sin_addr.s_addr = htonl (0x7f000001); - - /* Incorrect message class */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); - assert (stun_agent_init_response (&agent, &req, req_buf, sizeof (req_buf), &req)); - - rlen = stun_agent_finish_message (&agent, &req, NULL, 0); - assert (rlen > 0); - - len = sizeof (resp_buf); - val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, - &resp, resp_buf, &len, &addr.storage, - sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); - assert (val2 == STUN_USAGE_ICE_RETURN_INVALID_REQUEST); - assert (len == 0); - - /* Incorrect message method */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), 0x666)); - val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, username); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); - assert (rlen > 0); - - len = sizeof (resp_buf); - val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, - &resp, resp_buf, &len, &addr.storage, - sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); - assert (val2 == STUN_USAGE_ICE_RETURN_INVALID_METHOD); - assert (len > 0); - - /* Unknown attribute */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); - val = stun_message_append_string (&req, 0x666, "The evil unknown attribute!"); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, username); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); - assert (rlen > 0); - - valid = stun_agent_validate (&agent, &req, req_buf, rlen, - stun_agent_default_validater, validater_data); - - assert (valid == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE); - - /* Unauthenticated message */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); - rlen = stun_agent_finish_message (&agent, &req, NULL, 0); - assert (rlen > 0); - - valid = stun_agent_validate (&agent, &req, req_buf, rlen, - stun_agent_default_validater, validater_data); - - assert (valid == STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST); - - /* No username */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); - rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); - assert (rlen > 0); - - valid = stun_agent_validate (&agent, &req, req_buf, rlen, - stun_agent_default_validater, validater_data); - - assert (valid == STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST); - assert (stun_usage_ice_conncheck_priority (&req) == 0); - assert (stun_usage_ice_conncheck_use_candidate (&req) == false); - - /* Good message */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); - val = stun_message_append32 (&req, STUN_ATTRIBUTE_PRIORITY, 0x12345678); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - val = stun_message_append_flag (&req, STUN_ATTRIBUTE_USE_CANDIDATE); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, - (char*) ufrag); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); - assert (rlen > 0); - - len = sizeof (resp_buf); - val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, - &resp, resp_buf, &len, &addr.storage, - sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); - assert (val2 == STUN_USAGE_ICE_RETURN_SUCCESS); - assert (len > 0); - assert (stun_agent_validate (&agent, &resp, resp_buf, len, - stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); - assert (stun_message_get_class (&resp) == STUN_RESPONSE); - assert (stun_usage_ice_conncheck_priority (&req) == 0x12345678); - assert (stun_usage_ice_conncheck_use_candidate (&req) == true); - - /* Invalid socket address */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); - val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, - (char *) ufrag); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); - assert (rlen > 0); - - addr.ip4.sin_family = AF_UNSPEC; - len = sizeof (resp_buf); - val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, - &resp, resp_buf, &len, &addr.storage, - sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); - assert (val2 == STUN_USAGE_ICE_RETURN_INVALID_ADDRESS); - assert (len == 0); - - addr.ip4.sin_family = AF_INET; - - /* Role conflict, controlling + ICE-CONTROLLING, switching controlled */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); - val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLING, tie + 1); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, - (char *) ufrag); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); - assert (rlen > 0); - - len = sizeof (resp_buf); - control = true; - val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, - &resp, resp_buf, &len, &addr.storage, - sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); - assert (val2 == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT); - assert (len > 0); - assert (control == false); - assert (stun_agent_validate (&agent, &resp, resp_buf, len, - stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); - assert (stun_message_get_class (&resp) == STUN_RESPONSE); - - /* Role conflict, controlled + ICE-CONTROLLED, switching controlling */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); - val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLED, tie - 1); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, - (char *) ufrag); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); - assert (rlen > 0); - - len = sizeof (resp_buf); - control = false; - val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, - &resp, resp_buf, &len, &addr.storage, - sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); - assert (val2 == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT); - assert (len > 0); - assert (control == true); - assert (stun_agent_validate (&agent, &resp, resp_buf, len, - stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); - assert (stun_message_get_class (&resp) == STUN_RESPONSE); - - /* Role conflict, controlling + ICE-CONTROLLING, staying controlling */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); - val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLING, tie - 1); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, - (char *) ufrag); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); - assert (rlen > 0); - - len = sizeof (resp_buf); - control = true; - val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, - &resp, resp_buf, &len, &addr.storage, - sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); - assert (val2 == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT); - assert (len > 0); - assert (control == true); - assert (stun_agent_validate (&agent, &resp, resp_buf, len, - stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); - assert (stun_message_get_class (&resp) == STUN_ERROR); - stun_message_find_error (&resp, &code); - assert (code == STUN_ERROR_ROLE_CONFLICT); - - /* Role conflict, controlled + ICE-CONTROLLED, staying controlling */ - assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); - val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLED, tie + 1); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, - (char *) ufrag); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); - assert (rlen > 0); - - len = sizeof (resp_buf); - control = false; - val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, - &resp, resp_buf, &len, &addr.storage, - sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); - assert (val2 == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT); - assert (len > 0); - assert (control == false); - assert (stun_agent_validate (&agent, &resp, resp_buf, len, - stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); - assert (stun_message_get_class (&resp) == STUN_ERROR); - stun_message_find_error (&resp, &code); - assert (code == STUN_ERROR_ROLE_CONFLICT); - - return 0; -} diff --git a/stun/tests/test-format.c b/stun/tests/test-format.c deleted file mode 100644 index f364da4..0000000 --- a/stun/tests/test-format.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "stun/stunagent.h" -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#else -#include -#include -#include -#include -#endif - - -static void fatal (const char *msg, ...) -{ - va_list ap; - va_start (ap, msg); - vfprintf (stderr, msg, ap); - va_end (ap); - fputc ('\n', stderr); - exit (1); -} - -static const uint8_t usr[] = "admin"; -static const uint8_t pwd[] = "s3kr3t"; - -static bool dynamic_check_validater (StunAgent *agent, - StunMessage *message, uint8_t *username, uint16_t username_len, - uint8_t **password, size_t *password_len, void *user_data) -{ - - if (username_len != strlen ((char *) usr) || - memcmp (username, usr, strlen ((char *) usr)) != 0) - fatal ("vector test : Validater received wrong username!"); - - *password = (uint8_t *) pwd; - *password_len = strlen ((char *) pwd); - - - return true; -} -static void -dynamic_check (StunAgent *agent, StunMessage *msg, size_t len) -{ - StunMessage msg2; - - if (stun_agent_validate (agent, &msg2, msg->buffer, len, dynamic_check_validater, NULL) != STUN_VALIDATION_SUCCESS) - fatal ("Could not validate message"); - - printf ("Built message of %u bytes\n", (unsigned)len); -} - - -static size_t -finish_check (StunAgent *agent, StunMessage *msg) -{ - uint8_t buf[STUN_MAX_MESSAGE_SIZE + 8]; - size_t len; - uint16_t plen; - StunMessage msg2 = {0}; - StunMessageReturn val; - - msg2.agent = msg->agent; - msg2.buffer = buf; - msg2.buffer_len = sizeof(buf); - memcpy (msg2.buffer, msg->buffer, sizeof(buf) > msg->buffer_len ? msg->buffer_len : sizeof(buf)); - - len = stun_agent_finish_message (agent, msg, NULL, 0); - - if (len <= 0) - fatal ("Cannot finish message"); - dynamic_check (agent, msg, len); - - if (stun_message_find (&msg2, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, &plen) != NULL) - fatal ("Missing HMAC test failed"); - - val = stun_message_append_string (&msg2, STUN_ATTRIBUTE_USERNAME, (char *) usr); - assert (val == STUN_MESSAGE_RETURN_SUCCESS); - - len = stun_agent_finish_message (agent, &msg2, pwd, strlen ((char *) pwd)); - - if (len <= 0) - fatal ("Cannot finish message with short-term creds"); - dynamic_check (agent, &msg2, len); - - return len; -} - -static void -check_af (const char *name, int family, socklen_t addrlen) -{ - struct sockaddr_storage addr; - uint8_t buf[100]; - StunAgent agent; - StunMessage msg; - uint16_t known_attributes[] = {STUN_ATTRIBUTE_USERNAME, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, STUN_ATTRIBUTE_ERROR_CODE, 0}; - - stun_agent_init (&agent, known_attributes, - STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT); - - assert (addrlen <= sizeof (addr)); - - memset (&addr, 0, sizeof (addr)); - stun_agent_init_request (&agent, &msg, buf, sizeof(buf), STUN_BINDING); - - if (stun_message_append_addr (&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, - (struct sockaddr *) &addr, addrlen) != - STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS) - fatal ("Unknown address family test failed"); - if (stun_message_append_xor_addr (&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - &addr, addrlen) != - STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS) - fatal ("Unknown address family xor test failed"); - - addr.ss_family = family; - if (stun_message_append_addr (&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, - (struct sockaddr *) &addr, addrlen - 1) != - STUN_MESSAGE_RETURN_INVALID) - fatal ("Too small %s sockaddr test failed", name); - - if (stun_message_append_xor_addr (&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - &addr, addrlen - 1) != STUN_MESSAGE_RETURN_INVALID) - fatal ("Too small %s sockaddr xor test failed", name); - - if (stun_message_append_addr (&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, - (struct sockaddr *) &addr, addrlen) != STUN_MESSAGE_RETURN_SUCCESS) - fatal ("%s sockaddr test failed", name); - - if (stun_message_append_xor_addr (&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - &addr, addrlen) != STUN_MESSAGE_RETURN_SUCCESS) - fatal ("%s sockaddr xor test failed", name); -} - -int main (void) -{ - uint8_t buf[100]; - size_t len; - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } addr; - - StunAgent agent; - StunMessage msg; - uint16_t known_attributes[] = {STUN_ATTRIBUTE_USERNAME, - STUN_ATTRIBUTE_MESSAGE_INTEGRITY, - STUN_ATTRIBUTE_ERROR_CODE, - 0}; - - stun_agent_init (&agent, known_attributes, - STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT); - - /* Request formatting test */ - stun_agent_init_request (&agent, &msg, buf, sizeof(buf), STUN_BINDING); - finish_check (&agent, &msg); - if (memcmp (buf, "\x00\x01", 2)) - fatal ("Request formatting test failed"); - - /* Response formatting test */ - stun_agent_init_response (&agent, &msg, buf, sizeof (buf), &msg); - finish_check (&agent, &msg); - if (memcmp (buf, "\x01\x01", 2)) - fatal ("Response formatting test failed"); - - /* Error formatting test */ - stun_agent_init_request (&agent, &msg, buf, sizeof(buf), STUN_BINDING); - finish_check (&agent, &msg); - if (!stun_agent_init_error (&agent, &msg, buf, sizeof (buf), &msg, 400)) - fatal ("Error initialization test failed"); - finish_check (&agent, &msg); - if (memcmp (buf, "\x01\x11", 2)) - fatal ("Error formatting test failed"); - /* Unknown error formatting test */ - stun_agent_init_request (&agent, &msg, buf, sizeof(buf), STUN_BINDING); - finish_check (&agent, &msg); - if (!stun_agent_init_error (&agent, &msg, buf, sizeof (buf), &msg, 666)) - fatal ("Unknown error initialization test failed"); - finish_check (&agent, &msg); - if (memcmp (buf, "\x01\x11", 2)) - fatal ("Unknown error formatting test failed"); - - /* Overflow tests */ - stun_agent_init_request (&agent, &msg, buf, sizeof(buf), STUN_BINDING); - - for (len = 0; - stun_message_append_flag (&msg, 0xffff) != - STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE; - len += 4) - { - if (len > 0xffff) - fatal ("Overflow protection test failed"); - } - - if (stun_message_append32 (&msg, 0xffff, 0x12345678) != - STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE) - fatal ("Double-word overflow test failed"); - if (stun_message_append64 (&msg, 0xffff, - 0x123456789abcdef0) != STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE) - fatal ("Quad-word overflow test failed"); - if (stun_message_append_string (&msg, 0xffff, "foobar") != - STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE) - fatal ("String overflow test failed"); - - memset (&addr, 0, sizeof (addr)); - addr.addr.sa_family = AF_INET; -#ifdef HAVE_SS_LEN - addr.addr.ss_len = sizeof (addr); -#endif - if (stun_message_append_xor_addr (&msg, 0xffff, &addr.storage, - sizeof (addr)) != STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE) - fatal ("Address overflow test failed"); - - if (stun_agent_finish_message (&agent, &msg, NULL, 0) != 0) - fatal ("Fingerprint overflow test failed"); - if (stun_agent_finish_message (&agent, &msg, pwd, strlen ((char *) pwd)) != 0) - fatal ("Message integrity overflow test failed"); - - /* Address attributes tests */ - check_af ("IPv4", AF_INET, sizeof (struct sockaddr_in)); -#ifdef AF_INET6 - check_af ("IPv6", AF_INET6, sizeof (struct sockaddr_in6)); -#endif - - return 0; -} diff --git a/stun/tests/test-hmac.c b/stun/tests/test-hmac.c deleted file mode 100644 index a9cd0df..0000000 --- a/stun/tests/test-hmac.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - - -#include -#include -#include -#include -#include - -#include - -static void print_bytes (const uint8_t *bytes, int len) -{ - int i; - - printf ("0x"); - for (i = 0; i < len; i++) - printf ("%02x", bytes[i]); - printf ("\n"); -} - -static void test_hmac (const uint8_t *key, const uint8_t *str, - const uint8_t *expected) { - uint8_t hmac[20]; - - /* Arbitrary. */ - size_t msg_len = 300; - - stun_sha1 (str, strlen ((const char *) str), msg_len, hmac, - key, strlen ((const char *) key), TRUE /* padding */); - - printf ("HMAC of '%s' with key '%s' is : ", str, key); - print_bytes (hmac, sizeof (hmac)); - printf ("Expected : "); - print_bytes (expected, sizeof (hmac)); - - if (memcmp (hmac, expected, sizeof (hmac))) - exit (1); -} - -int main (void) -{ - const uint8_t hmac1[] = { 0x83, 0x5a, 0x9b, 0x05, 0xea, - 0xd7, 0x68, 0x45, 0x48, 0x74, - 0x6b, 0xa3, 0x37, 0xe0, 0xa9, - 0x3f, 0x4d, 0xb3, 0x9c, 0xa1 }; - - test_hmac ((const uint8_t *) "key", - (const uint8_t *) "some complicated input string which is over 44 bytes long", - hmac1); - - return 0; -} diff --git a/stun/tests/test-parse.c b/stun/tests/test-parse.c deleted file mode 100644 index 731c666..0000000 --- a/stun/tests/test-parse.c +++ /dev/null @@ -1,738 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "stun/stunagent.h" -#include "stun/stunhmac.h" -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#include -#endif - - -# define STUN_MAX_STR (763u) -# define STUN_MAX_CP (127u) - -static void fatal (const char *msg, ...) -{ - va_list ap; - va_start (ap, msg); - vfprintf (stderr, msg, ap); - va_end (ap); - fputc ('\n', stderr); - exit (1); -} - - -static void validate (const uint8_t *msg, unsigned len) -{ - unsigned i = 1; - - do - { - size_t vlen = stun_message_validate_buffer_length (msg, i, TRUE); - if ((vlen & 3) || (vlen != ((i >= len) * len))) - fatal ("%u/%u short message test failed", i, len); - } - while (i++ < (len + 4)); -} - - -/* Tests for generic message validation routines */ -static void test_message (void) -{ - static const uint8_t extra_garbage[] = - {0x15, 0x55, 0x00, 0x00, - 0x21, 0x12, 0xA4, 0x42, // cookie - 0x76, 0x54, 0x32, 0x10, - 0xfe, 0xdc, 0xba, 0x98, - 0x76, 0x54, 0x32, 0x10, - 0xaa, 0xbb, 0xcc, 0xdd}; //extra garbage - static const uint8_t simple_resp[] = - {0x15, 0x55, 0x00, 0x00, - 0x21, 0x12, 0xA4, 0x42, // cookie - 0x76, 0x54, 0x32, 0x10, - 0xfe, 0xdc, 0xba, 0x98, - 0x76, 0x54, 0x32, 0x10}; - static const uint8_t old_ind[] = - {0x14, 0x55, 0x00, 0x00, - 0xfe, 0xdc, 0xba, 0x98, // NO cookie - 0x76, 0x54, 0x32, 0x10, - 0xfe, 0xdc, 0xba, 0x98, - 0x76, 0x54, 0x32, 0x10}; - static const uint8_t fpr_resp[] = - {0x15, 0x55, 0x00, 0x10, - 0x21, 0x12, 0xA4, 0x42, // cookie - 0x76, 0x54, 0x32, 0x10, - 0xfe, 0xdc, 0xba, 0x98, - 0x76, 0x54, 0x32, 0x10, - 0x00, 0x06, 0x00, 0x04, // dummy USERNAME header - 0x41, 0x42, 0x43, 0x44, - 0x80, 0x28, 0x00, 0x04, // FINGERPRINT header - 0xdc, 0x8d, 0xa7, 0x74}; // CRC32; - static const uint8_t bad1[32] = - {0x15, 0x55, 0x00, 0x08, - 0x21, 0x12, 0xA4, 0x42, // cookie - 0x76, 0x54, 0x32, 0x10, - 0xfe, 0xdc, 0xba, 0x98, - 0x76, 0x54, 0x32, 0x10, - 0x00, 0x06, 0x00, 0x05, // too big attribute for message - 0x11, 0x22, 0x33, 0x44, - 0x55, 0x66, 0x77, 0x88}; - static const uint8_t bad2[24] = - {0x15, 0x55, 0x00, 0x05, // invalid message length - 0x21, 0x12, 0xA4, 0x42, - 0x76, 0x54, 0x32, 0x10, - 0xfe, 0xdc, 0xba, 0x98, - 0x76, 0x54, 0x32, 0x10, - 0x00, 0x06, 0x00, 0x01}; - static const uint8_t bad3[27] = - {0x15, 0x55, 0x00, 0x08, - 0x21, 0x12, 0xA4, 0x42, - 0x76, 0x54, 0x32, 0x10, - 0xfe, 0xdc, 0xba, 0x98, - 0x76, 0x54, 0x32, 0x10, - 0x00, 0x06, 0x00, 0x03, - 0x11, 0x22, 0x33}; // missing padding - static const uint8_t bad_crc[] = - {0x15, 0x55, 0x00, 0x08, - 0x21, 0x12, 0xA4, 0x42, - 0x76, 0x54, 0x32, 0x10, - 0xfe, 0xdc, 0xba, 0x98, - 0x76, 0x54, 0x32, 0x10, - 0x80, 0x28, 0x00, 0x04, // FINGERPRINT header - 0x04, 0x91, 0xcd, 0x78}; // CRC32 - static uint8_t bad_crc_offset[] = - {0x15, 0x55, 0x00, 0x10, - 0x21, 0x12, 0xA4, 0x42, - 0x76, 0x54, 0x32, 0x10, - 0xfe, 0xdc, 0xba, 0x98, - 0x20, 0x67, 0xc4, 0x09, - 0x80, 0x28, 0x00, 0x04, // FINGERPRINT header - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x06, 0x00, 0x04, - 0x41, 0x42, 0x43, 0x44}; - - static unsigned char req[] = - {0x00, 0x01, 0x00, 0x00, - 0x8b, 0x45, 0x9b, 0xc3, - 0xe7, 0x7a, 0x05, 0xb3, - 0xe4, 0xfe, 0x01, 0xf0, - 0xaf, 0x83, 0xe1, 0x9e}; - - static uint8_t binding_error_resp[] = - {0x01, 0x11, 0x00, 0x84, - 0x8b, 0x45, 0x9b, 0xc3, - 0xe7, 0x7a, 0x05, 0xb3, - 0xe4, 0xfe, 0x01, 0xf0, - 0xaf, 0x83, 0xe1, 0x9e, - - 0x00, 0x06, 0x00, 0x48, // USERNAME - 0x92, 0x6b, 0x2b, 0x3e, - 0x6a, 0xa5, 0x43, 0x58, - 0xa8, 0x51, 0x25, 0xa6, - 0xf7, 0x9c, 0x0a, 0xe7, - 0xd8, 0x86, 0xf7, 0x76, - 0xf9, 0xcd, 0x8a, 0x2e, - 0x45, 0xd7, 0xcb, 0xbb, - 0xae, 0xe5, 0x03, 0xc3, - 0x3a, 0x32, 0x3a, 0xa9, - 0x9e, 0xb7, 0x7b, 0x32, - 0xe3, 0xf3, 0xa6, 0xc0, - 0xe8, 0x54, 0x4b, 0xef, - 0x52, 0xd2, 0xe2, 0xc0, - 0x43, 0xc2, 0x4c, 0xbc, - 0xaf, 0xd9, 0xf2, 0xfa, - 0x48, 0x8b, 0x8c, 0xe6, - 0x62, 0x14, 0x64, 0x3a, - 0x32, 0x00, 0x00, 0x00, - - 0x00, 0x09, 0x00, 0x1c, // ERROR-CODE - 0x00, 0x00, 0x04, 0x1f, - 0x49, 0x6e, 0x74, 0x65, - 0x67, 0x72, 0x69, 0x74, - 0x79, 0x20, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x20, - 0x46, 0x61, 0x69, 0x6c, - 0x75, 0x72, 0x65, 0x2e, - - 0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY - 0xf7, 0x46, 0x81, 0xc4, - 0x6f, 0x4c, 0x21, 0x5c, - 0xf6, 0x8e, 0xc0, 0x81, - 0x0e, 0x20, 0x3f, 0xb1, - 0xb1, 0xad, 0xa4, 0x8a}; - - StunAgent agent; - StunAgent agent2; - StunMessage msg; - uint16_t known_attributes[] = {STUN_ATTRIBUTE_USERNAME, - STUN_ATTRIBUTE_ERROR_CODE, - STUN_ATTRIBUTE_MESSAGE_INTEGRITY}; - - uint8_t username_v[] = {0x92, 0x6b, 0x2b, 0x3e, 0x6a, 0xa5, 0x43, 0x58, - 0xa8, 0x51, 0x25, 0xa6, 0xf7, 0x9c, 0x0a, 0xe7, - 0xd8, 0x86, 0xf7, 0x76, 0xf9, 0xcd, 0x8a, 0x2e, - 0x45, 0xd7, 0xcb, 0xbb, 0xae, 0xe5, 0x03, 0xc3, - 0x3a, 0x32, 0x3a, 0xa9, 0x9e, 0xb7, 0x7b, 0x32, - 0xe3, 0xf3, 0xa6, 0xc0, 0xe8, 0x54, 0x4b, 0xef, - 0x52, 0xd2, 0xe2, 0xc0, 0x43, 0xc2, 0x4c, 0xbc, - 0xaf, 0xd9, 0xf2, 0xfa, 0x48, 0x8b, 0x8c, 0xe6, - 0x62, 0x14, 0x64, 0x3a, 0x32, 0x00, 0x00, 0x00}; - uint8_t password_v[] = {0x77, 0xd9, 0x7a, 0xe9, 0xcf, 0xe0, 0x3e, 0xa2, - 0x28, 0xa0, 0x5d, 0xec, 0xcf, 0x36, 0xe8, 0x49}; - - StunDefaultValidaterData v = {username_v, 72, password_v, 16}; - - stun_agent_init (&agent, known_attributes, - STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT); - stun_agent_init (&agent2, known_attributes, - STUN_COMPATIBILITY_RFC3489, STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS); - - - stun_agent_validate (&agent2, &msg, req, sizeof(req), NULL, NULL); - stun_agent_finish_message (&agent2, &msg, NULL, 0); - - if (stun_agent_validate (&agent2, &msg, binding_error_resp, - sizeof(binding_error_resp), - stun_agent_default_validater, &v) != STUN_VALIDATION_SUCCESS) - fatal ("Binding Error Response failed"); - - - if (stun_message_validate_buffer_length (NULL, 0, TRUE) != - STUN_MESSAGE_BUFFER_INVALID) - fatal ("0 bytes test failed"); - if (stun_message_validate_buffer_length ((uint8_t *)"\xf0", 1, TRUE) >= 0) - fatal ("1 byte test failed"); - if (stun_message_validate_buffer_length (bad1, sizeof (bad1), TRUE) >= 0) - fatal ("Badness 1 test failed"); - if (stun_message_validate_buffer_length (bad2, sizeof (bad2), TRUE) >= 0) - fatal ("Badness 2 test failed"); - if (stun_message_validate_buffer_length (bad3, sizeof (bad3), TRUE) != 0) - fatal ("Badness 3 test failed"); - validate (simple_resp, 20); - validate (old_ind, 20); - validate (fpr_resp, 36); - - if (stun_agent_validate (&agent, &msg, extra_garbage, sizeof(extra_garbage), - NULL, NULL) != STUN_VALIDATION_NOT_STUN) - fatal ("Extra garbage test failed"); - if (stun_agent_validate (&agent, &msg, simple_resp, sizeof(simple_resp), - NULL, NULL) != STUN_VALIDATION_BAD_REQUEST) - fatal ("Missing CRC test failed"); - if (stun_agent_validate (&agent, &msg, old_ind, sizeof(old_ind), - NULL, NULL) != STUN_VALIDATION_BAD_REQUEST) - fatal ("Missing cookie test failed"); - if (stun_agent_validate (&agent, &msg, bad_crc, sizeof(bad_crc), - NULL, NULL) != STUN_VALIDATION_BAD_REQUEST) - fatal ("Bad CRC test failed"); - if (stun_agent_validate (&agent, &msg, bad_crc_offset, sizeof(bad_crc_offset), - NULL, NULL) != STUN_VALIDATION_BAD_REQUEST) - fatal ("Bad CRC offset test failed"); - if (stun_agent_validate (&agent, &msg, fpr_resp, sizeof(fpr_resp), - NULL, NULL) != STUN_VALIDATION_UNMATCHED_RESPONSE) - fatal ("Good CRC test failed"); - - if (stun_message_get_class (&msg) != 3) - fatal ("Class test failed"); - if (stun_message_get_method (&msg) != 0x525) - fatal ("Method test failed"); -} - - -static bool test_attribute_validater (StunAgent *agent, - StunMessage *message, uint8_t *username, uint16_t username_len, - uint8_t **password, size_t *password_len, void *user_data) -{ - uint8_t *pwd = user_data; - - if (username_len != 4 || - memcmp (username, "ABCD", 4) != 0) - return false; - - *password = pwd; - *password_len = strlen ((char *) pwd); - - return true; -} - -/* Tests for message attribute parsing */ -static void test_attribute (void) -{ - static const uint8_t acme[] = - {0x04, 0x55, 0x00, 0x6C, // <-- update message length if needed!! - 0x21, 0x12, 0xA4, 0x42, // cookie - 0x76, 0x54, 0x32, 0x10, - 0xfe, 0xdc, 0xba, 0x98, - 0x76, 0x54, 0x32, 0x10, - - /* FF01: empty */ - 0xff, 0x01, 0x00, 0x00, - - /* FF02: address of unknown family, 32-bits */ - 0xff, 0x02, 0x00, 0x04, - 0x41, 0x42, 0x43, 0x44, - - /* FF03: too short IPv6 address */ - 0xff, 0x03, 0x00, 0x06, - 0x00, 0x02, 0x12, 0x34, - 0x20, 0x01, 0x0d, 0xb8, - - /* FF04: valid IPv4 address, 64-bits */ - 0xff, 0x04, 0x00, 0x08, - 0x00, 0x01, 0x12, 0x34, - 0xc0, 0x00, 0x02, 0x01, - - /* FF05: too long IPv4 address */ - 0xff, 0x05, 0x00, 0x0A, - 0x00, 0x01, 0x12, 0x34, - 0xc0, 0x00, 0x02, 0x01, - 0x66, 0x60, 0x00, 0x00, - - /* FF06: valid xor'd IPv6 address, 160-bits */ - 0xff, 0x06, 0x00, 0x14, - 0x00, 0x02, 0x12, 0x34, - 0x01, 0x13, 0xa9, 0xfa, - 0xa8, 0xf9, 0x8c, 0xff, - 0x20, 0x26, 0x74, 0x48, - 0x8c, 0x9a, 0xec, 0xfd, - - /* dummy USERNAME header */ - 0x00, 0x06, 0x00, 0x04, - 0x41, 0x42, 0x43, 0x44, - - /* MESSAGE-INTEGRITY attribute */ - 0x00, 0x08, 0x00, 0x14, - 0x0b, 0xc4, 0xb2, 0x0c, - 0x94, 0x58, 0xbb, 0x25, - 0xa3, 0x22, 0x1a, 0xc8, - 0xe1, 0x87, 0x32, 0x36, - 0x3a, 0xfc, 0xe2, 0xc3}; - - union - { - struct sockaddr_storage st; - struct sockaddr_in6 s6; - } addr; - socklen_t addrlen; - uint32_t dword; - uint64_t qword; - char str[STUN_MAX_STR]; - - StunAgent agent; - StunMessage msg; - uint16_t known_attributes[] = {STUN_ATTRIBUTE_MESSAGE_INTEGRITY, STUN_ATTRIBUTE_USERNAME, 0}; - - printf ("Attribute test message length: %zd\n", sizeof (acme)); - - stun_agent_init (&agent, known_attributes, - STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS); - - if (stun_agent_validate (&agent, &msg, acme, sizeof(acme), - NULL, NULL) != STUN_VALIDATION_UNAUTHORIZED) - fatal ("Unauthorized validation failed"); - - if (stun_agent_validate (&agent, &msg, acme, sizeof(acme), - test_attribute_validater, (void *) "bad__guy") != STUN_VALIDATION_UNAUTHORIZED) - fatal ("invalid password validation failed"); - - if (stun_agent_validate (&agent, &msg, acme, sizeof(acme), - test_attribute_validater, (void *) "good_guy") != STUN_VALIDATION_SUCCESS) - fatal ("good password validation failed"); - - if (stun_message_has_attribute (&msg, 0xff00)) - fatal ("Absent attribute test failed"); - if (!stun_message_has_attribute (&msg, 0xff01)) - fatal ("Present attribute test failed"); - - if (stun_message_find_flag (&msg, 0xff00) != STUN_MESSAGE_RETURN_NOT_FOUND) - fatal ("Absent flag test failed"); - if (stun_message_find_flag (&msg, 0xff01) != STUN_MESSAGE_RETURN_SUCCESS) - fatal ("Flag test failed"); - if (stun_message_find_flag (&msg, 0xff02) != STUN_MESSAGE_RETURN_INVALID) - fatal ("Too big flag test failed"); - - if (stun_message_find32 (&msg, 0xff00, &dword) != - STUN_MESSAGE_RETURN_NOT_FOUND) - fatal ("Absent dword test failed"); - if (stun_message_find32 (&msg, 0xff01, &dword) != STUN_MESSAGE_RETURN_INVALID) - fatal ("Bad dword test failed"); - if (stun_message_find32 (&msg, 0xff02, &dword) != STUN_MESSAGE_RETURN_SUCCESS) - fatal ("Double-word test failed"); - - if (stun_message_find64 (&msg, 0xff00, &qword) != - STUN_MESSAGE_RETURN_NOT_FOUND) - fatal ("Absent qword test failed"); - if (stun_message_find64 (&msg, 0xff01, &qword) != STUN_MESSAGE_RETURN_INVALID) - fatal ("Bad qword test failed"); - if (stun_message_find64 (&msg, 0xff04, &qword) != STUN_MESSAGE_RETURN_SUCCESS) - fatal ("Quad-word test failed"); - - if (stun_message_find_string (&msg, 0xff00, str, STUN_MAX_CP) != - STUN_MESSAGE_RETURN_NOT_FOUND) - fatal ("Absent string test failed"); - if ((stun_message_find_string (&msg, 0xff02, str, STUN_MAX_CP) != - STUN_MESSAGE_RETURN_SUCCESS) - || strcmp (str, "ABCD")) - fatal ("String test failed"); - - addrlen = sizeof (addr); - if (stun_message_find_addr (&msg, 0xff01, &addr.st, &addrlen) != - STUN_MESSAGE_RETURN_INVALID) - fatal ("Too short addres test failed"); - addrlen = sizeof (addr); - if (stun_message_find_addr (&msg, 0xff02, &addr.st, &addrlen) != - STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS) - fatal ("Unknown address family test failed"); - addrlen = sizeof (addr); - if (stun_message_find_addr (&msg, 0xff03, &addr.st, &addrlen) != - STUN_MESSAGE_RETURN_INVALID) - fatal ("Too short IPv6 address test failed"); - addrlen = sizeof (addr); - if (stun_message_find_addr (&msg, 0xff04, &addr.st, &addrlen) != - STUN_MESSAGE_RETURN_SUCCESS) - fatal ("IPv4 address test failed"); - addrlen = sizeof (addr); - if (stun_message_find_addr (&msg, 0xff05, &addr.st, &addrlen) != - STUN_MESSAGE_RETURN_INVALID) - fatal ("Too big IPv4 address test failed"); - addrlen = sizeof (addr); - if (stun_message_find_xor_addr (&msg, 0xff06, &addr.st, &addrlen) != - STUN_MESSAGE_RETURN_SUCCESS || - memcmp (&addr.s6.sin6_addr, "\x20\x01\x0d\xb8""\xde\xad\xbe\xef" - "\xde\xfa\xce\xd0""\xfa\xce\xde\xed", 16)) - fatal ("IPv6 address test failed"); - -} - -static const char vector_username[] = "evtj:h6vY"; -static uint8_t vector_password[] = "VOkJxbRl1RmTxUk/WvJxBt"; - -static bool test_vector_validater (StunAgent *agent, - StunMessage *message, uint8_t *username, uint16_t username_len, - uint8_t **password, size_t *password_len, void *user_data) -{ - intptr_t callable = (intptr_t) user_data; - - if (!callable) - fatal ("vector test : Validater should not be called!"); - - if (username_len != strlen (vector_username) || - memcmp (username, vector_username, strlen (vector_username)) != 0) - fatal ("vector test : Validater received wrong username!"); - - *password = vector_password; - *password_len = strlen ((char *) vector_password); - - - return true; -} - -static void test_vectors (void) -{ - /* Request message */ - static unsigned char req[] = - {0x00, 0x01, 0x00, 0x44, - 0x21, 0x12, 0xa4, 0x42, - 0xb7, 0xe7, 0xa7, 0x01, - 0xbc, 0x34, 0xd6, 0x86, - 0xfa, 0x87, 0xdf, 0xae, - - 0x00, 0x24, 0x00, 0x04, // PRIORITY - 0x6e, 0x00, 0x01, 0xff, - - 0x80, 0x29, 0x00, 0x08, // ICE_CONTROLLED - 0x93, 0x2f, 0xf9, 0xb1, - 0x51, 0x26, 0x3b, 0x36, - - 0x00, 0x06, 0x00, 0x09, // USERNAME - 0x65, 0x76, 0x74, 0x6a, - 0x3a, 0x68, 0x36, 0x76, - 0x59, 0x20, 0x20, 0x20, - - 0x00, 0x08, 0x00, 0x14, // MESSAGE_INTEGRITY - 0x62, 0x4e, 0xeb, 0xdc, - 0x3c, 0xc9, 0x2d, 0xd8, - 0x4b, 0x74, 0xbf, 0x85, - 0xd1, 0xc0, 0xf5, 0xde, - 0x36, 0x87, 0xbd, 0x33, - - 0x80, 0x28, 0x00, 0x04, // FINGERPRINT - 0xad, 0x8a, 0x85, 0xff}; - - static const unsigned char req2[] = - {0x00, 0x01, 0x00, 0x44, - 0x21, 0x12, 0xa4, 0x42, - 0xb7, 0xe7, 0xa7, 0x01, - 0xbc, 0x34, 0xd6, 0x86, - 0xfa, 0x87, 0xdf, 0xae, - - 0x00, 0x24, 0x00, 0x04, // PRIORITY - 0x6e, 0x00, 0x01, 0xff, - - 0x80, 0x29, 0x00, 0x08, // ICE_CONTROLLED - 0x93, 0x2f, 0xf9, 0xb1, - 0x51, 0x26, 0x3b, 0x36, - - 0x00, 0x06, 0x00, 0x09, // USERNAME - 0x65, 0x76, 0x74, 0x6a, - 0x3a, 0x68, 0x36, 0x76, - 0x59, 0x20, 0x20, 0x20, - - 0x00, 0x08, 0x00, 0x14, // MESSAGE_INTEGRITY - 0x62, 0x4e, 0xeb, 0xdc, - 0x3c, 0xc9, 0x2d, 0xd8, - 0x4b, 0x74, 0xbf, 0x85, - 0xd1, 0xc0, 0xf5, 0xde, - 0x36, 0x87, 0xbd, 0x33, - - 0x80, 0x28, 0x00, 0x04, // FINGERPRINT - 0xad, 0x8a, 0x85, 0xff}; - - /* Response message */ - static const unsigned char respv4[] = - {0x01, 0x01, 0x00, 0x4c, - 0x21, 0x12, 0xa4, 0x42, - 0xb7, 0xe7, 0xa7, 0x01, - 0xbc, 0x34, 0xd6, 0x86, - 0xfa, 0x87, 0xdf, 0xae, - - 0x80, 0x22, 0x00, 0x0b, // SERVER - 0x74, 0x65, 0x73, 0x74, - 0x20, 0x76, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x20, - - 0x00, 0x20, 0x00, 0x08, // XOR_MAPPED_ADDRESS - 0x00, 0x01, 0xa1, 0x47, - 0xe1, 0x12, 0xa6, 0x43, - - 0x00, 0x06, 0x00, 0x09, // USERNAME - 0x65, 0x76, 0x74, 0x6a, - 0x3a, 0x68, 0x36, 0x76, - 0x59, 0x20, 0x20, 0x20, - - 0x00, 0x08, 0x00, 0x14, // MESSAGE_INTEGRITY - 0x7d, 0xb7, 0xfc, 0x52, - 0x70, 0xc6, 0xdb, 0x1f, - 0xc3, 0x26, 0x34, 0xbb, - 0x4c, 0x64, 0x6e, 0xe7, - 0x1d, 0xb3, 0x78, 0x4a, - - 0x80, 0x28, 0x00, 0x04, // FINGERPRINT - 0xf0, 0x60, 0x66, 0xa9}; - static const unsigned char respv6[] = - {0x01, 0x01, 0x00, 0x58, - 0x21, 0x12, 0xa4, 0x42, - 0xb7, 0xe7, 0xa7, 0x01, - 0xbc, 0x34, 0xd6, 0x86, - 0xfa, 0x87, 0xdf, 0xae, - - 0x80, 0x22, 0x00, 0x0b, // SERVER - 0x74, 0x65, 0x73, 0x74, - 0x20, 0x76, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x20, - - 0x00, 0x20, 0x00, 0x14, // XOR_MAPPED_ADDRESS - 0x00, 0x02, 0xa1, 0x47, - 0x01, 0x13, 0xa9, 0xfa, - 0xa5, 0xd3, 0xf1, 0x79, - 0xbc, 0x25, 0xf4, 0xb5, - 0xbe, 0xd2, 0xb9, 0xd9, - - 0x00, 0x06, 0x00, 0x09, // USERNAME - 0x65, 0x76, 0x74, 0x6a, - 0x3a, 0x68, 0x36, 0x76, - 0x59, 0x20, 0x20, 0x20, - - 0x00, 0x08, 0x00, 0x14, // MESSAGE_INTEGRITY - 0x21, 0xcb, 0xbd, 0x25, - 0x1a, 0x8c, 0x4c, 0x38, - 0x8c, 0xc5, 0xcd, 0xb3, - 0x27, 0x6a, 0xf5, 0x61, - 0xb2, 0x21, 0xc8, 0x2b, - - 0x80, 0x28, 0x00, 0x04, // FINGERPRINT - 0xec, 0x27, 0xae, 0xb7}; - union { - struct sockaddr_storage st; - struct sockaddr_in ip4; - struct sockaddr_in6 ip6; - } addr; - socklen_t addrlen; - - StunAgent agent; - StunMessage msg; - StunMessage msg2; - uint16_t known_attributes[] = { - STUN_ATTRIBUTE_MESSAGE_INTEGRITY, - STUN_ATTRIBUTE_USERNAME, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - STUN_ATTRIBUTE_PRIORITY, 0}; - - stun_agent_init (&agent, known_attributes, - STUN_COMPATIBILITY_RFC5389, - STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS | - STUN_AGENT_USAGE_USE_FINGERPRINT); - - memset (&addr, 0, sizeof (addr)); - - puts ("Checking test vectors..."); - - if (stun_agent_validate (&agent, &msg2, req2, sizeof(req2), - test_vector_validater, (void *) 1) != STUN_VALIDATION_SUCCESS) - fatal ("Request test vector authentication failed"); - - if (stun_agent_validate (&agent, &msg, req, sizeof(req), - test_vector_validater, (void *) 1) != STUN_VALIDATION_SUCCESS) - fatal ("Request test vector authentication failed"); - - /* Remove the message-integrity and fingerprint attributes */ - req[3] = 0x24; - - if (stun_message_length (&msg) != sizeof(req) - 32) - fatal ("vector test: removing attributes failed"); - - stun_agent_finish_message (&agent, &msg, vector_password, - strlen ((char *) vector_password)); - - if (stun_message_length (&msg) != stun_message_length (&msg2) || - memcmp (req, req2, sizeof(req)) != 0) - fatal ("vector test : req and req2 are different"); - - if (stun_agent_validate (&agent, &msg, respv4, sizeof(respv4), - test_vector_validater, (void *) 0) != STUN_VALIDATION_SUCCESS) - fatal ("Response ipv4 test vector authentication failed"); - - if (stun_agent_validate (&agent, &msg, respv4, sizeof(respv4), - test_vector_validater, (void *) 0) != STUN_VALIDATION_UNMATCHED_RESPONSE) - fatal ("Response ipv4 test vector authentication failed"); - - addrlen = sizeof (addr.ip4); - if (stun_message_find_xor_addr (&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - &addr.st, &addrlen) != STUN_MESSAGE_RETURN_SUCCESS) - fatal ("Response test vector IPv4 extraction failed"); - if (addr.ip4.sin_family != AF_INET) - fatal ("Response test vector IPv4 family failed"); - if (ntohl (addr.ip4.sin_addr.s_addr) != 0xC0000201) - fatal ("Response test vector IPv4 address failed"); - if (ntohs (addr.ip4.sin_port) != 32853) - fatal ("Response test vector IPv6 port failed"); - - if (stun_agent_validate (&agent, &msg, req, sizeof(req), - test_vector_validater, (void *) 1) != STUN_VALIDATION_SUCCESS) - fatal ("Request test vector second authentication failed"); - - /* Remove the fingerprint attributes */ - msg.key = NULL; - msg.key_len = 0; - req[3] = 0x3C; - - if (stun_message_length (&msg) != sizeof(req) - 8) - fatal ("vector test: removing attributes failed"); - - stun_agent_finish_message (&agent, &msg, NULL, 0); - - if (stun_message_length (&msg) != stun_message_length (&msg2) || - memcmp (req, req2, sizeof(req)) != 0) - fatal ("vector test : req and req2 are different"); - - if (stun_agent_validate (&agent, &msg, respv6, sizeof(respv6), - test_vector_validater, (void *) 1) != STUN_VALIDATION_SUCCESS) - fatal ("Response ipv6 test vector authentication failed"); - - addrlen = sizeof (addr.ip6); - if (stun_message_find_xor_addr (&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - &addr.st, &addrlen) != STUN_MESSAGE_RETURN_SUCCESS) - fatal ("Response test vector IPv6 extraction failed"); - if (addr.ip6.sin6_family != AF_INET6) - fatal ("Response test vector IPv6 family failed"); - if (memcmp (addr.ip6.sin6_addr.s6_addr, "\x20\x01\x0d\xb8\x12\x34\x56\x78" - "\x00\x11\x22\x33\x44\x55\x66\x77", 16) != 0) - fatal ("Response test vector IPv6 address failed"); - if (ntohs (addr.ip6.sin6_port) != 32853) - fatal ("Response test vector IPv6 port failed"); - - - puts ("Done."); -} - -static void test_hash_creds (void) -{ - uint8_t md5[16]; - uint8_t real_md5[] = { - 0x84, 0x93, 0xfb, 0xc5, - 0x3b, 0xa5, 0x82, 0xfb, - 0x4c, 0x04, 0x4c, 0x45, - 0x6b, 0xdc, 0x40, 0xeb}; - - puts ("Testing long term credentials hash algorithm..."); - - - stun_hash_creds ((uint8_t *) "realm", strlen ("realm"), - (uint8_t *) "user", strlen ("user"), - (uint8_t *) "pass", strlen ("pass"), md5); - - stun_debug_bytes ("key for user:realm:pass is : ", md5, 16); - - stun_debug_bytes ("RFC key for user:realm:pass is : ", real_md5, 16); - - if(memcmp (md5, real_md5, sizeof(md5)) != 0) - fatal ("MD5 hashes are different!"); - - puts ("Done!"); - -} - -int main (void) -{ - test_message (); - test_attribute (); - test_vectors (); - test_hash_creds (); - return 0; -} diff --git a/stun/tests/test-turn.c b/stun/tests/test-turn.c deleted file mode 100644 index cb52768..0000000 --- a/stun/tests/test-turn.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include "stun/stunagent.h" -#include "stun/usages/turn.h" - -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include - -#define MSG_DONTWAIT 0 -#define MSG_NOSIGNAL 0 - -#define alarm(...) -#define close closesocket -#else -#include -#include -#include -#include -#include -#endif - -#undef NDEBUG /* ensure assertions are built-in */ -#include - - -static int listen_dgram (void) -{ - struct addrinfo hints, *res; - int val = -1; - - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = SOCK_DGRAM; - - if (getaddrinfo (NULL, "0", &hints, &res)) - return -1; - - for (const struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next) - { - int fd = socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); - if (fd == -1) - continue; - - if (bind (fd, ptr->ai_addr, ptr->ai_addrlen)) - { - close (fd); - continue; - } - - val = fd; - break; - } - - freeaddrinfo (res); - return val; -} - - -static void -printaddr (const char *str, const struct sockaddr *addr, socklen_t addrlen) -{ - char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV]; - - int val = getnameinfo (addr, addrlen, hostbuf, sizeof (hostbuf), - servbuf, sizeof (servbuf), - NI_NUMERICHOST | NI_NUMERICSERV); - if (val) - printf ("%s: %s\n", str, gai_strerror (val)); - else - printf ("%s: %s port %s\n", str, hostbuf, servbuf); -} - - -/** Various responses test */ -static void test_turn (char *username, char *password, char *hostname, int port) -{ - struct sockaddr_storage addr; - socklen_t addrlen = sizeof (addr); - struct sockaddr_storage alternate_addr; - socklen_t alternate_addrlen = sizeof (alternate_addr); - struct sockaddr_storage relay_addr; - socklen_t relay_addrlen = sizeof (relay_addr); - ssize_t val; - size_t len; - int fd; - uint8_t buf[STUN_MAX_MESSAGE_SIZE]; - uint8_t req[STUN_MAX_MESSAGE_SIZE]; - uint8_t refresh[STUN_MAX_MESSAGE_SIZE]; - size_t req_len; - StunAgent agent; - StunMessage msg; - StunMessage req_msg; - StunMessage refresh_msg; - uint32_t bandwidth, lifetime; - struct addrinfo hints, *res; - int ret = -1; - - memset (&hints, 0, sizeof (hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = 0; - - ret = getaddrinfo (hostname, port, &hints, &res); - assert (ret == 0); - - stun_agent_init (&agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS); - - /* Allocate a client socket and connect to server */ - fd = socket (AF_INET, SOCK_DGRAM, 0); - assert (fd != -1); - - val = connect (fd,res->ai_addr, res->ai_addrlen); -#ifdef G_OS_WIN32 - assert (val == 0 || (WSAGetLastError () == WSAEINPROGRESS)); -#else - assert (val == 0 || (errno == EINPROGRESS)); -#endif - - freeaddrinfo (res); - - - /* Send old-style response */ - req_len = stun_usage_turn_create (&agent, &req_msg, req, sizeof(req), - NULL, - STUN_USAGE_TURN_REQUEST_PORT_NORMAL, - -1, -1, - username, strlen (username), password, strlen(password), - STUN_USAGE_TURN_COMPATIBILITY_DRAFT9); - assert (req_len > 0); - - val = send (fd, req, req_len, MSG_NOSIGNAL); - assert (val >= 0); - - val = recv (fd, buf, 1000, 0); - assert (val >= 0); - - assert (stun_agent_validate (&agent, &msg, buf, val, NULL, NULL) - == STUN_VALIDATION_SUCCESS); - - val = stun_usage_turn_process (&msg, - (struct sockaddr *)&relay_addr, &relay_addrlen, - (struct sockaddr *)&addr, &addrlen, - (struct sockaddr *)&alternate_addr, &alternate_addrlen, - &bandwidth, &lifetime, - STUN_USAGE_TURN_COMPATIBILITY_DRAFT9); - assert (val == STUN_USAGE_TURN_RETURN_ERROR); - - req_len = stun_usage_turn_create (&agent, &req_msg, req, sizeof(req), - &msg, - STUN_USAGE_TURN_REQUEST_PORT_NORMAL, - -1, -1, - username, strlen (username), password, strlen(password), - STUN_USAGE_TURN_COMPATIBILITY_DRAFT9); - assert (req_len > 0); - - val = send (fd, req, req_len, MSG_NOSIGNAL); - assert (val >= 0); - - val = recv (fd, buf, 1000, 0); - assert (val >= 0); - - assert (stun_agent_validate (&agent, &msg, buf, val, NULL, NULL) - == STUN_VALIDATION_SUCCESS); - - val = stun_usage_turn_process (&msg, - (struct sockaddr *)&relay_addr, &relay_addrlen, - (struct sockaddr *)&addr, &addrlen, - (struct sockaddr *)&alternate_addr, &alternate_addrlen, - &bandwidth, &lifetime, - STUN_USAGE_TURN_COMPATIBILITY_DRAFT9); - assert (val == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS); - - printaddr ("Relay address found : ", (struct sockaddr *)&relay_addr, relay_addrlen); - printaddr ("Mapped address found : ",(struct sockaddr *) &addr, addrlen); - - - req_len = stun_usage_turn_create_refresh (&agent, &refresh_msg, refresh, - sizeof(refresh), &req_msg, 0, username, strlen (username), - password, strlen(password),STUN_USAGE_TURN_COMPATIBILITY_DRAFT9); - assert (req_len > 0); - - val = send (fd, refresh, req_len, MSG_NOSIGNAL); - assert (val >= 0); - - val = recv (fd, buf, 1000, 0); - assert (val >= 0); - - assert (stun_agent_validate (&agent, &msg, buf, val, NULL, NULL) - == STUN_VALIDATION_SUCCESS); - - val = close (fd); - assert (val == 0); -} - -static void turnserver (void) -{ - test_turn ("toto", "password", "127.0.0.1", "3478"); -} - -static void numb (void) -{ - test_turn ("youness.alaoui@collabora.co.uk", "badger", "numb.viagenie.ca", "3478"); -} - -static void test (void (*func) (void), const char *name) -{ - alarm (10); - - printf ("%s test... ", name); - func (); - puts ("OK"); -} - - -int main (void) -{ - test (turnserver, "Testing TURN"); - test (numb, "Testing numb"); - return 0; -} diff --git a/stun/tools/Makefile.am b/stun/tools/Makefile.am deleted file mode 100644 index c945650..0000000 --- a/stun/tools/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2006, 2007 Collabora Ltd. -# (C) 2006, 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. -# - -include $(top_srcdir)/common.mk -AM_CFLAGS = -std=gnu99 $(LIBNICE_CFLAGS) -AM_CPPFLAGS = -I$(top_srcdir) - -bin_PROGRAMS = stunbdc stund - -check_PROGRAMS = stund - -stund_SOURCES = stund.c stund.h -stund_LDADD = $(top_builddir)/stun/libstun.la - -stunbdc_SOURCES = stunbdc.c - -stunbdc_LDADD = $(top_builddir)/stun/libstun.la - - -if WINDOWS - AM_CFLAGS += -DWINVER=0x0501 # _WIN32_WINNT_WINXP - stunbdc_LDADD += -lws2_32 -endif - -EXTRA_DIST = meson.build diff --git a/stun/tools/meson.build b/stun/tools/meson.build deleted file mode 100644 index 0949e10..0000000 --- a/stun/tools/meson.build +++ /dev/null @@ -1,10 +0,0 @@ -stund_exe = executable('stund', 'stund.c', - include_directories: nice_incs, - link_with: libstun, - install: true) - -stunbdc_exe = executable('stunbdc', 'stunbdc.c', - include_directories: nice_incs, - dependencies: syslibs, - link_with: libstun, - install: true) diff --git a/stun/tools/stunbdc.c b/stun/tools/stunbdc.c deleted file mode 100644 index fd0f77f..0000000 --- a/stun/tools/stunbdc.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef _WIN32 -# include -#else -# include -# include -#endif - -#include -#include "stun/stunagent.h" -#include "stun/usages/bind.h" - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include -#include -#include - -static int ai_flags = 0; - -static void -printaddr (const char *str, const struct sockaddr *addr, socklen_t addrlen) -{ - char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV]; - - int val = getnameinfo (addr, addrlen, hostbuf, sizeof (hostbuf), - servbuf, sizeof (servbuf), - NI_NUMERICHOST | NI_NUMERICSERV); - if (val) - printf ("%s: %s\n", str, gai_strerror (val)); - else - printf ("%s: %s port %s\n", str, hostbuf, servbuf); -} - - - -static int run (int family, const char *hostname, const char *service) -{ - struct addrinfo hints, *res; - const struct addrinfo *ptr; - int ret = -1; - - memset (&hints, 0, sizeof (hints)); - hints.ai_family = family; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = ai_flags; - if (service == NULL) - service = "3478"; - - ret = getaddrinfo (hostname, service, &hints, &res); - if (ret) - { - fprintf (stderr, "%s (port %s): %s\n", hostname, service, - gai_strerror (ret)); - return -1; - } - - for (ptr = res; ptr != NULL; ptr = ptr->ai_next) - { - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } addr; - socklen_t addrlen = sizeof (addr); - StunUsageBindReturn val; - - printaddr ("Server address", ptr->ai_addr, ptr->ai_addrlen); - - val = stun_usage_bind_run (ptr->ai_addr, ptr->ai_addrlen, &addr.storage, - &addrlen); - if (val) - fprintf (stderr, "%d\n", val); - else - { - printaddr ("Mapped address", &addr.addr, addrlen); - ret = 0; - } - } - - freeaddrinfo (res); - return ret; -} - - -int main (int argc, char *argv[]) -{ - const char *server = NULL, *port = NULL; - int family = AF_UNSPEC; - int i; - int result; - -#ifdef _WIN32 - WSADATA w; - WSAStartup (0x0202, &w); -#endif - - for (i = 1; i < argc; ++i) - { - const char *arg = argv[i]; - - if (arg[0] != '-') - break; - - if (strcmp (arg, "--ipv4") == 0 || strcmp (arg, "-4") == 0) - { - family = AF_INET; - } - else if (strcmp (arg, "--ipv6") == 0 || strcmp (arg, "-6") == 0) - { - family = AF_INET6; - } - else if (strcmp (arg, "--help") == 0 || strcmp (arg, "-h") == 0) - { - printf ("Usage: %s [-4|-6] [port number]\n" - "Performs STUN Binding Discovery\n" - "\n" - " -4, --ipv4 Force IP version 4\n" - " -6, --ipv6 Force IP version 6\n" - " -n, --numeric Server in numeric form\n" - "\n", argv[0]); - return 0; - } - else if (strcmp (arg, "--numeric") == 0 || strcmp (arg, "-n") == 0) - { - ai_flags |= AI_NUMERICHOST; - } - else if (strcmp (arg, "--version") == 0 || strcmp (arg, "-V") == 0) - { - printf ("stunbcd: STUN Binding Discovery client (%s v%s)\n", - PACKAGE, VERSION); - return 0; - } else { - fprintf (stderr, "Unexpected command line argument '%s'", arg); - return 2; - } - } - - if (i < argc) - server = argv[i++]; - if (i < argc) - port = argv[i++]; - if (i < argc) - { - fprintf (stderr, "%s: extra parameter `%s'\n", argv[0], argv[i]); - return 2; - } - - result = run (family, server, port) ? 1 : 0; - -#ifdef _WIN32 - WSACleanup(); -#endif - - return result; -} diff --git a/stun/tools/stund.c b/stun/tools/stund.c deleted file mode 100644 index ed74c87..0000000 --- a/stun/tools/stund.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef __sun -#define _XPG4_2 1 -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#ifdef _WIN32 -#include -#else -#include -#include -#include -#endif - -#ifdef HAVE_UNISTD_H -# include -#else -# define close(fd) _close(fd) -#endif - -#include -#include -#include - -#ifndef SOL_IP -# define SOL_IP IPPROTO_IP -#endif - -#ifndef SOL_IPV6 -# define SOL_IPV6 IPPROTO_IPV6 -#endif - - -#ifndef IPV6_RECVPKTINFO -# define IPV6_RECVPKTINFO IPV6_PKTINFO -#endif - -/** Default port for STUN binding discovery */ -#define IPPORT_STUN 3478 - -#include "stun/stunagent.h" -#include "stund.h" - -static const uint16_t known_attributes[] = { - 0 -}; - -/* - * Creates a listening socket - */ -int listen_socket (int fam, int type, int proto, unsigned int port) -{ - int yes = 1; - int fd = socket (fam, type, proto); - union { - struct sockaddr addr; - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr_storage storage; - } addr; - - if (fd == -1) - { - perror ("Error opening IP port"); - return -1; - } - - memset (&addr, 0, sizeof (addr)); - addr.storage.ss_family = fam; -#ifdef HAVE_SA_LEN - addr.storage.ss_len = sizeof (addr); -#endif - - switch (fam) - { - case AF_INET: - addr.in.sin_port = htons (port); - break; - - case AF_INET6: -#ifdef IPV6_V6ONLY - setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, (const char *) &yes, sizeof (yes)); -#endif - addr.in6.sin6_port = htons (port); - break; - - default: - assert (0); /* should never be reached */ - } - - if (bind (fd, &addr.addr, sizeof (struct sockaddr_storage))) - { - perror ("Error opening IP port"); - goto error; - } - - if ((type == SOCK_DGRAM) || (type == SOCK_RAW)) - { - switch (fam) - { - case AF_INET: -#ifdef IP_RECVERR - setsockopt (fd, SOL_IP, IP_RECVERR, (const char*) &yes, sizeof (yes)); -#endif - break; - - case AF_INET6: -#ifdef IPV6_RECVERR - setsockopt (fd, SOL_IPV6, IPV6_RECVERR, (const char*) &yes, sizeof (yes)); -#endif - break; - - default: - assert (0); /* should never be reached */ - } - } - else - { - if (listen (fd, INT_MAX)) - { - perror ("Error opening IP port"); - goto error; - } - } - - return fd; - -error: - close (fd); - return -1; -} - -static int dgram_process (int sock, StunAgent *oldagent, StunAgent *newagent) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } addr; - socklen_t addr_len; - uint8_t buf[STUN_MAX_MESSAGE_SIZE]; - size_t buf_len = 0; - size_t len = 0; - StunMessage request; - StunMessage response; - StunValidationStatus validation; - StunAgent *agent = NULL; - - addr_len = sizeof (struct sockaddr_storage); - len = recvfrom (sock, buf, sizeof(buf), 0, &addr.addr, &addr_len); - if (len == (size_t)-1) - return -1; - - validation = stun_agent_validate (newagent, &request, buf, len, NULL, 0); - - if (validation == STUN_VALIDATION_SUCCESS) { - agent = newagent; - } - else { - validation = stun_agent_validate (oldagent, &request, buf, len, NULL, 0); - agent = oldagent; - } - - /* Unknown attributes */ - if (validation == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE) - { - buf_len = stun_agent_build_unknown_attributes_error (agent, &response, buf, - sizeof (buf), &request); - goto send_buf; - } - - /* Mal-formatted packets */ - if (validation != STUN_VALIDATION_SUCCESS || - stun_message_get_class (&request) != STUN_REQUEST) { - return -1; - } - - switch (stun_message_get_method (&request)) - { - case STUN_BINDING: - stun_agent_init_response (agent, &response, buf, sizeof (buf), &request); - if (stun_message_has_cookie (&request)) - stun_message_append_xor_addr (&response, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &addr.storage, addr_len); - else - stun_message_append_addr (&response, STUN_ATTRIBUTE_MAPPED_ADDRESS, - &addr.addr, addr_len); - break; - - case STUN_SHARED_SECRET: - case STUN_ALLOCATE: - case STUN_SEND: - case STUN_CONNECT: - case STUN_IND_SEND: - case STUN_IND_DATA: - case STUN_CREATEPERMISSION: - case STUN_CHANNELBIND: - default: - if (!stun_agent_init_error (agent, &response, buf, sizeof (buf), - &request, STUN_ERROR_BAD_REQUEST)) - return -1; - } - - buf_len = stun_agent_finish_message (agent, &response, NULL, 0); -send_buf: - len = sendto (sock, buf, buf_len, 0, &addr.addr, addr_len); - return (len < buf_len) ? -1 : 0; -} - - -static int run (int family, int protocol, unsigned port) -{ - StunAgent oldagent; - StunAgent newagent; - int sock = listen_socket (family, SOCK_DGRAM, protocol, port); - if (sock == -1) - return -1; - - stun_agent_init (&oldagent, known_attributes, - STUN_COMPATIBILITY_RFC3489, 0); - stun_agent_init (&newagent, known_attributes, - STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT); - - for (;;) - dgram_process (sock, &oldagent, &newagent); -} - - -/* Pretty useless dummy signal handler... - * But calling exit() is needed for gcov to work properly. */ -static void exit_handler (int signum) -{ - (void)signum; - exit (0); -} - - -int main (int argc, char *argv[]) -{ - int family = AF_INET; - unsigned port = IPPORT_STUN; - int i; - - -#ifdef _WIN32 - WSADATA wsadata; - - if (WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) { - fprintf(stderr, "Could not start Winsock2"); - return 1; - } - -#endif - - - for (i = 1; i < argc; ++i) - { - const char *arg = argv[i]; - - if (strcmp (arg, "-4") == 0) - { - family = AF_INET; - } - else if (strcmp (arg, "-6") == 0) - { - family = AF_INET6; - } - else if (arg[0] < '0' || arg[0] > '9') - { - fprintf (stderr, "Unexpected command line argument '%s'", arg); - } - else - { - port = atoi (arg); - break; - } - } - - signal (SIGINT, exit_handler); - signal (SIGTERM, exit_handler); - return run (family, IPPROTO_UDP, port) ? EXIT_FAILURE : EXIT_SUCCESS; -} - diff --git a/stun/tools/stund.h b/stun/tools/stund.h deleted file mode 100644 index 2ce5203..0000000 --- a/stun/tools/stund.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef NICE_STUN_STUND_H -# define NICE_STUN_STUND_H 1 - -int listen_socket (int fam, int type, int proto, unsigned port); -ssize_t send_safe (int fd, const struct msghdr *msg); -ssize_t recv_safe (int fd, struct msghdr *msg); - -#endif diff --git a/stun/usages/bind.c b/stun/usages/bind.c deleted file mode 100644 index 504bd89..0000000 --- a/stun/usages/bind.c +++ /dev/null @@ -1,594 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef _WIN32 -#include -#include -#include "win32_common.h" -#define close closesocket -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - - -#ifdef HAVE_POLL -# include -#endif - - -#include "bind.h" -#include "stun/stunagent.h" - -#include -#include -#include -#include -#include -#include "timer.h" - - -#ifndef SOL_IP -# define SOL_IP IPPROTO_IP -#endif - -#ifndef SOL_IPV6 -# define SOL_IPV6 IPPROTO_IPV6 -#endif - - -/** Non-blocking mode STUN binding discovery */ - -size_t stun_usage_bind_create (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len) -{ - stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_BINDING); - - return stun_agent_finish_message (agent, msg, NULL, 0); -} - -StunUsageBindReturn stun_usage_bind_process (StunMessage *msg, - struct sockaddr *addr, socklen_t *addrlen, - struct sockaddr *alternate_server, socklen_t *alternate_server_len) -{ - int code = -1; - StunMessageReturn val; - union { - struct sockaddr *sa; - struct sockaddr_storage *sas; - } sa; - - sa.sa = addr; - - if (stun_message_get_method (msg) != STUN_BINDING) - return STUN_USAGE_BIND_RETURN_INVALID; - - switch (stun_message_get_class (msg)) - { - case STUN_REQUEST: - case STUN_INDICATION: - return STUN_USAGE_BIND_RETURN_INVALID; - - case STUN_RESPONSE: - break; - - case STUN_ERROR: - if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) { - /* missing ERROR-CODE: ignore message */ - return STUN_USAGE_BIND_RETURN_INVALID; - } - - /* NOTE: currently we ignore unauthenticated messages if the context - * is authenticated, for security reasons. */ - stun_debug (" STUN error message received (code: %d)", code); - - /* ALTERNATE-SERVER mechanism */ - if ((code / 100) == 3) { - union { - struct sockaddr *sa; - struct sockaddr_storage *sas; - } alternate_sa; - - alternate_sa.sa = alternate_server; - if (alternate_server && alternate_server_len) { - if (stun_message_find_addr (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER, - alternate_sa.sas, - alternate_server_len) != STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute"); - return STUN_USAGE_BIND_RETURN_ERROR; - } - } else { - if (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER)) { - stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute"); - return STUN_USAGE_BIND_RETURN_ERROR; - } - } - - stun_debug ("Found alternate server"); - return STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER; - - } - return STUN_USAGE_BIND_RETURN_ERROR; - - default: - /* Fall through. */ - break; - } - - stun_debug ("Received %u-bytes STUN message", stun_message_length (msg)); - - val = stun_message_find_xor_addr (msg, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, sa.sas, - addrlen); - if (val != STUN_MESSAGE_RETURN_SUCCESS) - { - stun_debug (" No XOR-MAPPED-ADDRESS: %d", val); - val = stun_message_find_addr (msg, - STUN_ATTRIBUTE_MAPPED_ADDRESS, sa.sas, - addrlen); - if (val != STUN_MESSAGE_RETURN_SUCCESS) - { - stun_debug (" No MAPPED-ADDRESS: %d", val); - return STUN_USAGE_BIND_RETURN_ERROR; - } - } - - stun_debug (" Mapped address found!"); - return STUN_USAGE_BIND_RETURN_SUCCESS; - -} - - -/** Binding keep-alive (Binding discovery indication!) */ - -size_t -stun_usage_bind_keepalive (StunAgent *agent, StunMessage *msg, - uint8_t *buf, size_t len) -{ - - stun_agent_init_indication (agent, msg, - buf, len, STUN_BINDING); - return stun_agent_finish_message (agent, msg, NULL, 0); -} - - - -typedef struct stun_trans_s -{ - - int fd; - int own_fd; - socklen_t dstlen; - struct sockaddr_storage dst; -} StunTransport; - - -typedef enum { - STUN_USAGE_TRANS_RETURN_SUCCESS, - STUN_USAGE_TRANS_RETURN_ERROR, - STUN_USAGE_TRANS_RETURN_RETRY, - STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS, - STUN_USAGE_TRANS_RETURN_UNSUPPORTED, -} StunUsageTransReturn; - - - - -static StunUsageTransReturn -stun_trans_init (StunTransport *tr, int fd, - const struct sockaddr *srv, socklen_t srvlen) -{ - assert (fd != -1); - - if ((size_t) srvlen > sizeof (tr->dst)) - return STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS; - - tr->own_fd = -1; - tr->fd = fd; - - tr->dstlen = srvlen; - memcpy (&tr->dst, srv, srvlen); - - return STUN_USAGE_TRANS_RETURN_SUCCESS; -} - - -/* - * Creates and connects a socket. This is useful when a socket is to be used - * for multiple consecutive transactions (e.g. TURN). - */ -static int stun_socket (int family, int type, int proto) -{ -#ifdef _WIN32 - unsigned long set_nonblock=1; -#endif - - int fd = socket (family, type, proto); - if (fd == -1) - return -1; - -#ifdef FD_CLOEXEC - fcntl (fd, F_SETFD, fcntl (fd, F_GETFD) | FD_CLOEXEC); -#endif -#ifdef O_NONBLOCK - fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK); -#elif defined _WIN32 - ioctlsocket(fd, FIONBIO, &set_nonblock); -#endif - -#ifdef MSG_ERRQUEUE - if (type == SOCK_DGRAM) - { - /* Linux specifics for ICMP errors on non-connected sockets */ - int yes = 1; - switch (family) - { - case AF_INET: - setsockopt (fd, SOL_IP, IP_RECVERR, &yes, sizeof (yes)); - break; - case AF_INET6: - setsockopt (fd, SOL_IPV6, IPV6_RECVERR, &yes, sizeof (yes)); - break; - default: - /* Nothing to do. */ - break; - } - } -#endif - - return fd; -} - - -static StunUsageTransReturn -stun_trans_create (StunTransport *tr, int type, int proto, - const struct sockaddr *srv, socklen_t srvlen) -{ - StunUsageTransReturn val = STUN_USAGE_TRANS_RETURN_ERROR; - int fd; - - if ((size_t) srvlen < sizeof(*srv)) - return STUN_USAGE_TRANS_RETURN_INVALID_ADDRESS; - - fd = stun_socket (srv->sa_family, type, proto); - if (fd == -1) - return STUN_USAGE_TRANS_RETURN_ERROR; - - if (type != SOCK_DGRAM) { - if (connect (fd, srv, srvlen) && -#ifdef _WIN32 - (WSAGetLastError () != WSAEINPROGRESS)) { -#else - (errno != EINPROGRESS)) { -#endif - goto error; - } - val = stun_trans_init (tr, fd, NULL, 0); - } else { - val = stun_trans_init (tr, fd, srv, srvlen); - } - - if (val) - goto error; - - tr->own_fd = tr->fd; - return STUN_USAGE_TRANS_RETURN_SUCCESS; - -error: - close (fd); - return val; -} - - -static void stun_trans_deinit (StunTransport *tr) -{ - int saved = errno; - - assert (tr->fd != -1); - - if (tr->own_fd != -1) - close (tr->own_fd); - - tr->own_fd = -1; - tr->fd = -1; - - errno = saved; -} - - -#ifndef MSG_DONTWAIT -# define MSG_DONTWAIT 0 -#endif -#ifndef MSG_NOSIGNAL -# define MSG_NOSIGNAL 0 -#endif - - -static int stun_err_dequeue (int fd) -{ -#ifdef MSG_ERRQUEUE - struct msghdr hdr; - int saved_errno = errno, ret; - - memset (&hdr, 0, sizeof (hdr)); - ret = (recvmsg (fd, &hdr, MSG_ERRQUEUE) >= 0); - errno = saved_errno; - return ret; -#else - (void) fd; - return 0; -#endif -} - - -static ssize_t -stun_trans_sendto (StunTransport *tr, const uint8_t *buf, size_t len, - const struct sockaddr *dst, socklen_t dstlen) -{ - static const int flags = MSG_DONTWAIT | MSG_NOSIGNAL; - ssize_t val; - - do - { - if (dstlen > 0) - val = sendto (tr->fd, (void *)buf, len, flags, dst, dstlen); - else - val = send (tr->fd, (void *)buf, len, flags); - } - while ((val == -1) && stun_err_dequeue (tr->fd)); - - return val; -} - - -static ssize_t -stun_trans_recvfrom (StunTransport *tr, uint8_t *buf, size_t maxlen, - struct sockaddr_storage * dst, - socklen_t * dstlen) -{ - static const int flags = MSG_DONTWAIT | MSG_NOSIGNAL; - ssize_t val; - - if (dstlen != NULL) - val = recvfrom (tr->fd, (void *)buf, maxlen, flags, (struct sockaddr *) dst, - dstlen); - else - val = recv (tr->fd, (void *)buf, maxlen, flags); - - if (val == -1) - stun_err_dequeue (tr->fd); - - return val; -} - - -static ssize_t -stun_trans_send (StunTransport *tr, const uint8_t *buf, size_t len) -{ - struct sockaddr *conv; - - conv = (struct sockaddr *) &tr->dst; - - return stun_trans_sendto (tr, buf, len, conv, tr->dstlen); -} - -static ssize_t -stun_trans_recv (StunTransport *tr, uint8_t *buf, size_t maxlen) -{ - return stun_trans_recvfrom (tr, buf, maxlen, NULL, NULL); -} - - -#ifdef HAVE_POLL -static int stun_trans_fd (const StunTransport *tr) -{ - assert (tr != NULL); - return tr->fd; -} -#endif - - -/* - * Waits for a response or timeout to occur. - * - * @return ETIMEDOUT if the transaction has timed out, or 0 if an incoming - * message needs to be processed. - */ -static StunUsageTransReturn -stun_trans_poll (StunTransport *tr, unsigned int delay) -{ -#ifdef HAVE_POLL - struct pollfd ufd; - - memset (&ufd, 0, sizeof (ufd)); - ufd.fd = stun_trans_fd (tr); - - ufd.events |= POLLIN; - - if (poll (&ufd, 1, delay) <= 0) { - return STUN_USAGE_TRANS_RETURN_RETRY; - } - - return STUN_USAGE_TRANS_RETURN_SUCCESS; -#else - (void)tr; - return STUN_USAGE_TRANS_RETURN_UNSUPPORTED; -#endif -} - - - -/** Blocking mode STUN binding discovery */ -StunUsageBindReturn stun_usage_bind_run (const struct sockaddr *srv, - socklen_t srvlen, struct sockaddr_storage *addr, socklen_t *addrlen) -{ - StunTimer timer; - StunTransport trans; - StunAgent agent; - StunMessage req; - uint8_t req_buf[STUN_MAX_MESSAGE_SIZE]; - StunMessage msg; - uint8_t buf[STUN_MAX_MESSAGE_SIZE]; - StunValidationStatus valid; - size_t len; - StunUsageTransReturn ret; - int val; - struct sockaddr_storage alternate_server = { AF_UNSPEC } ; - socklen_t alternate_server_len = sizeof (alternate_server); - StunUsageBindReturn bind_ret; - - trans.fd = -1; - - stun_agent_init (&agent, STUN_ALL_KNOWN_ATTRIBUTES, - STUN_COMPATIBILITY_RFC3489, 0); - - len = stun_usage_bind_create (&agent, &req, req_buf, sizeof(req_buf)); - - ret = stun_trans_create (&trans, SOCK_DGRAM, 0, srv, srvlen); - if (ret != STUN_USAGE_TRANS_RETURN_SUCCESS) { - stun_debug ("STUN transaction failed: couldn't create transport."); - bind_ret = STUN_USAGE_BIND_RETURN_ERROR; - goto done; - } - - val = stun_trans_send (&trans, req_buf, len); - if (val < -1) { - stun_debug ("STUN transaction failed: couldn't send request."); - bind_ret = STUN_USAGE_BIND_RETURN_ERROR; - goto done; - } - - stun_timer_start (&timer, STUN_TIMER_DEFAULT_TIMEOUT, - STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS); - stun_debug ("STUN transaction started (timeout %dms).", - stun_timer_remainder (&timer)); - - do - { - for (;;) { - unsigned delay = stun_timer_remainder (&timer); - ret = stun_trans_poll (&trans, delay); - if (ret == STUN_USAGE_TRANS_RETURN_RETRY) { - switch (stun_timer_refresh (&timer)) { - case STUN_USAGE_TIMER_RETURN_TIMEOUT: - stun_debug ("STUN transaction failed: time out."); - bind_ret = STUN_USAGE_BIND_RETURN_TIMEOUT; // fatal error! - goto done; - case STUN_USAGE_TIMER_RETURN_RETRANSMIT: - stun_debug ("STUN transaction retransmitted (timeout %dms).", - stun_timer_remainder (&timer)); - val = stun_trans_send (&trans, req_buf, len); - if (val < -1) { - stun_debug ("STUN transaction failed: couldn't resend request."); - bind_ret = STUN_USAGE_BIND_RETURN_ERROR; - goto done; - } - continue; - case STUN_USAGE_TIMER_RETURN_SUCCESS: - default: - /* Fall through. */ - break; - } - } - val = stun_trans_recv (&trans, buf, sizeof (buf)); - if (val >= 0) { - break; - } - } - - valid = stun_agent_validate (&agent, &msg, buf, val, NULL, NULL); - if (valid == STUN_VALIDATION_UNKNOWN_ATTRIBUTE) - { - bind_ret = STUN_USAGE_BIND_RETURN_ERROR; - goto done; - } - - if (valid != STUN_VALIDATION_SUCCESS) { - ret = STUN_USAGE_TRANS_RETURN_RETRY; - } else { - bind_ret = stun_usage_bind_process (&msg, (struct sockaddr *) addr, - addrlen, (struct sockaddr *) &alternate_server, &alternate_server_len); - if (bind_ret == STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER) { - stun_trans_deinit (&trans); - - assert (alternate_server.ss_family != AF_UNSPEC); - - ret = stun_trans_create (&trans, SOCK_DGRAM, 0, - (struct sockaddr *) &alternate_server, alternate_server_len); - - if (ret != STUN_USAGE_TRANS_RETURN_SUCCESS) { - bind_ret = STUN_USAGE_BIND_RETURN_ERROR; - goto done; - } - - val = stun_trans_send (&trans, req_buf, len); - if (val < -1) - { - bind_ret = STUN_USAGE_BIND_RETURN_ERROR; - goto done; - } - - stun_timer_start (&timer, STUN_TIMER_DEFAULT_TIMEOUT, - STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS); - ret = STUN_USAGE_TRANS_RETURN_RETRY; - } else if (bind_ret == STUN_USAGE_BIND_RETURN_INVALID) { - ret = STUN_USAGE_TRANS_RETURN_RETRY; - } else { - break; - } - } - } - while (ret == STUN_USAGE_TRANS_RETURN_RETRY); - -done: - if (trans.fd != -1) - stun_trans_deinit (&trans); - - return bind_ret; -} diff --git a/stun/usages/bind.h b/stun/usages/bind.h deleted file mode 100644 index 500f9fe..0000000 --- a/stun/usages/bind.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef STUN_BIND_H -# define STUN_BIND_H 1 - -/** - * SECTION:bind - * @short_description: STUN Binding Usage - * @include: stun/usages/bind.h - * @stability: Stable - * - * The STUN Binding usage allows for easily creating and parsing STUN Binding - * requests and responses. It offers both an asynchronous and a synchronous API - * that uses the STUN timer usage. - */ - - -#ifdef _WIN32 -# include "../win32_common.h" -#else -# include -# include -#endif - -# include "stun/stunagent.h" - -# ifdef __cplusplus -extern "C" { -# endif - -/** - * StunUsageBindReturn: - * @STUN_USAGE_BIND_RETURN_SUCCESS: The binding usage succeeded - * @STUN_USAGE_BIND_RETURN_ERROR: There was an unknown error in the bind usage - * @STUN_USAGE_BIND_RETURN_INVALID: The message is invalid and should be ignored - * @STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER: The binding request has an - * ALTERNATE-SERVER attribute - * @STUN_USAGE_BIND_RETURN_TIMEOUT: The binding was unsuccessful because it has - * timed out. - * - * Return value of stun_usage_bind_process() and stun_usage_bind_run() which - * allows you to see what status the function call returned. - */ -typedef enum { - STUN_USAGE_BIND_RETURN_SUCCESS, - STUN_USAGE_BIND_RETURN_ERROR, - STUN_USAGE_BIND_RETURN_INVALID, - STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER, - STUN_USAGE_BIND_RETURN_TIMEOUT, -} StunUsageBindReturn; - - -/** - * stun_usage_bind_create: - * @agent: The #StunAgent to use to create the binding request - * @msg: The #StunMessage to build - * @buffer: The buffer to use for creating the #StunMessage - * @buffer_len: The size of the @buffer - * - * Create a new STUN binding request to use with a STUN server. - * Returns: The length of the built message. - */ -size_t stun_usage_bind_create (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len); - -/** - * stun_usage_bind_process: - * @msg: The #StunMessage to process - * @addr: A pointer to a #sockaddr structure to fill with the mapped address - * that the STUN server gives us - * @addrlen: The length of @add. rMust be set to the size of the @addr socket - * address and will be set to the actual length of the socket address. - * @alternate_server: A pointer to a #sockaddr structure to fill with the - * address of an alternate server to which we should send our new STUN - * binding request, in case the currently used STUN server is requesting the use - * of an alternate server. This argument will only be filled if the return value - * of the function is #STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER - * @alternate_server_len: The length of @alternate_server. Must be set to - * the size of the @alternate_server socket address and will be set to the - * actual length of the socket address. - * - * Process a STUN binding response and extracts the mapped address from the STUN - * message. Also checks for the ALTERNATE-SERVER attribute. - * Returns: A #StunUsageBindReturn value. - * Note that #STUN_USAGE_BIND_RETURN_TIMEOUT cannot be returned by this function - */ -StunUsageBindReturn stun_usage_bind_process (StunMessage *msg, - struct sockaddr *addr, socklen_t *addrlen, - struct sockaddr *alternate_server, socklen_t *alternate_server_len); - -/** - * stun_usage_bind_keepalive: - * @agent: The #StunAgent to use to build the message - * @msg: The #StunMessage to build - * @buf: The buffer to use for creating the #StunMessage - * @len: The size of the @buf - * - * Creates a STUN binding indication that can be used for a keepalive. - * Since this is an indication message, no STUN response will be generated - * and it can only be used as a keepalive message. - * Returns: The length of the message to send - */ -size_t stun_usage_bind_keepalive (StunAgent *agent, StunMessage *msg, - uint8_t *buf, size_t len); - -/** - * stun_usage_bind_run: - * @srv: A pointer to the #sockaddr structure representing the STUN server's - * address - * @srvlen: The length of @srv - * @addr: A pointer to a #sockaddr structure to fill with the mapped address - * that the STUN server gives us - * @addrlen: The length of @addr - * - * This is a convenience function that will do a synchronous Binding request to - * a server and wait for its answer. It will create the socket transports and - * use the #StunTimer usage to send the request and handle the response. - * Returns: A #StunUsageBindReturn. - * Possible return values are #STUN_USAGE_BIND_RETURN_SUCCESS, - * #STUN_USAGE_BIND_RETURN_ERROR and #STUN_USAGE_BIND_RETURN_TIMEOUT - */ -StunUsageBindReturn stun_usage_bind_run (const struct sockaddr *srv, - socklen_t srvlen, struct sockaddr_storage *addr, socklen_t *addrlen); - -# ifdef __cplusplus -} -# endif - -#endif diff --git a/stun/usages/ice.c b/stun/usages/ice.c deleted file mode 100644 index 2d76ff0..0000000 --- a/stun/usages/ice.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include - -#ifdef _WIN32 -#include -#else -#include -#include -#include -#endif - - -#include "stunagent.h" - -/** ICE connectivity checks **/ -#include "ice.h" - - -size_t -stun_usage_ice_conncheck_create (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, - const uint8_t *username, const size_t username_len, - const uint8_t *password, const size_t password_len, - bool cand_use, bool controlling, uint32_t priority, - uint64_t tie, const char *candidate_identifier, - StunUsageIceCompatibility compatibility) -{ - StunMessageReturn val; - - stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_BINDING); - - if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245 || - compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2) { - if (cand_use) - { - val = stun_message_append_flag (msg, STUN_ATTRIBUTE_USE_CANDIDATE); - if (val != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - val = stun_message_append32 (msg, STUN_ATTRIBUTE_PRIORITY, priority); - if (val != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - - if (controlling) - val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLING, tie); - else - val = stun_message_append64 (msg, STUN_ATTRIBUTE_ICE_CONTROLLED, tie); - if (val != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - if (username && username_len > 0) { - val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, - username, username_len); - if (val != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2 && - candidate_identifier) { - size_t identifier_len = strlen(candidate_identifier); - size_t attribute_len = identifier_len; - int modulo4 = identifier_len % 4; - uint8_t* buf; - - if (modulo4) - attribute_len += 4 - modulo4; - - // Avoid a coverify false positive - assert (attribute_len >= identifier_len); - buf = malloc(attribute_len); - memset(buf, 0, attribute_len); - memcpy(buf, candidate_identifier, identifier_len); - - val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER, - buf, attribute_len); - - free(buf); - - if (val != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - - val = stun_message_append32 (msg, - STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION, 2); - - if (val != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - return stun_agent_finish_message (agent, msg, password, password_len); - -} - - -StunUsageIceReturn stun_usage_ice_conncheck_process (StunMessage *msg, - struct sockaddr_storage *addr, socklen_t *addrlen, - StunUsageIceCompatibility compatibility) -{ - int code = -1; - StunMessageReturn val; - - if (stun_message_get_method (msg) != STUN_BINDING) - return STUN_USAGE_ICE_RETURN_INVALID; - - switch (stun_message_get_class (msg)) - { - case STUN_REQUEST: - case STUN_INDICATION: - return STUN_USAGE_ICE_RETURN_INVALID; - - case STUN_RESPONSE: - break; - - case STUN_ERROR: - default: - if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) { - /* missing ERROR-CODE: ignore message */ - return STUN_USAGE_ICE_RETURN_INVALID; - } - - if (code == STUN_ERROR_ROLE_CONFLICT) - return STUN_USAGE_ICE_RETURN_ROLE_CONFLICT; - - /* NOTE: currently we ignore unauthenticated messages if the context - * is authenticated, for security reasons. */ - stun_debug (" STUN error message received (code: %d)", code); - - return STUN_USAGE_ICE_RETURN_ERROR; - } - - stun_debug ("Received %u-bytes STUN message", stun_message_length (msg)); - - if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSN) { - union { - StunTransactionId u8; - uint32_t u32[STUN_MESSAGE_TRANS_ID_LEN / 4]; - } transid; - uint32_t magic_cookie; - stun_message_id (msg, transid.u8); - magic_cookie = *(transid.u32); - - val = stun_message_find_xor_addr_full (msg, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen, htonl (magic_cookie)); - } else { - val = stun_message_find_xor_addr (msg, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen); - } - if (val != STUN_MESSAGE_RETURN_SUCCESS) - { - stun_debug (" No XOR-MAPPED-ADDRESS: %d", val); - val = stun_message_find_addr (msg, - STUN_ATTRIBUTE_MAPPED_ADDRESS, addr, addrlen); - if (val != STUN_MESSAGE_RETURN_SUCCESS) - { - stun_debug (" No MAPPED-ADDRESS: %d", val); - return STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS; - } - } - - stun_debug ("Mapped address found!"); - return STUN_USAGE_ICE_RETURN_SUCCESS; -} - -static int -stun_bind_error (StunAgent *agent, StunMessage *msg, - uint8_t *buf, size_t *plen, const StunMessage *req, - StunError code) -{ - size_t len = *plen; - int val; - - *plen = 0; - stun_debug ("STUN Error Reply (buffer size: %u)...", (unsigned)len); - - val = stun_agent_init_error (agent, msg, buf, len, req, code); - if (!val) - return val; - - len = stun_agent_finish_message (agent, msg, NULL, 0); - if (len == 0) - return 0; - - *plen = len; - stun_debug (" Error response (%u) of %u bytes", (unsigned)code, - (unsigned)*plen); - return 1; -} - -StunUsageIceReturn -stun_usage_ice_conncheck_create_reply (StunAgent *agent, StunMessage *req, - StunMessage *msg, uint8_t *buf, size_t *plen, - const struct sockaddr_storage *src, socklen_t srclen, - bool *control, uint64_t tie, - StunUsageIceCompatibility compatibility) -{ - const char *username = NULL; - uint16_t username_len; - size_t len = *plen; - uint64_t q; - StunMessageReturn val = STUN_MESSAGE_RETURN_SUCCESS; - StunUsageIceReturn ret = STUN_USAGE_ICE_RETURN_SUCCESS; - - -#define err( code ) \ - stun_bind_error (agent, msg, buf, &len, req, code); \ - *plen = len - - *plen = 0; - stun_debug ("STUN Reply (buffer size = %u)...", (unsigned)len); - - if (stun_message_get_class (req) != STUN_REQUEST) - { - stun_debug (" Unhandled non-request (class %u) message.", - stun_message_get_class (req)); - return STUN_USAGE_ICE_RETURN_INVALID_REQUEST; - } - - if (stun_message_get_method (req) != STUN_BINDING) - { - stun_debug (" Bad request (method %u) message.", - stun_message_get_method (req)); - err (STUN_ERROR_BAD_REQUEST); - return STUN_USAGE_ICE_RETURN_INVALID_METHOD; - } - - /* Role conflict handling */ - assert (control != NULL); - if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLING - : STUN_ATTRIBUTE_ICE_CONTROLLED, &q) == STUN_MESSAGE_RETURN_SUCCESS) - { - /* we have the ice-controlling/controlled attribute, - * and there's a role conflict - */ - stun_debug ("STUN Role Conflict detected:"); - - /* According to ICE RFC 5245, section 7.2.1.1, we consider the four - * possible cases when a role conflict is detected: two cases are - * resolved by switching role locally, and the two other cases are - * handled by responding with a STUN error. - */ - if ((tie < q && *control) || (tie >= q && !*control)) - { - stun_debug (" switching role from \"controll%s\" to \"controll%s\"", - *control ? "ing" : "ed", *control ? "ed" : "ing"); - *control = !*control; - ret = STUN_USAGE_ICE_RETURN_ROLE_CONFLICT; - } - else - { - stun_debug (" staying \"controll%s\" (sending error)", - *control ? "ing" : "ed"); - err (STUN_ERROR_ROLE_CONFLICT); - return STUN_USAGE_ICE_RETURN_ROLE_CONFLICT; - } - } else { - if (stun_message_find64 (req, *control ? STUN_ATTRIBUTE_ICE_CONTROLLED - : STUN_ATTRIBUTE_ICE_CONTROLLING, &q) != STUN_MESSAGE_RETURN_SUCCESS) - { - /* we don't have the expected ice-controlling/controlled - * attribute - */ - if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_RFC5245 || - compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2) - { - stun_debug ("STUN Role not specified by peer!"); - } - } - } - - if (stun_agent_init_response (agent, msg, buf, len, req) == FALSE) { - stun_debug ("Unable to create response"); - goto failure; - } - if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSN) { - union { - StunTransactionId transid; - uint32_t magic_cookie; - } conv; - - stun_message_id (msg, conv.transid); - - val = stun_message_append_xor_addr_full (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - src, srclen, htonl (conv.magic_cookie)); - } else if (stun_message_has_cookie (msg) && - compatibility != STUN_USAGE_ICE_COMPATIBILITY_GOOGLE) { - val = stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - src, srclen); - } else { - val = stun_message_append_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, - (struct sockaddr *) src, srclen); - } - - if (val != STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug (" Mapped address problem: %d", val); - goto failure; - } - - username = (const char *)stun_message_find (req, - STUN_ATTRIBUTE_USERNAME, &username_len); - if (username) { - val = stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, - username, username_len); - } - - if (val != STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug ("Error appending username: %d", val); - goto failure; - } - - if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSICE2) { - val = stun_message_append32 (msg, - STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION, 2); - - if (val != STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug ("Error appending implementation version: %d", val); - goto failure; - } - } - - /* the stun agent will automatically use the password of the request */ - len = stun_agent_finish_message (agent, msg, NULL, 0); - if (len == 0) - goto failure; - - *plen = len; - stun_debug (" All done (response size: %u)", (unsigned)len); - return ret; - -failure: - assert (*plen == 0); - stun_debug (" Fatal error formatting Response: %d", val); - - switch (val) - { - case STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE: - return STUN_USAGE_ICE_RETURN_MEMORY_ERROR; - case STUN_MESSAGE_RETURN_INVALID: - case STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS: - return STUN_USAGE_ICE_RETURN_INVALID_ADDRESS; - case STUN_MESSAGE_RETURN_SUCCESS: - assert (0); /* shouldn’t be reached */ - case STUN_MESSAGE_RETURN_NOT_FOUND: - default: - return STUN_USAGE_ICE_RETURN_ERROR; - } -} -#undef err - - -uint32_t stun_usage_ice_conncheck_priority (const StunMessage *msg) -{ - uint32_t value; - - if (stun_message_find32 (msg, STUN_ATTRIBUTE_PRIORITY, &value) - != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - return value; -} - - -bool stun_usage_ice_conncheck_use_candidate (const StunMessage *msg) -{ - return (stun_message_find_flag (msg, - STUN_ATTRIBUTE_USE_CANDIDATE) == STUN_MESSAGE_RETURN_SUCCESS); -} - diff --git a/stun/usages/ice.h b/stun/usages/ice.h deleted file mode 100644 index 561a0ce..0000000 --- a/stun/usages/ice.h +++ /dev/null @@ -1,240 +0,0 @@ - -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef STUN_CONNCHECK_H -# define STUN_CONNCHECK_H 1 - -/** - * SECTION:ice - * @short_description: STUN ICE Usage - * @include: stun/usages/ice.h - * @stability: Stable - * - * The STUN ICE usage allows for easily creating and parsing STUN Binding - * requests and responses used for ICE connectivity checks. The API allows you - * to create a connectivity check message, parse a response or create a reply - * to an incoming connectivity check request. - */ - -# include "stun/stunagent.h" - -# ifdef __cplusplus -extern "C" { -# endif - -/** - * StunUsageIceCompatibility: - * @STUN_USAGE_ICE_COMPATIBILITY_RFC5245: The ICE compatibility with RFC 5245 - * @STUN_USAGE_ICE_COMPATIBILITY_GOOGLE: The ICE compatibility with Google's - * implementation of ICE - * @STUN_USAGE_ICE_COMPATIBILITY_MSN: The ICE compatibility with MSN's - * implementation of ICE - * @STUN_USAGE_ICE_COMPATIBILITY_MSICE2: The ICE compatibility with [MS-ICE2] - * specification - * @STUN_USAGE_ICE_COMPATIBILITY_DRAFT19: The ICE compatibility with draft 19 - * @STUN_USAGE_ICE_COMPATIBILITY_WLM2009: An alias - * for @STUN_USAGE_ICE_COMPATIBILITY_MSICE2 - * - * This enum defines which compatibility modes this ICE usage can use - * - * @STUN_USAGE_ICE_COMPATIBILITY_DRAFT19 and - * @STUN_USAGE_ICE_COMPATIBILITY_WLM2009 are deprecated and should not be used - * in newly-written code. They are kept for compatibility reasons and represent - * the same compatibilities as @STUN_USAGE_ICE_COMPATIBILITY_RFC5245 and - * @STUN_USAGE_ICE_COMPATIBILITY_MSICE2 respectively. - */ -typedef enum { - STUN_USAGE_ICE_COMPATIBILITY_RFC5245, - STUN_USAGE_ICE_COMPATIBILITY_GOOGLE, - STUN_USAGE_ICE_COMPATIBILITY_MSN, - STUN_USAGE_ICE_COMPATIBILITY_MSICE2, - STUN_USAGE_ICE_COMPATIBILITY_DRAFT19 = STUN_USAGE_ICE_COMPATIBILITY_RFC5245, - STUN_USAGE_ICE_COMPATIBILITY_WLM2009 = STUN_USAGE_ICE_COMPATIBILITY_MSICE2, -} StunUsageIceCompatibility; - - -/** - * StunUsageIceReturn: - * @STUN_USAGE_ICE_RETURN_SUCCESS: The function succeeded - * @STUN_USAGE_ICE_RETURN_ERROR: There was an unspecified error - * @STUN_USAGE_ICE_RETURN_INVALID: The message is invalid for processing - * @STUN_USAGE_ICE_RETURN_ROLE_CONFLICT: A role conflict was detected - * @STUN_USAGE_ICE_RETURN_INVALID_REQUEST: The message is an not a request - * @STUN_USAGE_ICE_RETURN_INVALID_METHOD: The method of the request is invalid - * @STUN_USAGE_ICE_RETURN_MEMORY_ERROR: The buffer size is too small to hold - * the STUN reply - * @STUN_USAGE_ICE_RETURN_INVALID_ADDRESS: The mapped address argument has - * an invalid address family - * @STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS: The response is valid but no - * MAPPED-ADDRESS or XOR-MAPPED-ADDRESS attribute was found - * - * Return value of stun_usage_ice_conncheck_process() and - * stun_usage_ice_conncheck_create_reply() which allows you to see what - * status the function call returned. - */ -typedef enum { - STUN_USAGE_ICE_RETURN_SUCCESS, - STUN_USAGE_ICE_RETURN_ERROR, - STUN_USAGE_ICE_RETURN_INVALID, - STUN_USAGE_ICE_RETURN_ROLE_CONFLICT, - STUN_USAGE_ICE_RETURN_INVALID_REQUEST, - STUN_USAGE_ICE_RETURN_INVALID_METHOD, - STUN_USAGE_ICE_RETURN_MEMORY_ERROR, - STUN_USAGE_ICE_RETURN_INVALID_ADDRESS, - STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS, -} StunUsageIceReturn; - - -/** - * stun_usage_ice_conncheck_create: - * @agent: The #StunAgent to use to build the request - * @msg: The #StunMessage to build - * @buffer: The buffer to use for creating the #StunMessage - * @buffer_len: The size of the @buffer - * @username: The username to use in the request - * @username_len: The length of @username - * @password: The key to use for building the MESSAGE-INTEGRITY - * @password_len: The length of @password - * @cand_use: Set to %TRUE to append the USE-CANDIDATE flag to the request - * @controlling: Set to %TRUE if you are the controlling agent or set to - * %FALSE if you are the controlled agent. - * @priority: The value of the PRIORITY attribute - * @tie: The value of the tie-breaker to put in the ICE-CONTROLLED or - * ICE-CONTROLLING attribute - * @candidate_identifier: The foundation value to put in the - * CANDIDATE-IDENTIFIER attribute - * @compatibility: The compatibility mode to use for building the conncheck - * request - * - * Builds an ICE connectivity check STUN message. - * If the compatibility is not #STUN_USAGE_ICE_COMPATIBILITY_RFC5245, the - * @cand_use, @controlling, @priority and @tie arguments are not used. - * If the compatibility is not #STUN_USAGE_ICE_COMPATIBILITY_MSICE2, the - * @candidate_identifier argument is not used. - * Returns: The length of the message built. - */ -size_t -stun_usage_ice_conncheck_create (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, - const uint8_t *username, const size_t username_len, - const uint8_t *password, const size_t password_len, - bool cand_use, bool controlling, uint32_t priority, - uint64_t tie, const char *candidate_identifier, - StunUsageIceCompatibility compatibility); - - -/** - * stun_usage_ice_conncheck_process: - * @msg: The #StunMessage to process - * @addr: A pointer to a #sockaddr structure to fill with the mapped address - * that the STUN connectivity check response contains - * @addrlen: The length of @addr - * @compatibility: The compatibility mode to use for processing the conncheck - * response - * - * Process an ICE connectivity check STUN message and retrieve the - * mapped address from the message - * See also stun_usage_ice_conncheck_priority() and - * stun_usage_ice_conncheck_use_candidate() - * Returns: A #StunUsageIceReturn value - */ -StunUsageIceReturn stun_usage_ice_conncheck_process (StunMessage *msg, - struct sockaddr_storage *addr, socklen_t *addrlen, - StunUsageIceCompatibility compatibility); - -/** - * stun_usage_ice_conncheck_create_reply: - * @agent: The #StunAgent to use to build the response - * @req: The original STUN request to reply to - * @msg: The #StunMessage to build - * @buf: The buffer to use for creating the #StunMessage - * @plen: A pointer containing the size of the @buffer on input. - * Will contain the length of the message built on output. - * @src: A pointer to a #sockaddr structure containing the source address from - * which the request was received. Will be used as the mapped address in the - * response - * @srclen: The length of @addr - * @control: Set to %TRUE if you are the controlling agent or set to - * %FALSE if you are the controlled agent. - * @tie: The value of the tie-breaker to put in the ICE-CONTROLLED or - * ICE-CONTROLLING attribute - * @compatibility: The compatibility mode to use for building the conncheck - * response - * - * Tries to parse a STUN connectivity check request and builds a - * response accordingly. - - - In case of error, the @msg is filled with the appropriate error response - to be sent and the value of @plen is set to the size of that message. - If @plen has a size of 0, then no error response should be sent. - - - * Returns: A #StunUsageIceReturn value - */ -StunUsageIceReturn -stun_usage_ice_conncheck_create_reply (StunAgent *agent, StunMessage *req, - StunMessage *msg, uint8_t *buf, size_t *plen, - const struct sockaddr_storage *src, socklen_t srclen, - bool *control, uint64_t tie, - StunUsageIceCompatibility compatibility); - -/** - * stun_usage_ice_conncheck_priority: - * @msg: The #StunMessage to parse - * - * Extracts the priority from a STUN message. - * Returns: host byte order priority, or 0 if not specified. - */ -uint32_t stun_usage_ice_conncheck_priority (const StunMessage *msg); - -/** - * stun_usage_ice_conncheck_use_candidate: - * @msg: The #StunMessage to parse - * - * Extracts the USE-CANDIDATE attribute flag from a STUN message. - * Returns: %TRUE if the flag is set, %FALSE if not. - */ -bool stun_usage_ice_conncheck_use_candidate (const StunMessage *msg); - -# ifdef __cplusplus -} -# endif - -#endif diff --git a/stun/usages/timer.c b/stun/usages/timer.c deleted file mode 100644 index 3a2f2e6..0000000 --- a/stun/usages/timer.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#else -#include -#endif - -#include "timer.h" - -#include /* div() */ - -/* - * Clock used throughout the STUN code. - * STUN requires a monotonic 1kHz clock to operate properly. - */ -static void stun_gettime (struct timeval *now) -{ -#ifdef _WIN32 - FILETIME ft; - unsigned long long *time64 = (unsigned long long *) &ft; - - GetSystemTimeAsFileTime (&ft); - - /* Convert from 100s of nanoseconds since 1601-01-01 - * to Unix epoch. Yes, this is Y2038 unsafe. - */ - *time64 -= (unsigned long long) 116444736000000000; - *time64 /= 10; - - now->tv_sec = (long)(*time64 / 1000000); - now->tv_usec = *time64 % 1000000; -#else -#if defined (_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0) - struct timespec spec; - if (!clock_gettime (CLOCK_MONOTONIC, &spec)) { - now->tv_sec = spec.tv_sec; - now->tv_usec = spec.tv_nsec / 1000; - } else -#endif - { // fallback to wall clock - gettimeofday (now, NULL); - } -#endif -} - - -static void set_delay (struct timeval *ts, unsigned delay) -{ - stun_gettime (ts); - - /* Delay is in ms. */ - ts->tv_sec += delay / 1000; - ts->tv_usec += (delay % 1000) * 1000; - - while (ts->tv_usec > 1000000) - { - ts->tv_usec -= 1000000; - ts->tv_sec++; - } -} - - -void stun_timer_start (StunTimer *timer, unsigned int initial_timeout, - unsigned int max_retransmissions) -{ - timer->retransmissions = 1; - timer->delay = initial_timeout; - timer->max_retransmissions = max_retransmissions; - set_delay (&timer->deadline, timer->delay); -} - - -void stun_timer_start_reliable (StunTimer *timer, unsigned int initial_timeout) -{ - stun_timer_start (timer, initial_timeout, 0); -} - - - -unsigned stun_timer_remainder (const StunTimer *timer) -{ - unsigned delay; - struct timeval now; - - stun_gettime (&now); - if (now.tv_sec > timer->deadline.tv_sec) - return 0; - - delay = timer->deadline.tv_sec - now.tv_sec; - if ((delay == 0) && (now.tv_usec >= timer->deadline.tv_usec)) - return 0; - - delay *= 1000; - delay += ((signed)(timer->deadline.tv_usec - now.tv_usec)) / 1000; - return delay; -} - - -StunUsageTimerReturn stun_timer_refresh (StunTimer *timer) -{ - unsigned delay = stun_timer_remainder (timer); - if (delay == 0) - { - if (timer->retransmissions >= timer->max_retransmissions) - return STUN_USAGE_TIMER_RETURN_TIMEOUT; - - if (timer->retransmissions == timer->max_retransmissions - 1) - timer->delay = timer->delay / 2; - else - timer->delay = timer->delay * 2; - set_delay (&timer->deadline, timer->delay); - timer->retransmissions++; - return STUN_USAGE_TIMER_RETURN_RETRANSMIT; - } - - return STUN_USAGE_TIMER_RETURN_SUCCESS; -} diff --git a/stun/usages/timer.h b/stun/usages/timer.h deleted file mode 100644 index 17f3669..0000000 --- a/stun/usages/timer.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef STUN_TIMER_H -# define STUN_TIMER_H 1 - -/** - * SECTION:timer - * @short_description: STUN timer Usage - * @include: stun/usages/timer.h - * @stability: Stable - * - * The STUN timer usage is a set of helpful utility functions that allows you - * to easily track when a STUN message should be retransmitted or considered - * as timed out. - * - * - - Simple example on how to use the timer usage - - StunTimer timer; - unsigned remainder; - StunUsageTimerReturn ret; - - // Build the message, etc.. - ... - - // Send the message and start the timer - send(socket, request, sizeof(request)); - stun_timer_start(&timer, STUN_TIMER_DEFAULT_TIMEOUT, - STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS); - - // Loop until we get the response - for (;;) { - remainder = stun_timer_remainder(&timer); - - // Poll the socket until data is received or the timer expires - if (poll (&pollfd, 1, delay) <= 0) { - // Time out and no response was received - ret = stun_timer_refresh (&timer); - if (ret == STUN_USAGE_TIMER_RETURN_TIMEOUT) { - // Transaction timed out - break; - } else if (ret == STUN_USAGE_TIMER_RETURN_RETRANSMIT) { - // A retransmission is necessary - send(socket, request, sizeof(request)); - continue; - } else if (ret == STUN_USAGE_TIMER_RETURN_SUCCESS) { - // The refresh succeeded and nothing has to be done, continue polling - continue; - } - } else { - // We received a response, read it - recv(socket, response, sizeof(response)); - break; - } - } - - // Check if the transaction timed out or not - if (ret == STUN_USAGE_TIMER_RETURN_TIMEOUT) { - // do whatever needs to be done in that case - } else { - // Parse the response - } - - - - */ - -#ifdef _WIN32 -#include -#else -# include -# include -# include -#endif - - -/** - * StunTimer: - * - * An opaque structure representing a STUN transaction retransmission timer - */ -typedef struct stun_timer_s StunTimer; - -struct stun_timer_s { - struct timeval deadline; - unsigned delay; - unsigned retransmissions; - unsigned max_retransmissions; -}; - - -/** - * STUN_TIMER_DEFAULT_TIMEOUT: - * - * The default intial timeout to use for the timer - * This timeout is used for discovering server reflexive and relay - * candidates, and also for keepalives, and turn refreshes. - * - * This value is important because it defines how much time will be - * required to discover our local candidates, and this is an - * uncompressible delay before the agent signals that candidates - * gathering is done. - * - * The overall delay required for the discovery stun requests is - * computed as follow, with 3 retransmissions and an initial delay - * of 500ms : 500 * ( 1 + 2 + 1 ) = 2000 ms - * The timeout doubles at each retransmission, except for the last one. - */ -#define STUN_TIMER_DEFAULT_TIMEOUT 500 - -/** - * STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS: - * - * The default maximum retransmissions before declaring that the - * transaction timed out. - */ -#define STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS 3 - -/** - * STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT: - * - * The default intial timeout to use for a reliable timer - * - * The idea with this value is that stun request sent over udp or tcp - * should fail at the same time, with an initial default timeout set - * to 500ms. - */ -#define STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT 2000 - -/** - * StunUsageTimerReturn: - * @STUN_USAGE_TIMER_RETURN_SUCCESS: The timer was refreshed successfully - * and there is nothing to be done - * @STUN_USAGE_TIMER_RETURN_RETRANSMIT: The timer expired and the message - * should be retransmitted now. - * @STUN_USAGE_TIMER_RETURN_TIMEOUT: The timer expired as well as all the - * retransmissions, the transaction timed out - * - * Return value of stun_usage_timer_refresh() which provides you with status - * information on the timer. - */ -typedef enum { - STUN_USAGE_TIMER_RETURN_SUCCESS, - STUN_USAGE_TIMER_RETURN_RETRANSMIT, - STUN_USAGE_TIMER_RETURN_TIMEOUT -} StunUsageTimerReturn; - -# ifdef __cplusplus -extern "C" { -# endif - - -/** - * stun_timer_start: - * @timer: The #StunTimer to start - * @initial_timeout: The initial timeout to use before the first retransmission - * @max_retransmissions: The maximum number of transmissions before the - * #StunTimer times out - * - * Starts a STUN transaction retransmission timer. - * This should be called as soon as you send the message for the first time on - * a UDP socket. - * The timeout before the next retransmission is set to @initial_timeout, then - * each time a packet is retransmited, that timeout will be doubled, until the - * @max_retransmissions retransmissions limit is reached. - * - * To determine the total timeout value, one can use the following equation : - - total_timeout = initial_timeout * (2^(max_retransmissions + 1) - 1); - - * - * - * See also: #STUN_TIMER_DEFAULT_TIMEOUT - * - * See also: #STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS - */ -void stun_timer_start (StunTimer *timer, unsigned int initial_timeout, - unsigned int max_retransmissions); - -/** - * stun_timer_start_reliable: - * @timer: The #StunTimer to start - * @initial_timeout: The initial timeout to use before the first retransmission - * - * Starts a STUN transaction retransmission timer for a reliable transport. - * This should be called as soon as you send the message for the first time on - * a TCP socket - */ -void stun_timer_start_reliable (StunTimer *timer, unsigned int initial_timeout); - -/** - * stun_timer_refresh: - * @timer: The #StunTimer to refresh - * - * Updates a STUN transaction retransmission timer. - * Returns: A #StunUsageTimerReturn telling you what to do next - */ -StunUsageTimerReturn stun_timer_refresh (StunTimer *timer); - -/** - * stun_timer_remainder: - * @timer: The #StunTimer to query - * - * Query the timer on the time left before the next refresh should be done - * Returns: The time remaining for the timer to expire in milliseconds - */ -unsigned stun_timer_remainder (const StunTimer *timer); - -# ifdef __cplusplus -} -# endif - -#endif /* !STUN_TIMER_H */ diff --git a/stun/usages/turn.c b/stun/usages/turn.c deleted file mode 100644 index 80b30a0..0000000 --- a/stun/usages/turn.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -#include "stun/stunagent.h" -#include "turn.h" - -#include -#include -#include - - - -#define REQUESTED_PROPS_E 0x80000000 -#define REQUESTED_PROPS_R 0x40000000 -#define REQUESTED_PROPS_P 0x20000000 - - -#define STUN_ATTRIBUTE_MSN_MAPPED_ADDRESS 0x8000 - - -#define TURN_REQUESTED_TRANSPORT_UDP 0x11000000 - -/** Non-blocking mode STUN TURN usage */ - -size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, - StunMessage *previous_response, - StunUsageTurnRequestPorts request_props, - int32_t bandwidth, int32_t lifetime, - uint8_t *username, size_t username_len, - uint8_t *password, size_t password_len, - StunUsageTurnCompatibility compatibility) -{ - stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_ALLOCATE); - - if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 || - compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) { - if (stun_message_append32 (msg, STUN_ATTRIBUTE_REQUESTED_TRANSPORT, - TURN_REQUESTED_TRANSPORT_UDP) != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - if (bandwidth >= 0) { - if (stun_message_append32 (msg, STUN_ATTRIBUTE_BANDWIDTH, bandwidth) != - STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - } else { - if (stun_message_append32 (msg, STUN_ATTRIBUTE_MAGIC_COOKIE, - TURN_MAGIC_COOKIE) != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_OC2007) { - if (stun_message_append32(msg, STUN_ATTRIBUTE_MS_VERSION, 1) != - STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - if (lifetime >= 0) { - if (stun_message_append32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime) != - STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - if ((compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 || - compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) && - request_props != STUN_USAGE_TURN_REQUEST_PORT_NORMAL) { - uint32_t req = 0; - - - if (request_props & STUN_USAGE_TURN_REQUEST_PORT_EVEN_AND_RESERVE) { - req |= REQUESTED_PROPS_R; - req |= REQUESTED_PROPS_E; - } else if (request_props & STUN_USAGE_TURN_REQUEST_PORT_EVEN) { - req |= REQUESTED_PROPS_E; - } - - if (stun_message_append32 (msg, STUN_ATTRIBUTE_REQUESTED_PORT_PROPS, - req) != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - if (previous_response) { - uint8_t *realm; - uint8_t *nonce; - uint64_t reservation; - uint16_t len; - - realm = (uint8_t *) stun_message_find (previous_response, - STUN_ATTRIBUTE_REALM, &len); - if (realm != NULL) { - if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, len) != - STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - nonce = (uint8_t *) stun_message_find (previous_response, - STUN_ATTRIBUTE_NONCE, &len); - if (nonce != NULL) { - if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, len) != - STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - if (stun_message_find64 (previous_response, - STUN_ATTRIBUTE_RESERVATION_TOKEN, - &reservation) == STUN_MESSAGE_RETURN_SUCCESS) { - if (stun_message_append64 (msg, STUN_ATTRIBUTE_RESERVATION_TOKEN, - reservation) != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - } - - if (username != NULL && username_len > 0 && - (agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS || - previous_response)) { - if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, - username, username_len) != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - return stun_agent_finish_message (agent, msg, password, password_len); -} - -size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, - StunMessage *previous_response, int32_t lifetime, - uint8_t *username, size_t username_len, - uint8_t *password, size_t password_len, - StunUsageTurnCompatibility compatibility) -{ - - if (compatibility != STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 && - compatibility != STUN_USAGE_TURN_COMPATIBILITY_RFC5766) { - return stun_usage_turn_create (agent, msg, buffer, buffer_len, - previous_response, STUN_USAGE_TURN_REQUEST_PORT_NORMAL, 0, lifetime, - username, username_len, password, password_len, compatibility); - } - - stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_REFRESH); - if (lifetime >= 0) { - if (stun_message_append32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime) != - STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - if (previous_response) { - uint8_t *realm; - uint8_t *nonce; - uint16_t len; - - realm = (uint8_t *) stun_message_find (previous_response, - STUN_ATTRIBUTE_REALM, &len); - if (realm != NULL) { - if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, realm, len) != - STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - nonce = (uint8_t *) stun_message_find (previous_response, - STUN_ATTRIBUTE_NONCE, &len); - if (nonce != NULL) { - if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, nonce, len) != - STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - } - - - if (username != NULL && username_len > 0 && - (agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS || - previous_response)) { - if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, - username, username_len) != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - - return stun_agent_finish_message (agent, msg, password, password_len); -} - -size_t stun_usage_turn_create_permission (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, - uint8_t *username, size_t username_len, - uint8_t *password, size_t password_len, - uint8_t *realm, size_t realm_len, - uint8_t *nonce, size_t nonce_len, - struct sockaddr_storage *peer, - StunUsageTurnCompatibility compatibility) -{ - if (!peer) - return 0; - - stun_agent_init_request (agent, msg, buffer, buffer_len, - STUN_CREATEPERMISSION); - - /* PEER address */ - if (stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, - peer, sizeof(*peer)) != STUN_MESSAGE_RETURN_SUCCESS) { - return 0; - } - - /* nonce */ - if (nonce != NULL) { - if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE, - nonce, nonce_len) != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - /* realm */ - if (realm != NULL) { - if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM, - realm, realm_len) != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - /* username */ - if (username != NULL && - (agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS || - (nonce != NULL && realm != NULL))) { - if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME, - username, username_len) != STUN_MESSAGE_RETURN_SUCCESS) - return 0; - } - - return stun_agent_finish_message (agent, msg, password, password_len); -} - - -StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg, - struct sockaddr_storage *relay_addr, socklen_t *relay_addrlen, - struct sockaddr_storage *addr, socklen_t *addrlen, - struct sockaddr_storage *alternate_server, socklen_t *alternate_server_len, - uint32_t *bandwidth, uint32_t *lifetime, - StunUsageTurnCompatibility compatibility) -{ - int val, code = -1; - StunUsageTurnReturn ret = STUN_USAGE_TURN_RETURN_RELAY_SUCCESS; - - if (stun_message_get_method (msg) != STUN_ALLOCATE) - return STUN_USAGE_TURN_RETURN_INVALID; - - switch (stun_message_get_class (msg)) - { - case STUN_REQUEST: - case STUN_INDICATION: - return STUN_USAGE_TURN_RETURN_INVALID; - - case STUN_RESPONSE: - break; - - case STUN_ERROR: - if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) { - /* missing ERROR-CODE: ignore message */ - return STUN_USAGE_TURN_RETURN_INVALID; - } - - /* NOTE: currently we ignore unauthenticated messages if the context - * is authenticated, for security reasons. */ - stun_debug (" STUN error message received (code: %d)", code); - - /* ALTERNATE-SERVER mechanism */ - if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_OC2007 && - alternate_server && alternate_server_len && - stun_message_find_addr (msg, STUN_ATTRIBUTE_MS_ALTERNATE_SERVER, - alternate_server, - alternate_server_len) == STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug ("Found alternate server"); - /* The ALTERNATE_SERVER will always be returned by the MS turn server. - * We need to check if the ALTERNATE_SERVER is the same as the current - * server to decide whether we need to switch servers or not. - */ - } - if ((code / 100) == 3) { - if (alternate_server && alternate_server_len) { - if (stun_message_find_addr (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER, - alternate_server, alternate_server_len) != - STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute"); - return STUN_USAGE_TURN_RETURN_ERROR; - } - } else { - if (!stun_message_has_attribute (msg, - STUN_ATTRIBUTE_ALTERNATE_SERVER)) { - stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute"); - return STUN_USAGE_TURN_RETURN_ERROR; - } - } - - stun_debug ("Found alternate server"); - return STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER; - - } - return STUN_USAGE_TURN_RETURN_ERROR; - - default: - /* Fall through. */ - break; - } - - stun_debug ("Received %u-bytes STUN message", stun_message_length (msg)); - - if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 || - compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) { - val = stun_message_find_xor_addr (msg, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen); - - if (val == STUN_MESSAGE_RETURN_SUCCESS) - ret = STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS; - val = stun_message_find_xor_addr (msg, - STUN_ATTRIBUTE_RELAY_ADDRESS, relay_addr, relay_addrlen); - if (val != STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug (" No RELAYED-ADDRESS: %d", val); - return STUN_USAGE_TURN_RETURN_ERROR; - } - } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_GOOGLE) { - val = stun_message_find_addr (msg, - STUN_ATTRIBUTE_MAPPED_ADDRESS, relay_addr, relay_addrlen); - if (val != STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug (" No MAPPED-ADDRESS: %d", val); - return STUN_USAGE_TURN_RETURN_ERROR; - } - } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_MSN) { - val = stun_message_find_addr (msg, - STUN_ATTRIBUTE_MSN_MAPPED_ADDRESS, addr, addrlen); - - if (val == STUN_MESSAGE_RETURN_SUCCESS) - ret = STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS; - - val = stun_message_find_addr (msg, - STUN_ATTRIBUTE_MAPPED_ADDRESS, relay_addr, relay_addrlen); - if (val != STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug (" No MAPPED-ADDRESS: %d", val); - return STUN_USAGE_TURN_RETURN_ERROR; - } - } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_OC2007) { - union { - StunTransactionId id; - uint32_t u32[4]; - } transid; - uint32_t magic_cookie; - - stun_message_id (msg, transid.id); - magic_cookie = transid.u32[0]; - - val = stun_message_find_xor_addr_full (msg, - STUN_ATTRIBUTE_MS_XOR_MAPPED_ADDRESS, addr, addrlen, - htonl (magic_cookie)); - - if (val == STUN_MESSAGE_RETURN_SUCCESS) - ret = STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS; - - val = stun_message_find_addr (msg, - STUN_ATTRIBUTE_MAPPED_ADDRESS, relay_addr, relay_addrlen); - if (val != STUN_MESSAGE_RETURN_SUCCESS) { - stun_debug (" No MAPPED-ADDRESS: %d", val); - return STUN_USAGE_TURN_RETURN_ERROR; - } - } - - stun_message_find32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime); - stun_message_find32 (msg, STUN_ATTRIBUTE_BANDWIDTH, bandwidth); - - stun_debug (" Mapped address found!"); - return ret; - -} - - - -StunUsageTurnReturn stun_usage_turn_refresh_process (StunMessage *msg, - uint32_t *lifetime, StunUsageTurnCompatibility compatibility) -{ - int code = -1; - StunUsageTurnReturn ret = STUN_USAGE_TURN_RETURN_RELAY_SUCCESS; - - if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 || - compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) { - if (stun_message_get_method (msg) != STUN_REFRESH) - return STUN_USAGE_TURN_RETURN_INVALID; - } else { - if (stun_message_get_method (msg) != STUN_ALLOCATE) - return STUN_USAGE_TURN_RETURN_INVALID; - } - - switch (stun_message_get_class (msg)) - { - case STUN_REQUEST: - case STUN_INDICATION: - return STUN_USAGE_TURN_RETURN_INVALID; - - case STUN_RESPONSE: - break; - - case STUN_ERROR: - if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) { - /* missing ERROR-CODE: ignore message */ - return STUN_USAGE_TURN_RETURN_INVALID; - } - - return STUN_USAGE_TURN_RETURN_ERROR; - - default: - /* Fall through. */ - break; - } - - stun_message_find32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime); - - stun_debug ("TURN Refresh successful!"); - return ret; - -} diff --git a/stun/usages/turn.h b/stun/usages/turn.h deleted file mode 100644 index 83fa00a..0000000 --- a/stun/usages/turn.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Rémi Denis-Courmont, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef STUN_TURN_H -# define STUN_TURN_H 1 - -/** - * SECTION:turn - * @short_description: TURN Allocation Usage - * @include: stun/usages/turn.h - * @stability: Stable - * - * The STUN TURN usage allows for easily creating and parsing STUN Allocate - * requests and responses used for TURN. The API allows you to create a new - * allocation or refresh an existing one as well as to parse a response to - * an allocate or refresh request. - */ - - -#ifdef _WIN32 -# include "../win32_common.h" -#else -# include -# include -#endif - -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -# include "stun/stunagent.h" - -# ifdef __cplusplus -extern "C" { -# endif - -/** - * StunUsageTurnRequestPorts: - * @STUN_USAGE_TURN_REQUEST_PORT_NORMAL: Request a normal port - * @STUN_USAGE_TURN_REQUEST_PORT_EVEN: Request an even port - * @STUN_USAGE_TURN_REQUEST_PORT_EVEN_AND_RESERVE: Request an even port and - * reserve the next higher port - * - * This enum is used to specify which port configuration you want when creating - * a new Allocation - */ -typedef enum { - STUN_USAGE_TURN_REQUEST_PORT_NORMAL = 0, - STUN_USAGE_TURN_REQUEST_PORT_EVEN = 1, - STUN_USAGE_TURN_REQUEST_PORT_EVEN_AND_RESERVE = 2 -} StunUsageTurnRequestPorts; - -/** - * StunUsageTurnCompatibility: - * @STUN_USAGE_TURN_COMPATIBILITY_DRAFT9: Use the specification compatible with - * TURN Draft 09 - * @STUN_USAGE_TURN_COMPATIBILITY_GOOGLE: Use the specification compatible with - * Google Talk's relay server - * @STUN_USAGE_TURN_COMPATIBILITY_MSN: Use the specification compatible with - * MSN TURN servers - * @STUN_USAGE_TURN_COMPATIBILITY_OC2007: Use the specification compatible with - * Microsoft Office Communicator 2007 - * @STUN_USAGE_TURN_COMPATIBILITY_RFC5766: Use the specification compatible with - * RFC 5766 (the final, canonical TURN standard) - * - * Specifies which TURN specification compatibility to use - */ -typedef enum { - STUN_USAGE_TURN_COMPATIBILITY_DRAFT9, - STUN_USAGE_TURN_COMPATIBILITY_GOOGLE, - STUN_USAGE_TURN_COMPATIBILITY_MSN, - STUN_USAGE_TURN_COMPATIBILITY_OC2007, - STUN_USAGE_TURN_COMPATIBILITY_RFC5766, -} StunUsageTurnCompatibility; - -/** - * StunUsageTurnReturn: - * @STUN_USAGE_TURN_RETURN_RELAY_SUCCESS: The response was successful and a relay - * address is provided - * @STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS: The response was successful and a - * relay address as well as a mapped address are provided - * @STUN_USAGE_TURN_RETURN_ERROR: The response resulted in an error - * @STUN_USAGE_TURN_RETURN_INVALID: The response is not a valid response - * @STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER: The server requests the message - * to be sent to an alternate server - * - * Return value of stun_usage_turn_process() and - * stun_usage_turn_refresh_process() which allows you to see what status the - * function call returned. - */ -typedef enum { - STUN_USAGE_TURN_RETURN_RELAY_SUCCESS, - STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS, - STUN_USAGE_TURN_RETURN_ERROR, - STUN_USAGE_TURN_RETURN_INVALID, - STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER, -} StunUsageTurnReturn; - - -/** - * stun_usage_turn_create: - * @agent: The #StunAgent to use to build the request - * @msg: The #StunMessage to build - * @buffer: The buffer to use for creating the #StunMessage - * @buffer_len: The size of the @buffer - * @previous_response: If this is the first request you are sending, set this - * argument to NULL, if it's a subsequent request you are building, then set this - * argument to the response you have received. This argument is used for building - * long term credentials (using the REALM and NONCE attributes) as well as for - * getting the RESERVATION-TOKEN attribute when you previously requested an - * allocation which reserved two ports - * @request_ports: Specify how you want to request the allocated port(s). - * This is only used if the compatibility is set to - * #STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 - * See #StunUsageTurnRequestPorts - * @bandwidth: The bandwidth to request from the server for the allocation. If - * this value is negative, then no BANDWIDTH attribute is added to the request. - * This is only used if the compatibility is set to - * #STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 - * @lifetime: The lifetime of the allocation to request from the server. If - * this value is negative, then no LIFETIME attribute is added to the request. - * This is only used if the compatibility is set to - * #STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 - * @username: The username to use in the request - * @username_len: The length of @username - * @password: The key to use for building the MESSAGE-INTEGRITY - * @password_len: The length of @password - * @compatibility: The compatibility mode to use for building the Allocation - * request - * - * Create a new TURN Allocation request - * Returns: The length of the message to send - */ -size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, - StunMessage *previous_response, - StunUsageTurnRequestPorts request_ports, - int32_t bandwidth, int32_t lifetime, - uint8_t *username, size_t username_len, - uint8_t *password, size_t password_len, - StunUsageTurnCompatibility compatibility); - -/** - * stun_usage_turn_create_refresh: - * @agent: The #StunAgent to use to build the request - * @msg: The #StunMessage to build - * @buffer: The buffer to use for creating the #StunMessage - * @buffer_len: The size of the @buffer - * @previous_response: If this is the first request you are sending, set this - * argument to NULL, if it's a subsequent request you are building, then set this - * argument to the response you have received. This argument is used for building - * long term credentials (using the REALM and NONCE attributes) - * @lifetime: The lifetime of the allocation to request from the server. If - * this value is negative, then no LIFETIME attribute is added to the request. - * This is only used if the compatibility is set to - * #STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 - * @username: The username to use in the request - * @username_len: The length of @username - * @password: The key to use for building the MESSAGE-INTEGRITY - * @password_len: The length of @password - * @compatibility: The compatibility mode to use for building the Allocation - * request - * - * Create a new TURN Refresh request - * Returns: The length of the message to send - */ -size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, - StunMessage *previous_response, int32_t lifetime, - uint8_t *username, size_t username_len, - uint8_t *password, size_t password_len, - StunUsageTurnCompatibility compatibility); - -/** - * stun_usage_turn_create_permission: - * @agent: The #StunAgent to use to build the request - * @msg: The #StunMessage to build - * @buffer: The buffer to use for creating the #StunMessage - * @buffer_len: The size of the @buffer - * @username: The username to use in the request - * @username_len: The length of @username - * @password: The key to use for building the MESSAGE-INTEGRITY - * @password_len: The length of @password - * @realm: The realm identifier to use in the request - * @realm_len: The length of @realm - * @nonce: Unique and securely random nonce to use in the request - * @nonce_len: The length of @nonce - * @peer: Server-reflexive host address to request permission for - * @compatibility: The compatibility mode to use for building the - * CreatePermission request - * - * Create a new TURN CreatePermission request - * - * Returns: The length of the message to send - */ -size_t stun_usage_turn_create_permission (StunAgent *agent, StunMessage *msg, - uint8_t *buffer, size_t buffer_len, - uint8_t *username, size_t username_len, - uint8_t *password, size_t password_len, - uint8_t *realm, size_t realm_len, - uint8_t *nonce, size_t nonce_len, - struct sockaddr_storage *peer, - StunUsageTurnCompatibility compatibility); - -/** - * stun_usage_turn_process: - * @msg: The message containing the response - * @relay_addr: A pointer to a #sockaddr structure to fill with the relay address - * that the TURN server allocated for us - * @relay_addrlen: The length of @relay_addr - * @addr: A pointer to a #sockaddr structure to fill with the mapped address - * that the STUN response contains. - * This argument will only be filled if the return value - * of the function is #STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS - * @addrlen: The length of @addr - * @alternate_server: A pointer to a #sockaddr structure to fill with the - * address of an alternate server to which we should send our new STUN - * Allocate request, in case the currently used TURN server is requesting the use - * of an alternate server. This argument will only be filled if the return value - * of the function is #STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER - * In the case of @STUN_USAGE_TURN_COMPATIBILITY_OC2007 compatibility, the - * @alternate_server could be filled at any time, and should only be considered - * if the request was sent to a different server than the address returned - * in the @alternate_server field - * @alternate_server_len: The length of @alternate_server - * @bandwidth: A pointer to fill with the bandwidth the TURN server allocated us - * @lifetime: A pointer to fill with the lifetime of the allocation - * @compatibility: The compatibility mode to use for processing the Allocation - * response - * - * Process a TURN Allocate response and extract the necessary information from - * the message - * Returns: A #StunUsageTurnReturn value - */ -StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg, - struct sockaddr_storage *relay_addr, socklen_t *relay_addrlen, - struct sockaddr_storage *addr, socklen_t *addrlen, - struct sockaddr_storage *alternate_server, socklen_t *alternate_server_len, - uint32_t *bandwidth, uint32_t *lifetime, - StunUsageTurnCompatibility compatibility); - -/** - * stun_usage_turn_refresh_process: - * @msg: The message containing the response - * @lifetime: A pointer to fill with the lifetime of the allocation - * @compatibility: The compatibility mode to use for processing the Refresh - * response - * - * Process a TURN Refresh response and extract the necessary information from - * the message - * Returns: A #StunUsageTurnReturn value. A #STUN_USAGE_TURN_RETURN_RELAY_SUCCESS - * means the Refresh was successful, but no relay address is given (kept the same - * as for the original allocation) - */ -StunUsageTurnReturn stun_usage_turn_refresh_process (StunMessage *msg, - uint32_t *lifetime, StunUsageTurnCompatibility compatibility); - - -# ifdef __cplusplus -} -# endif - -#endif diff --git a/stun/utils.c b/stun/utils.c deleted file mode 100644 index bd6ea20..0000000 --- a/stun/utils.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2007-2009 Nokia Corporation. All rights reserved. - * Contact: Rémi Denis-Courmont - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Olivier Crete, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#include "utils.h" - -size_t stun_padding (size_t l) -{ - return (4 - (l & 3)) & 3; -} - -size_t stun_align (size_t l) -{ - return (l + 3) & ~3; -} - - -uint16_t stun_getw (const uint8_t *ptr) -{ - return ((ptr)[0] << 8) | ptr[1]; -} - - -void *stun_setw (uint8_t *ptr, uint16_t value) -{ - *ptr++ = value >> 8; - *ptr++ = value & 0xff; - return ptr; -} - - -void stun_set_type (uint8_t *h, StunClass c, StunMethod m) -{ -/* assert (c < 4); */ -/* assert (m < (1 << 12)); */ - - h[0] = (c >> 1) | ((m >> 6) & 0x3e); - h[1] = ((c << 4) & 0x10) | ((m << 1) & 0xe0) | (m & 0x0f); - -/* assert (stun_getw (h) < (1 << 14)); */ -/* assert (stun_get_class (h) == c); */ -/* assert (stun_get_method (h) == m); */ -} - - -StunMessageReturn stun_xor_address (const StunMessage *msg, - struct sockaddr_storage *addr, socklen_t addrlen, - uint32_t magic_cookie) -{ - union { - struct sockaddr_storage *addr; - struct sockaddr_in *in; - struct sockaddr_in6 *in6; - } addr_ptr; - - addr_ptr.addr = addr; - - switch (addr->ss_family) - { - case AF_INET: - { - struct sockaddr_in *ip4 = addr_ptr.in; - if ((size_t) addrlen < sizeof (*ip4)) - return STUN_MESSAGE_RETURN_INVALID; - - ip4->sin_port ^= htons (magic_cookie >> 16); - ip4->sin_addr.s_addr ^= htonl (magic_cookie); - return STUN_MESSAGE_RETURN_SUCCESS; - } - - case AF_INET6: - { - struct sockaddr_in6 *ip6 = addr_ptr.in6; - unsigned short i; - - if ((size_t) addrlen < sizeof (*ip6)) - return STUN_MESSAGE_RETURN_INVALID; - - ip6->sin6_port ^= htons (magic_cookie >> 16); - for (i = 0; i < 16; i++) - ip6->sin6_addr.s6_addr[i] ^= msg->buffer[4 + i]; - return STUN_MESSAGE_RETURN_SUCCESS; - } - - default: - return STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS; - } -} diff --git a/stun/utils.h b/stun/utils.h deleted file mode 100644 index 673fcccd..0000000 --- a/stun/utils.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifndef STUN_UTILS_H -# define STUN_UTILS_H 1 - -/* - * @file utils.h - * @brief STUN client generic utility functions - */ - -#include "stunmessage.h" - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#endif - -# ifdef __cplusplus -extern "C" { -# endif - -size_t stun_padding (size_t l); - -size_t stun_align (size_t l); - -uint16_t stun_getw (const uint8_t *ptr); - -void *stun_setw (uint8_t *ptr, uint16_t value); - -void stun_set_type (uint8_t *h, StunClass c, StunMethod m); - -StunMessageReturn stun_xor_address (const StunMessage *msg, - struct sockaddr_storage *addr, socklen_t addrlen, - uint32_t magic_cookie); - - -# ifdef __cplusplus -} -# endif - -#endif /* STUN_UTILS_H */ diff --git a/stun/win32_common.h b/stun/win32_common.h deleted file mode 100644 index ec833c3..0000000 --- a/stun/win32_common.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2008-2009 Collabora Ltd. - * Contact: Youness Alaoui - * (C) 2008-2009 Nokia Corporation. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * Danny Smith - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/* ISO C9x 7.18 Integer types - * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * Contributor: Danny Smith - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Date: 2000-12-02 - */ - - -#ifndef _WIN32_COMMON_H -#define _WIN32_COMMON_H - -#include -#include -#include - -/* On MSVC, ssize_t is SSIZE_T */ -#ifdef _MSC_VER -#include -#define ssize_t SSIZE_T -#endif - -/* Windows v10.0.16232 SDK defines MSG_ERRQUEUE, but doesn't support it with - * recvmsg, and also uses a different msghdr struct */ -#undef MSG_ERRQUEUE - -#endif /* _WIN32_COMMON_H */ diff --git a/subprojects/glib.wrap b/subprojects/glib.wrap deleted file mode 100644 index fdfb550..0000000 --- a/subprojects/glib.wrap +++ /dev/null @@ -1,5 +0,0 @@ -[wrap-file] -directory=glib-2.64.2 -source_url=https://ftp.gnome.org/pub/gnome/sources/glib/2.64/glib-2.64.2.tar.xz -source_filename=glib-2.64.2.tar.xz -source_hash=9a2f21ed8f13b9303399de13a0252b7cbcede593d26971378ec6cb90e87f2277 \ No newline at end of file diff --git a/tests/Makefile.am b/tests/Makefile.am deleted file mode 100644 index 473e5e0..0000000 --- a/tests/Makefile.am +++ /dev/null @@ -1,152 +0,0 @@ -# -# Makefile.am for the Nice Glib ICE library -# -# (C) 2006, 2007 Collabora Ltd. -# (C) 2006, 2007 Nokia Corporation. All rights reserved. -# -# Licensed under MPL 1.1/LGPL 2.1. See file COPYING. - -include $(top_srcdir)/common.mk - -AM_CFLAGS = \ - $(LIBNICE_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(GUPNP_CFLAGS) \ - -I $(top_srcdir) \ - -I $(top_srcdir)/agent \ - -I $(top_srcdir)/random \ - -I $(top_srcdir)/socket \ - -I $(top_srcdir)/stun -AM_CPPFLAGS = -DG_LOG_DOMAIN=\"libnice-tests\" - -AM_TESTS_ENVIRONMENT = \ - G_MESSAGES_DEBUG=all \ - NICE_DEBUG=all \ - GST_PLUGIN_PATH=${GST_PLUGIN_PATH}:$(top_builddir)/gst - -COMMON_LDADD = $(top_builddir)/agent/libagent.la $(top_builddir)/socket/libsocket.la $(GLIB_LIBS) $(GUPNP_LIBS) - -check_PROGRAMS = \ - test-pseudotcp \ - test-pseudotcp-fin \ - test-pseudotcp-fuzzy \ - test-bsd \ - test \ - test-address \ - test-add-remove-stream \ - test-build-io-stream \ - test-io-stream-thread \ - test-io-stream-closing-write \ - test-io-stream-closing-read \ - test-io-stream-cancelling \ - test-io-stream-pollable \ - test-send-recv \ - test-socket-is-based-on \ - test-udp-turn-fragmentation \ - test-priority \ - test-fullmode \ - test-different-number-streams \ - test-restart \ - test-fallback \ - test-thread \ - test-trickle \ - test-new-trickle \ - test-tcp \ - test-icetcp \ - test-credentials \ - test-turn \ - test-drop-invalid \ - test-nomination \ - test-interfaces - -dist_check_SCRIPTS = \ - check-test-fullmode-with-stun.sh \ - test-pseudotcp-random.sh - -if HAVE_GST_CHECK -check_PROGRAMS += test-gstreamer -endif - -TESTS = $(check_PROGRAMS) $(dist_check_SCRIPTS) - -noinst_HEADERS = test-io-stream-common.h - -test_pseudotcp_LDADD = $(COMMON_LDADD) - -test_pseudotcp_fin_LDADD = $(COMMON_LDADD) - -test_pseudotcp_fuzzy_LDADD = $(COMMON_LDADD) -lm - -test_bsd_LDADD = $(COMMON_LDADD) - -test_LDADD = $(COMMON_LDADD) - -test_thread_LDADD = $(COMMON_LDADD) - -test_address_LDADD = $(COMMON_LDADD) - -test_add_remove_stream_LDADD = $(COMMON_LDADD) - -test_build_io_stream_LDADD = $(COMMON_LDADD) - -test_io_stream_thread_SOURCES = test-io-stream-thread.c test-io-stream-common.c -test_io_stream_thread_LDADD = $(COMMON_LDADD) - -test_io_stream_closing_write_SOURCES = test-io-stream-closing-write.c test-io-stream-common.c -test_io_stream_closing_write_LDADD = $(COMMON_LDADD) - -test_io_stream_closing_read_SOURCES = test-io-stream-closing-read.c test-io-stream-common.c -test_io_stream_closing_read_LDADD = $(COMMON_LDADD) - -test_io_stream_cancelling_SOURCES = test-io-stream-cancelling.c test-io-stream-common.c -test_io_stream_cancelling_LDADD = $(COMMON_LDADD) - -test_io_stream_pollable_SOURCES = test-io-stream-pollable.c test-io-stream-common.c -test_io_stream_pollable_LDADD = $(COMMON_LDADD) - -test_send_recv_SOURCES = test-send-recv.c test-io-stream-common.c -test_send_recv_LDADD = $(COMMON_LDADD) - -test_socket_is_based_on_LDADD = $(COMMON_LDADD) - -test_udp_turn_fragmentation_LDADD = $(COMMON_LDADD) - -test_priority_LDADD = $(COMMON_LDADD) - -test_fullmode_LDADD = $(COMMON_LDADD) - -test_different_number_streams_LDADD = $(COMMON_LDADD) - -test_restart_LDADD = $(COMMON_LDADD) - -test_fallback_LDADD = $(COMMON_LDADD) - -test_trickle_LDADD = $(COMMON_LDADD) - -test_new_trickle_LDADD = $(COMMON_LDADD) - -test_tcp_LDADD = $(COMMON_LDADD) - -test_icetcp_LDADD = $(COMMON_LDADD) - -test_credentials_LDADD = $(COMMON_LDADD) - -test_turn_LDADD = $(COMMON_LDADD) - -test_drop_invalid_LDADD = $(COMMON_LDADD) - -test_nomination_LDADD = $(COMMON_LDADD) - -test_gstreamer_CFLAGS = $(AM_CFLAGS) $(GST_CHECK_CFLAGS) -test_gstreamer_LDADD = -lnice -L$(top_builddir)/nice/.libs $(GLIB_LIBS) $(GUPNP_LIBS) $(GST_CHECK_LIBS) $(GST_LIBS) - -test_interfaces_LDADD = $(COMMON_LDADD) - -all-local: - chmod a+x $(srcdir)/check-test-fullmode-with-stun.sh - chmod a+x $(srcdir)/test-pseudotcp-random.sh - -EXTRA_DIST = \ - libnice.supp \ - meson.build \ - test-fullmode-with-stun.c diff --git a/tests/check-test-fullmode-with-stun.sh b/tests/check-test-fullmode-with-stun.sh deleted file mode 100755 index 7be4190..0000000 --- a/tests/check-test-fullmode-with-stun.sh +++ /dev/null @@ -1,36 +0,0 @@ -#! /bin/sh - -if test -n "${BUILT_WITH_MESON}"; then - STUND=$1 - TEST_FULLMODE=$2 -else - STUND=../stun/tools/stund - TEST_FULLMODE=./test-fullmode -fi - -echo "Starting ICE full-mode with STUN unit test." - -[ -e "$STUND" ] || { - echo "STUN server not found: Cannot run unit test!" >&2 - exit 77 -} - -set -x -pidfile=./stund.pid - -export NICE_STUN_SERVER=127.0.0.1 -export NICE_STUN_SERVER_PORT=3800 - -echo "Launching $STUND on port ${NICE_STUN_SERVER_PORT}." - -rm -f -- "$pidfile" -(sh -c "echo \$\$ > \"$pidfile\" && exec "$STUND" ${NICE_STUN_SERVER_PORT}") & -sleep 1 - -"${TEST_FULLMODE}" -error=$? - -kill "$(cat "$pidfile")" -rm -f -- "$pidfile" -wait -exit ${error} diff --git a/tests/docker/centos7-autotools/Dockerfile b/tests/docker/centos7-autotools/Dockerfile deleted file mode 100644 index 10fbf5e..0000000 --- a/tests/docker/centos7-autotools/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# build with -# docker build -t registry.freedesktop.org/libnice/libnice/centos7/autotools-build:$(date --rfc-3339=date) . -# docker tag registry.freedesktop.org/libnice/libnice/centos7/autotools-build:$(date --rfc-3339=date) registry.freedesktop.org/libnice/libnice/centos7/autotools-build:latest -# docker push registry.freedesktop.org/libnice/libnice/centos7/autotools-build:$(date --rfc-3339=date) -# docker push registry.freedesktop.org/libnice/libnice/centos7/autotools-build:latest - -# alternatively - -# export BUILDAH_FORMAT=docker -# buildah bud -t registry.freedesktop.org/libnice/libnice/centos7/autotools-build:$(date --rfc-3339=date) . -# buildah tag registry.freedesktop.org/libnice/libnice/centos7/autotools-build:$(date --rfc-3339=date) registry.freedesktop.org/libnice/libnice/centos7/autotools-build:latest -# buildah push registry.freedesktop.org/libnice/libnice/centos7/autotools-build:latest -# buildah push registry.freedesktop.org/libnice/libnice/centos7/autotools-build:$(date --rfc-3339=date) - -FROM centos:centos7 - -RUN yum -y update; yum clean all -RUN yum -y install git gtk-doc gnutls-devel gupnp-igd-devel gstreamer1-devel gobject-introspection-devel valgrind; yum clean all - -RUN yum -y install autoconf automake libtool; yum clean all -RUN yum -y install net-tools; yum clean all diff --git a/tests/docker/centos7-meson/Dockerfile b/tests/docker/centos7-meson/Dockerfile deleted file mode 100644 index 694e34e..0000000 --- a/tests/docker/centos7-meson/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -# build with -# docker build -t registry.freedesktop.org/libnice/libnice/centos7/meson-build:$(date --rfc-3339=date) . -# docker tag registry.freedesktop.org/libnice/libnice/centos7/meson-build:$(date --rfc-3339=date) registry.freedesktop.org/libnice/libnice/centos7/meson-build:latest -# docker push registry.freedesktop.org/libnice/libnice/centos7/meson-build:latest -# docker push registry.freedesktop.org/libnice/libnice/centos7/meson-build:$(date --rfc-3339=date) - -# alternatively - -# export BUILDAH_FORMAT=docker -# buildah bud -t registry.freedesktop.org/libnice/libnice/centos7/meson-build:$(date --rfc-3339=date) . -# buildah tag registry.freedesktop.org/libnice/libnice/centos7/meson-build:$(date --rfc-3339=date) registry.freedesktop.org/libnice/libnice/centos7/meson-build:latest -# buildah push registry.freedesktop.org/libnice/libnice/centos7/meson-build:latest -# buildah push registry.freedesktop.org/libnice/libnice/centos7/meson-build:$(date --rfc-3339=date) - -FROM centos:centos7 - -RUN yum -y update; yum clean all -RUN yum -y install git gtk-doc gnutls-devel gupnp-igd-devel gstreamer1-devel gobject-introspection-devel valgrind; yum clean all -RUN yum -y install net-tools; yum clean all - - -RUN yum -y install centos-release-scl ; yum clean all -RUN yum -y install rh-python36; yum clean all -RUN scl enable rh-python36 "pip3 install meson" - -RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm; yum clean all -RUN yum -y install ninja-build; yum clean all diff --git a/tests/libnice.supp b/tests/libnice.supp deleted file mode 100644 index 46622a8..0000000 --- a/tests/libnice.supp +++ /dev/null @@ -1,613 +0,0 @@ -{ - gnutls-init-calloc - Memcheck:Leak - fun:calloc - ... - fun:gtls_gnutls_init -} - -{ - gnutls-init-realloc - Memcheck:Leak - fun:realloc - ... - fun:gtls_gnutls_init -} - -{ - g-tls-backend-gnutls-init - Memcheck:Leak - fun:g_once_impl - fun:g_tls_backend_gnutls_init -} - -{ - p11-tokens-init - Memcheck:Leak - fun:calloc - ... - fun:create_tokens_inlock - fun:initialize_module_inlock_reentrant -} - -{ - gobject-init-malloc - Memcheck:Leak - fun:malloc - ... - fun:gobject_init_ctor -} - -{ - gobject-init-realloc - Memcheck:Leak - fun:realloc - ... - fun:gobject_init_ctor -} - -{ - gobject-init-calloc - Memcheck:Leak - fun:calloc - ... - fun:gobject_init_ctor -} - -{ - g-type-register-dynamic - Memcheck:Leak - fun:malloc - ... - fun:g_type_register_dynamic -} - -{ - g-type-register-static - Memcheck:Leak - fun:malloc - ... - fun:g_type_register_static -} - -{ - g-type-register-static-realloc - Memcheck:Leak - fun:realloc - ... - fun:g_type_register_static -} - -{ - g-type-register-static-calloc - Memcheck:Leak - fun:calloc - ... - fun:g_type_register_static -} - -{ - g-type-add-interface-dynamic - Memcheck:Leak - fun:malloc - ... - fun:g_type_add_interface_dynamic -} - -{ - g-type-add-interface-static - Memcheck:Leak - fun:malloc - ... - fun:g_type_add_interface_static -} - -{ - g-test-rand-init - Memcheck:Leak - fun:calloc - ... - fun:g_rand_new_with_seed_array - fun:test_run_seed - ... - fun:g_test_run -} - -{ - g-test-rand-init2 - Memcheck:Leak - fun:calloc - ... - fun:g_rand_new_with_seed_array - ... - fun:get_global_random - ... - fun:g_test_init -} - -{ - g-quark-table-new - Memcheck:Leak - fun:g_hash_table_new - ... - fun:quark_new -} - -{ - g-quark-table-resize - Memcheck:Leak - fun:g_hash_table_resize - ... - fun:quark_new -} - -{ - g-type-interface-init - Memcheck:Leak - fun:malloc - ... - fun:type_iface_vtable_base_init_Wm -} - -{ - g-type-class-init - Memcheck:Leak - fun:calloc - ... - fun:type_class_init_Wm -} - -{ - g-io-module-default-singleton-malloc - Memcheck:Leak - fun:malloc - ... - fun:g_type_create_instance - ... - fun:_g_io_module_get_default -} - -{ - g-io-module-default-singleton-module - Memcheck:Leak - fun:calloc - ... - fun:g_module_open - ... - fun:_g_io_module_get_default -} - -{ - g-get-language-names - Memcheck:Leak - fun:malloc - ... - fun:g_get_language_names -} - -{ - g-static-mutex - Memcheck:Leak - fun:malloc - ... - fun:g_static_mutex_get_mutex_impl -} - -{ - g-system-thread-init - Memcheck:Leak - fun:calloc - ... - fun:g_system_thread_new -} - -{ - g-io-module-default-proxy-resolver-gnome - Memcheck:Leak - fun:calloc - ... - fun:g_proxy_resolver_gnome_init - ... - fun:_g_io_module_get_default -} - -{ - g-private-get - drd:ConflictingAccess - fun:g_private_get -} -{ - g-private-get-helgrind - Helgrind:Race - fun:g_private_get -} - - -{ - g-private-set - drd:ConflictingAccess - fun:g_private_set -} -{ - g-private-set-helgrind - Helgrind:Race - fun:g_private_set -} - -{ - g-type-construct-free - drd:ConflictingAccess - fun:g_type_free_instance -} -{ - g-type-construct-free-helgrind - Helgrind:Race - fun:g_type_free_instance -} - -{ - g-variant-unref - drd:ConflictingAccess - fun:g_variant_unref -} -{ - g-variant-unref-helgrind - Helgrind:Race - fun:g_variant_unref -} - -# TODO: haven't checked these entirely rigorously -{ - g-unix-signals-main - drd:ConflictingAccess - fun:_g_main_create_unix_signal_watch -} -{ - g-unix-signals-dispatch - drd:ConflictingAccess - ... - fun:dispatch_unix_signals* -} -{ - g-unix-signals-dispatch-helgrind - Helgrind:Race - ... - fun:dispatch_unix_signals* -} -{ - g-unix-signals-other - drd:ConflictingAccess - fun:g_unix_signal_watch* -} -{ - g-unix-signals-other-helgrind - Helgrind:Race - fun:g_unix_signal_watch* -} -{ - g-unix-signals-handler - drd:ConflictingAccess - fun:g_unix_signal_handler* -} -{ - g-unix-signals-handler-helgrind - Helgrind:Race - fun:g_unix_signal_handler* -} -{ - g-unix-signals-worker - drd:ConflictingAccess - fun:glib_worker_main -} -{ - g-unix-signals-worker-helgrind - Helgrind:Race - fun:glib_worker_main -} - -# TODO: haven't checked this thoroughly either -{ - g-wakeup-acknowledge - drd:ConflictingAccess - fun:read - fun:g_wakeup_acknowledge -} - -# TODO: or these -{ - g-type-fundamental - drd:ConflictingAccess - fun:g_type_fundamental -} -{ - g-type-fundamental-helgrind - Helgrind:Race - fun:g_type_fundamental -} -{ - g-type-class-peek-static - drd:ConflictingAccess - fun:g_type_class_peek_static -} -{ - g-type-class-peek-static-helgrind - Helgrind:Race - fun:g_type_class_peek_static -} -{ - g-type-is-a - drd:ConflictingAccess - ... - fun:g_type_is_a -} -{ - g-type-is-a-helgrind - Helgrind:Race - ... - fun:g_type_is_a -} - -# TODO: ???? -{ - g-inet-address-get-type - drd:ConflictingAccess - fun:g_inet_address_get_type -} -{ - g-inet-address-get-type-helgrind - Helgrind:Race - fun:g_inet_address_get_type -} -{ - nice-get-type-helgrind - Helgrind:Race - fun:nice_*_get_type -} - -# From: https://github.com/fredericgermain/valgrind/blob/master/glibc-2.X-drd.supp -{ - drd-libc-stdio - drd:ConflictingAccess - obj:*/lib*/libc-* -} -{ - drd-libc-recv - drd:ConflictingAccess - fun:recv -} -{ - drd-libc-send - drd:ConflictingAccess - fun:send -} - -# GSources do an opportunistic ref count check -{ - g-source-set-ready-time - drd:ConflictingAccess - fun:g_source_set_ready_time -} -{ - g-source-set-ready-time-helgrind - Helgrind:Race - fun:g_source_set_ready_time -} - -# TODO: Check this -{ - g-source-iter-next - Helgrind:Race - fun:g_source_iter_next - fun:g_main_context_* - fun:g_main_context_iterate -} - -{ - g-object-instance-private - drd:ConflictingAccess - fun:*_get_instance_private -} -{ - g-object-instance-private-helgrind - Helgrind:Race - fun:*_get_instance_private -} - -# GLib legitimately calls pthread_cond_signal without a mutex held -{ - g-task-thread-complete - drd:CondErr - ... - fun:g_cond_signal - fun:g_task_thread_complete -} -{ - g-task-thread-complete - Helgrind:Misc - ... - fun:g_cond_signal - fun:g_task_thread_complete -} - -# False positive -{ - nice-output-stream-cond - Helgrind:Misc - ... - fun:g_cond_clear - fun:write_data_unref -} - -# False positive, but I can't explain how (FIXME) -{ - g-task-cond - Helgrind:Misc - ... - fun:g_cond_clear - fun:g_task_finalize -} - -# TODO FIXME: This is definitely a race. -# https://bugzilla.gnome.org/show_bug.cgi?id=735754 -{ - g-tls-base-stream-close - Helgrind:Race - ... - fun:g_*_stream_close - fun:streams_removed_cb -} -{ - g-tls-base-stream-close2 - Helgrind:Race - ... - fun:g_*_stream_close - fun:g_tls_connection_gnutls_close -} - -# Real race, but is_cancelled() is an opportunistic function anyway -{ - g-cancellable-is-cancelled - Helgrind:Race - fun:g_cancellable_is_cancelled -} - -# False positive -{ - g-main-context-cond - Helgrind:Misc - ... - fun:g_cond_clear - fun:g_main_context_unref -} - -# False positives -{ - g-source-unlocked - Helgrind:Race - fun:g_source_*_unlocked -} -{ - g-source-internal - Helgrind:Race - fun:g_source_*_internal -} - -# FIXME: Probably actually a race -{ - test-io-stream-common-termination - Helgrind:Race - fun:check_for_termination -} -{ - test-io-stream-common-wait - Helgrind:Race - fun:wait_for_start -} -{ - test-io-stream-common-main - Helgrind:Race - fun:main_thread_cb -} -{ - test-io-stream-common-read - Helgrind:Race - fun:read_thread_cb -} -{ - test-io-stream-common-write - Helgrind:Race - fun:write_thread_cb -} - -# False positive -{ - g_object_real_dispose - Helgrind:Race - fun:g_object_real_dispose -} - -# False positive -{ - g_object_new_valist - Helgrind:Race - ... - fun:g_object_new_valist -} - - -# GStreamer leaks, we know -{ - gst-check-init - Memcheck:Leak - ... - fun:gst_check_init -} - - -{ - g-quark-init - Memcheck:Leak - ... - fun:g_quark_init -} - -# For Glib in RHEL 7 -{ - g_type_register_fundamental-rhel7 - Memcheck:Leak - ... - fun:g_type_register_fundamental -} -{ - dl-init-rhel7 - Memcheck:Leak - ... - fun:_dl_init -} -{ - g-type-class-ref-rhel7 - Memcheck:Leak - ... - fun:g_type_class_ref -} -{ - invalid-free-in-rhel7 - Memcheck:Free - fun:free - fun:__libc_freeres -} -{ - g-thread-pool-push-rhel7 - Memcheck:Leak - ... - fun:g_thread_pool_push -} -{ - exit-shell-rhel7 - Memcheck:Leak - ... - fun:exit_shell -} -{ - g-bus-rhel7 - Memcheck:Leak - ... - fun:g_bus_get_sync -} - -# glibc does not deallocate thread-local storage - -{ - - Memcheck:Leak - ... - fun:_dl_allocate_tls - fun:pthread_create@@* -} - -{ - - Memcheck:Leak - ... - fun:_dl_allocate_tls -} diff --git a/tests/meson.build b/tests/meson.build deleted file mode 100644 index e238a92..0000000 --- a/tests/meson.build +++ /dev/null @@ -1,98 +0,0 @@ -nice_tests = [ - 'test-pseudotcp', - # 'test-pseudotcp-fuzzy', FIXME: this test is not reliable, times out sometimes - 'test-bsd', - 'test', - 'test-address', - 'test-add-remove-stream', - 'test-build-io-stream', - 'test-io-stream-thread', - 'test-io-stream-closing-write', - 'test-io-stream-closing-read', - 'test-io-stream-cancelling', - 'test-io-stream-pollable', - 'test-send-recv', - 'test-socket-is-based-on', - 'test-udp-turn-fragmentation', - 'test-priority', - 'test-fullmode', - 'test-different-number-streams', - 'test-restart', - 'test-fallback', - 'test-thread', - 'test-trickle', - 'test-tcp', - 'test-icetcp', - 'test-credentials', - 'test-turn', - 'test-drop-invalid', - 'test-nomination', - 'test-interfaces', -] - -if cc.has_header('arpa/inet.h') - nice_tests += [ - 'test-pseudotcp-fin', - 'test-new-trickle', - ] -endif - -tenv = environment() -tenv.set('BUILT_WITH_MESON', '1') - -foreach tname : nice_tests - if tname.startswith('test-io-stream') or tname.startswith('test-send-recv') - extra_src = ['test-io-stream-common.c'] - else - extra_src = [] - endif - exe = executable('nice-@0@'.format(tname), - '@0@.c'.format(tname), extra_src, - c_args: '-DG_LOG_DOMAIN="libnice-tests"', - include_directories: nice_incs, - dependencies: [nice_deps, libm], - link_with: [libagent, libstun, libsocket, librandom], - install: false) - set_variable(tname.underscorify(), exe) - test(tname, exe, env: tenv) - - if tname == 'test-fullmode' - wrapper_exe = executable ('nice-test-fullmode-with-stun', - 'test-fullmode-with-stun.c', - dependencies: gio_deps, - install: false) - test('test-fullmode-with-stun', wrapper_exe, - args: [stund_exe, test_fullmode], - env: tenv, - is_parallel: false, - depends: exe) - endif -endforeach - -if gst_dep.found() - gst_check = dependency('gstreamer-check-1.0', required: get_option('gstreamer'), - fallback : ['gstreamer', 'gst_check_dep']) - if gst_check.found() - exe = executable('nice-test-gstreamer', - 'test-gstreamer.c', extra_src, - c_args: '-DG_LOG_DOMAIN="libnice-tests"', - include_directories: nice_incs, - dependencies: [nice_deps, gst_check, libm], - link_with: libnice, - install: false) - gst_env = tenv - gst_env.append('GST_PLUGIN_PATH_1_0', join_paths(meson.current_build_dir(), '..', 'gst')) - test('test-gstreamer', exe, env: gst_env) - endif -endif - -if find_program('sh', required : false).found() and find_program('dd', required : false).found() and find_program('diff', required : false).found() - test('test-pseudotcp-random', find_program('test-pseudotcp-random.sh'), - args: test_pseudotcp, - env: tenv) -endif - -debugenv = environment() -debugenv.set('G_MESSAGES_DEBUG', 'all') -debugenv.set('NICE_DEBUG', 'all') -add_test_setup('debug', env: debugenv) diff --git a/tests/test-add-remove-stream.c b/tests/test-add-remove-stream.c deleted file mode 100644 index 6df9dce..0000000 --- a/tests/test-add-remove-stream.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "agent-priv.h" -#include - -int -main (void) -{ - NiceAgent *agent; - NiceAddress addr; - -#ifdef G_OS_WIN32 - WSADATA w; - WSAStartup(0x0202, &w); -#endif - nice_address_init (&addr); - - if (!nice_address_set_from_string (&addr, "127.0.0.1")) - g_assert_not_reached (); - - agent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); - nice_agent_add_local_address (agent, &addr); - - g_assert_cmpuint (nice_agent_add_stream (agent, 1), ==, 1); - g_assert_cmpuint (nice_agent_add_stream (agent, 10), ==, 2); - g_assert_cmpuint (nice_agent_add_stream (agent, 2), ==, 3); - - g_assert (NULL != agent->streams); - - nice_agent_remove_stream (agent, 1); - nice_agent_remove_stream (agent, 2); - nice_agent_remove_stream (agent, 3); - - g_assert (NULL == agent->streams); - - g_object_unref (agent); -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return 0; -} - diff --git a/tests/test-address.c b/tests/test-address.c deleted file mode 100644 index 583830e..0000000 --- a/tests/test-address.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include "address.h" - -static void -test_ipv4 (void) -{ - NiceAddress addr; - NiceAddress other; - gchar str[NICE_ADDRESS_STRING_LEN]; - - nice_address_init (&addr); - nice_address_init (&other); - nice_address_set_ipv4 (&addr, 0x01020304); - g_assert_cmpint (addr.s.ip4.sin_family, ==, AF_INET); - - nice_address_to_string (&addr, str); - g_assert_cmpstr (str, ==, "1.2.3.4"); - - nice_address_to_string (&addr, str); - - /* same address */ - nice_address_set_ipv4 (&other, 0x01020304); - g_assert (TRUE == nice_address_equal (&addr, &other)); - - /* from sockaddr_in */ - nice_address_set_port (&other, 9876); /* in native byte order */ - other.s.ip4.sin_family = AF_INET; - nice_address_set_from_string (&addr, "1.2.3.4"); - nice_address_set_port (&addr, 9876); /* in native byte order */ - nice_address_to_string (&addr, str); - nice_address_to_string (&other, str); - g_assert (TRUE == nice_address_equal (&addr, &other)); - - /* different IP */ - nice_address_set_ipv4 (&other, 0x01020305); - g_assert (FALSE == nice_address_equal (&addr, &other)); - - /* different port */ - nice_address_set_ipv4 (&other, 0x01020304); - nice_address_set_port (&addr, 1); - g_assert (FALSE == nice_address_equal (&addr, &other)); - - /* test private address check */ - { - NiceAddress *heap_addr = nice_address_new (); - - g_assert (nice_address_set_from_string (heap_addr, "127.0.0.1.1") != TRUE); - - g_assert (nice_address_set_from_string (heap_addr, "127.0.0.1") == TRUE); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - g_assert (nice_address_set_from_string (heap_addr, "127.1.1.1") == TRUE); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - g_assert (nice_address_set_from_string(heap_addr, "192.168.2.0")); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - g_assert (nice_address_set_from_string(heap_addr, "192.168.15.69")); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - g_assert (nice_address_set_from_string(heap_addr, "192.169.0.0")); - g_assert (nice_address_is_private (heap_addr) == FALSE); - - g_assert (nice_address_set_from_string(heap_addr, "192.167.0.0")); - g_assert (nice_address_is_private (heap_addr) == FALSE); - - g_assert (nice_address_set_from_string(heap_addr, "10.2.1.2")); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - g_assert (nice_address_set_from_string(heap_addr, "11.0.0.0")); - g_assert (nice_address_is_private (heap_addr) == FALSE); - - g_assert (nice_address_set_from_string(heap_addr, "9.255.255.255")); - g_assert (nice_address_is_private (heap_addr) == FALSE); - - g_assert (nice_address_set_from_string(heap_addr, "172.15.255.255")); - g_assert (nice_address_is_private (heap_addr) == FALSE); - - g_assert (nice_address_set_from_string(heap_addr, "172.16.0.0")); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - g_assert (nice_address_set_from_string(heap_addr, "172.31.255.255")); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - g_assert (nice_address_set_from_string(heap_addr, "172.32.0.0")); - g_assert (nice_address_is_private (heap_addr) == FALSE); - g_assert (nice_address_set_from_string(heap_addr, "172.63.0.0")); - g_assert (nice_address_is_private (heap_addr) == FALSE); - - g_assert (nice_address_set_from_string(heap_addr, "169.253.255.255")); - g_assert (nice_address_is_private (heap_addr) == FALSE); - - g_assert (nice_address_set_from_string(heap_addr, "169.254.0.0")); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - g_assert (nice_address_set_from_string(heap_addr, "169.254.255.255")); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - g_assert (nice_address_set_from_string(heap_addr, "169.255.0.0")); - g_assert (nice_address_is_private (heap_addr) == FALSE); - - g_assert (nice_address_set_from_string(heap_addr, "fe70::0")); - g_assert (nice_address_is_private (heap_addr) == FALSE); - - g_assert (nice_address_set_from_string(heap_addr, "fe80::0")); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - g_assert (nice_address_set_from_string(heap_addr, "fe81::0")); - g_assert (nice_address_is_private (heap_addr) == TRUE); - - nice_address_free (heap_addr); - } -} - -static void -test_ipv6 (void) -{ - NiceAddress addr, other, v4addr; - gchar str[NICE_ADDRESS_STRING_LEN]; - union { - struct sockaddr_in6 in6; - struct sockaddr addr; - } sin, sin2; - - g_assert (nice_address_set_from_string (&v4addr, "172.1.0.1") == TRUE); - - memset (&sin, 0, sizeof (sin)); - memset (&sin2, 0, sizeof (sin2)); - - memset (&addr, 0, sizeof (NiceAddress)); - memset (&other, 0, sizeof (NiceAddress)); - nice_address_init (&addr); - nice_address_init (&other); - nice_address_set_ipv6 (&addr, (guchar *) - "\x00\x11\x22\x33" - "\x44\x55\x66\x77" - "\x88\x99\xaa\xbb" - "\xcc\xdd\xee\xff"); - g_assert_cmpint (addr.s.ip6.sin6_family, ==, AF_INET6); - - nice_address_to_string (&addr, str); - g_assert_cmpstr (str, ==, "11:2233:4455:6677:8899:aabb:ccdd:eeff"); - - nice_address_set_port (&addr, 9876); /* in native byte order */ - nice_address_set_from_string (&other, "11:2233:4455:6677:8899:aabb:ccdd:eeff"); - nice_address_set_port (&other, 9876); /* in native byte order */ - - nice_address_copy_to_sockaddr (&other, &sin2.addr); - nice_address_copy_to_sockaddr (&addr, &sin.addr); - g_assert (nice_address_equal (&addr, &other) == TRUE); - nice_address_to_string (&addr, str); - nice_address_to_string (&other, str); - - g_assert_cmpmem (&sin, sizeof(sin), &sin2, sizeof(sin2)); - - /* private IPv6 address */ - nice_address_set_ipv6 (&addr, (guchar *) - "\xfc\x00\x00\x00" - "\x00\x00\x00\x00" - "\x00\x00\x00\x00" - "\x00\x00\x00\x01"); - g_assert (nice_address_is_private (&addr) == TRUE); - nice_address_set_ipv6 (&addr, (guchar *) - "\x00\x00\x00\x00" - "\x00\x00\x00\x00" - "\x00\x00\x00\x00" - "\x00\x00\x00\x01"); - g_assert (nice_address_is_private (&addr) == TRUE); - - /* mismatching address families */ - g_assert (nice_address_equal (&addr, &v4addr) != TRUE); - - /* mismatched type */ - addr.s.addr.sa_family = AF_UNSPEC; - /*g_assert (nice_address_equal (&addr, &v4addr) != TRUE);*/ -} - -int -main (void) -{ -#ifdef G_OS_WIN32 - WSADATA w; -#endif - -#ifdef G_OS_WIN32 - WSAStartup(0x0202, &w); -#endif - test_ipv4 (); - test_ipv6 (); - -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return 0; -} - diff --git a/tests/test-bsd.c b/tests/test-bsd.c deleted file mode 100644 index c182164..0000000 --- a/tests/test-bsd.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007, 2014 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "socket.h" - -static gssize -socket_recv (NiceSocket *sock, NiceAddress *addr, gsize buf_len, gchar *buf) -{ - GInputVector local_buf = { buf, buf_len }; - NiceInputMessage local_message = { &local_buf, 1, addr, 0 }; - gint ret; - - ret = nice_socket_recv_messages (sock, &local_message, 1); - if (ret <= 0) - return ret; - - return local_buf.size; -} - -static void -test_socket_initial_properties (void) -{ - NiceSocket *sock; - - sock = nice_udp_bsd_socket_new (NULL); - g_assert (sock != NULL); - - // not bound to a particular interface - g_assert_cmpint (sock->addr.s.ip4.sin_addr.s_addr, ==, 0); - // is bound to a particular port - g_assert_cmpuint (nice_address_get_port (&sock->addr), !=, 0); - - nice_socket_free (sock); -} - -static void -test_socket_address_properties (void) -{ - NiceSocket *sock; - NiceAddress tmp; - - sock = nice_udp_bsd_socket_new (NULL); - g_assert (sock != NULL); - - g_assert (nice_address_set_from_string (&tmp, "127.0.0.1")); - g_assert_cmpuint (nice_address_get_port (&sock->addr), !=, 0); - nice_address_set_port (&tmp, nice_address_get_port (&sock->addr)); - g_assert_cmpuint (nice_address_get_port (&tmp), !=, 0); - - nice_socket_free (sock); -} - -static void -test_simple_send_recv (void) -{ - NiceSocket *server; - NiceSocket *client; - NiceAddress tmp; - gchar buf[5]; - - server = nice_udp_bsd_socket_new (NULL); - g_assert (server != NULL); - - client = nice_udp_bsd_socket_new (NULL); - g_assert (client != NULL); - - g_assert (nice_address_set_from_string (&tmp, "127.0.0.1")); - nice_address_set_port (&tmp, nice_address_get_port (&server->addr)); - - /* Send and receive stuff. */ - g_assert_cmpint (nice_socket_send (client, &tmp, 5, "hello"), ==, 5); - - g_assert_cmpint (socket_recv (server, &tmp, 5, buf), ==, 5); - g_assert_cmpint (strncmp (buf, "hello", 5), ==, 0); - - g_assert_cmpint (nice_socket_send (server, &tmp, 5, "uryyb"), ==, 5); - - g_assert_cmpint (socket_recv (client, &tmp, 5, buf), ==, 5); - g_assert_cmpint (strncmp (buf, "uryyb", 5), ==, 0); - - nice_socket_free (client); - nice_socket_free (server); -} - -/* Check that sending and receiving to/from zero-length buffers returns - * immediately. */ -static void -test_zero_send_recv (void) -{ - NiceSocket *sock; - NiceAddress tmp; - gchar buf[5]; - NiceOutputMessage local_out_message; - NiceInputMessage local_in_message; - - sock = nice_udp_bsd_socket_new (NULL); - g_assert (sock != NULL); - - g_assert (nice_address_set_from_string (&tmp, "127.0.0.1")); - g_assert_cmpuint (nice_address_get_port (&sock->addr), !=, 0); - nice_address_set_port (&tmp, nice_address_get_port (&sock->addr)); - g_assert_cmpuint (nice_address_get_port (&tmp), !=, 0); - - g_assert_cmpint (nice_socket_send (sock, &tmp, 0, "ignore-me"), ==, 0); - g_assert_cmpint (nice_socket_send (sock, &tmp, 0, NULL), ==, 0); - - g_assert_cmpint (socket_recv (sock, &tmp, 0, buf), ==, 0); - g_assert_cmpint (socket_recv (sock, &tmp, 0, NULL), ==, 0); - - /* And again with messages. */ - g_assert_cmpint (nice_socket_send_messages (sock, &tmp, - &local_out_message, 0), ==, 0); - g_assert_cmpint (nice_socket_send_messages (sock, &tmp, NULL, 0), ==, 0); - - g_assert_cmpint (nice_socket_recv_messages (sock, - &local_in_message, 0), ==, 0); - g_assert_cmpint (nice_socket_recv_messages (sock, NULL, 0), ==, 0); - - nice_socket_free (sock); -} - -/* Test receiving into multiple tiny buffers. */ -static void -test_multi_buffer_recv (void) -{ - NiceSocket *server; - NiceSocket *client; - NiceAddress tmp; - guint8 buf[20]; - guint8 dummy_buf[9]; - - server = nice_udp_bsd_socket_new (NULL); - g_assert (server != NULL); - - client = nice_udp_bsd_socket_new (NULL); - g_assert (client != NULL); - - g_assert (nice_address_set_from_string (&tmp, "127.0.0.1")); - nice_address_set_port (&tmp, nice_address_get_port (&server->addr)); - - /* Send and receive stuff. */ - { - GInputVector bufs[7] = { - { &buf[0], 1 }, - { &buf[1], 4 }, - { &buf[1], 0 }, /* should be unused (zero-length) */ - { &buf[5], 1 }, - { &buf[6], 5 }, - { &buf[11], 9 }, /* should be unused (message fits in prior buffers) */ - { &buf[11], 0 }, /* should be unused (zero-length) */ - }; - NiceInputMessage message = { bufs, G_N_ELEMENTS (bufs), NULL, 0 }; - - /* Initialise the buffers so we can try and catch out-of-bounds accesses. */ - memset (buf, 0xaa, sizeof (buf)); - memset (dummy_buf, 0xaa, sizeof (dummy_buf)); - - /* Send and receive. */ - g_assert_cmpint (nice_socket_send (client, &tmp, 11, "hello-world"), ==, 11); - g_assert_cmpuint (nice_socket_recv_messages (server, &message, 1), ==, 1); - g_assert_cmpuint (message.length, ==, 11); - - /* Check all of the things. The sizes should not have been modified. */ - g_assert_cmpuint (bufs[0].size, ==, 1); - g_assert_cmpuint (bufs[1].size, ==, 4); - g_assert_cmpuint (bufs[2].size, ==, 0); - g_assert_cmpuint (bufs[3].size, ==, 1); - g_assert_cmpuint (bufs[4].size, ==, 5); - g_assert_cmpuint (bufs[5].size, ==, 9); - g_assert_cmpuint (bufs[6].size, ==, 0); - - g_assert_cmpint (strncmp ((gchar *) buf, "hello-world", 11), ==, 0); - g_assert_cmpmem (buf + 11, 9, dummy_buf, 9); - } - - nice_socket_free (client); - nice_socket_free (server); -} - -/* Fill a buffer with deterministic but non-repeated data, so that transmission - * and reception corruption is more likely to be detected. */ -static void -fill_send_buf (guint8 *buf, gsize buf_len, guint seed) -{ - gsize i; - - for (i = 0; i < buf_len; i++) { - buf[i] = '0' + (seed % 10); - seed++; - } -} - -/* Test receiving multiple messages in a single call. */ -static void -test_multi_message_recv (guint n_sends, guint n_receives, - guint n_bufs_per_message, gsize send_buf_size, gsize recv_buf_size, - guint expected_n_received_messages, guint expected_n_sent_messages) -{ - NiceSocket *server; - NiceSocket *client; - NiceAddress tmp; - - server = nice_udp_bsd_socket_new (NULL); - g_assert (server != NULL); - - client = nice_udp_bsd_socket_new (NULL); - g_assert (client != NULL); - - g_assert (nice_address_set_from_string (&tmp, "127.0.0.1")); - nice_address_set_port (&tmp, nice_address_get_port (&server->addr)); - - /* Send and receive stuff. */ - { - GInputVector *recv_bufs; - NiceInputMessage *recv_messages; - GOutputVector *send_bufs; - NiceOutputMessage *send_messages; - guint i, j; - guint8 *_expected_recv_buf; - gsize expected_recv_buf_len; - - /* Set up the send buffers. */ - send_bufs = g_malloc0_n (n_sends * n_bufs_per_message, - sizeof (GOutputVector)); - send_messages = g_malloc0_n (n_sends, sizeof (NiceOutputMessage)); - - for (i = 0; i < n_sends; i++) { - for (j = 0; j < n_bufs_per_message; j++) { - guint8 *buf = g_slice_alloc (send_buf_size); - - send_bufs[i * n_bufs_per_message + j].buffer = buf; - send_bufs[i * n_bufs_per_message + j].size = send_buf_size; - - /* Set up the buffer data. */ - fill_send_buf (buf, send_buf_size, i); - } - - send_messages[i].buffers = send_bufs + i * n_bufs_per_message; - send_messages[i].n_buffers = n_bufs_per_message; - } - - /* Set up the receive buffers. Yay for dynamic tests! */ - recv_bufs = g_malloc0_n (n_receives * n_bufs_per_message, - sizeof (GInputVector)); - recv_messages = g_malloc0_n (n_receives, sizeof (NiceInputMessage)); - - for (i = 0; i < n_receives; i++) { - for (j = 0; j < n_bufs_per_message; j++) { - recv_bufs[i * n_bufs_per_message + j].buffer = - g_slice_alloc (recv_buf_size); - recv_bufs[i * n_bufs_per_message + j].size = recv_buf_size; - - /* Initialise the buffer to try to catch out-of-bounds accesses. */ - memset (recv_bufs[i * n_bufs_per_message + j].buffer, 0xaa, - recv_buf_size); - } - - recv_messages[i].buffers = recv_bufs + i * n_bufs_per_message; - recv_messages[i].n_buffers = n_bufs_per_message; - recv_messages[i].from = NULL; - recv_messages[i].length = 0; - } - - /* Send multiple packets. */ - g_assert_cmpint ( - nice_socket_send_messages (client, &tmp, send_messages, n_sends), ==, - expected_n_sent_messages); - - /* Receive things. */ - g_assert_cmpint ( - nice_socket_recv_messages (server, recv_messages, n_receives), ==, - expected_n_received_messages); - - /* Check all of the things. The sizes should not have been modified. */ - expected_recv_buf_len = recv_buf_size * n_bufs_per_message; - _expected_recv_buf = g_slice_alloc (expected_recv_buf_len); - - for (i = 0; i < expected_n_received_messages; i++) { - NiceInputMessage *message = &recv_messages[i]; - guint8 *expected_recv_buf = _expected_recv_buf; - gsize expected_len; - - expected_len = MIN (send_buf_size * n_bufs_per_message, - expected_recv_buf_len); - g_assert_cmpuint (message->length, ==, expected_len); - - /* Build the expected buffer as a concatenation of the expected values of - * all receive buffers in the message. */ - memset (expected_recv_buf, 0xaa, expected_recv_buf_len); - fill_send_buf (expected_recv_buf, expected_len, i); - - for (j = 0; j < n_bufs_per_message; j++) { - g_assert_cmpuint (message->buffers[j].size, ==, recv_buf_size); - g_assert_cmpint ( - memcmp (message->buffers[j].buffer, expected_recv_buf, - recv_buf_size), ==, 0); - - expected_recv_buf += recv_buf_size; - } - } - - g_slice_free1 (expected_recv_buf_len, _expected_recv_buf); - - for (i = 0; i < n_receives; i++) { - for (j = 0; j < n_bufs_per_message; j++) { - g_slice_free1 (recv_buf_size, - recv_bufs[i * n_bufs_per_message + j].buffer); - } - } - - for (i = 0; i < n_sends; i++) { - for (j = 0; j < n_bufs_per_message; j++) { - g_slice_free1 (send_buf_size, - (gpointer) send_bufs[i * n_bufs_per_message + j].buffer); - } - } - - g_free (recv_messages); - g_free (recv_bufs); - g_free (send_messages); - g_free (send_bufs); - } - - nice_socket_free (client); - nice_socket_free (server); -} - -int -main (void) -{ - test_socket_initial_properties (); - test_socket_address_properties (); - test_simple_send_recv (); - test_zero_send_recv (); - test_multi_buffer_recv (); - - /* Multi-message testing. Serious business. */ - { - guint i; - struct { - guint n_sends; /* messages */ - guint expected_n_sent_messages; - - guint n_receives; /* messages */ - guint expected_n_received_messages; - - guint n_bufs_per_message; - gsize send_buf_size; - gsize recv_buf_size; - } test_cases[] = { - /* same number of sends and receives */ - { 2, 2, 2, 2, 1, 100, 100 }, /* send 200B, receive 200B */ - /* more sends than receives */ - { 4, 4, 2, 2, 2, 100, 77 }, /* send 800B, receive 308B */ - /* more receives than sends */ - { 1, 1, 4, 1, 4, 10, 100 }, /* send 40B, receive 1600B */ - /* small receive buffer (data loss) */ - { 100, 100, 100, 100, 1, 100, 64 }, /* send 10000B, receive 6400B */ - /* small receive buffers (data loss) */ - { 50, 50, 50, 50, 10, 100, 8 }, /* send 50000B, receive 4000B */ - }; - - for (i = 0; i < G_N_ELEMENTS (test_cases); i++) { - test_multi_message_recv (test_cases[i].n_sends, test_cases[i].n_receives, - test_cases[i].n_bufs_per_message, test_cases[i].send_buf_size, - test_cases[i].recv_buf_size, - test_cases[i].expected_n_received_messages, - test_cases[i].expected_n_sent_messages); - } - } - - return 0; -} - diff --git a/tests/test-build-io-stream.c b/tests/test-build-io-stream.c deleted file mode 100644 index 195a8a9..0000000 --- a/tests/test-build-io-stream.c +++ /dev/null @@ -1,465 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2013 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "agent.h" - -#include "iostream.h" - -#include "test-io-stream-common.h" - -static void -test_invalid_stream (NiceAddress *addr) -{ - NiceAgent *agent; - GIOStream *io_stream; - - agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245); - g_object_set (G_OBJECT (agent), "upnp", FALSE, NULL); - nice_agent_add_local_address (agent, addr); - - /* Try building an I/O stream for an invalid stream. All its operations should - * return G_IO_ERROR_BROKEN_PIPE. */ - io_stream = nice_agent_get_io_stream (agent, 5, 5); - g_assert (io_stream == NULL); - - g_object_unref (agent); -} - -static void -test_io_stream_properties (NiceAddress *addr) -{ - NiceAgent *agent; - guint stream_id; - GIOStream *io_stream; - GInputStream *input_stream; - GOutputStream *output_stream; - - agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245); - g_object_set (G_OBJECT (agent), "upnp", FALSE, NULL); - nice_agent_add_local_address (agent, addr); - - stream_id = nice_agent_add_stream (agent, 1); - - /* Try building an I/O stream around it. */ - io_stream = nice_agent_get_io_stream (agent, stream_id, 1); - g_assert (G_IS_IO_STREAM (io_stream)); - g_assert (NICE_IS_IO_STREAM (io_stream)); - - /* Check various initial properties. */ - g_assert (!g_io_stream_is_closed (G_IO_STREAM (io_stream))); - g_assert (!g_io_stream_has_pending (G_IO_STREAM (io_stream))); - - /* Check the input stream’s properties. */ - input_stream = g_io_stream_get_input_stream (G_IO_STREAM (io_stream)); - g_assert (G_IS_INPUT_STREAM (input_stream)); - g_assert (NICE_IS_INPUT_STREAM (input_stream)); - - g_assert (!g_input_stream_is_closed (input_stream)); - g_assert (!g_input_stream_has_pending (input_stream)); - - /* Check the output stream’s properties. */ - output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream)); - g_assert (G_IS_OUTPUT_STREAM (output_stream)); - g_assert (NICE_IS_OUTPUT_STREAM (output_stream)); - - g_assert (!g_output_stream_is_closing (output_stream)); - g_assert (!g_output_stream_is_closed (output_stream)); - g_assert (!g_output_stream_has_pending (output_stream)); - - /* Remove the component and check that the I/O streams close. */ - nice_agent_remove_stream (agent, stream_id); - - g_assert (g_io_stream_is_closed (G_IO_STREAM (io_stream))); - g_assert (g_input_stream_is_closed (input_stream)); - g_assert (g_output_stream_is_closed (output_stream)); - - g_object_unref (io_stream); - g_object_unref (agent); -} - -static void -test_pollable_properties (NiceAddress *addr) -{ - NiceAgent *agent; - guint stream_id; - GIOStream *io_stream; - GInputStream *input_stream; - GOutputStream *output_stream; - GPollableInputStream *pollable_input_stream; - GPollableOutputStream *pollable_output_stream; - guint8 buf[65536]; - GError *error = NULL; - GSource *stream_source; - - agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245); - g_object_set (G_OBJECT (agent), "upnp", FALSE, NULL); - nice_agent_add_local_address (agent, addr); - - /* Add a stream. */ - stream_id = nice_agent_add_stream (agent, 1); - - /* Try building an I/O stream around it. */ - io_stream = nice_agent_get_io_stream (agent, stream_id, 1); - g_assert (G_IS_IO_STREAM (io_stream)); - g_assert (NICE_IS_IO_STREAM (io_stream)); - - /* Check the input stream’s properties. */ - input_stream = g_io_stream_get_input_stream (G_IO_STREAM (io_stream)); - g_assert (G_IS_POLLABLE_INPUT_STREAM (input_stream)); - pollable_input_stream = G_POLLABLE_INPUT_STREAM (input_stream); - - g_assert (g_pollable_input_stream_can_poll (pollable_input_stream)); - g_assert (!g_pollable_input_stream_is_readable (pollable_input_stream)); - - g_assert ( - g_pollable_input_stream_read_nonblocking (pollable_input_stream, - buf, sizeof (buf), NULL, &error) == -1); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK); - g_clear_error (&error); - - stream_source = - g_pollable_input_stream_create_source (pollable_input_stream, NULL); - g_assert (stream_source != NULL); - g_source_unref (stream_source); - - /* Check the output stream’s properties. */ - output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream)); - g_assert (G_IS_POLLABLE_OUTPUT_STREAM (output_stream)); - pollable_output_stream = G_POLLABLE_OUTPUT_STREAM (output_stream); - - g_assert (g_pollable_output_stream_can_poll (pollable_output_stream)); - g_assert (!g_pollable_output_stream_is_writable (pollable_output_stream)); - - g_assert ( - g_pollable_output_stream_write_nonblocking (pollable_output_stream, - buf, sizeof (buf), NULL, &error) == -1); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK); - g_clear_error (&error); - - stream_source = - g_pollable_output_stream_create_source (pollable_output_stream, NULL); - g_assert (stream_source != NULL); - g_source_unref (stream_source); - - /* Remove the component and check that the I/O streams close. */ - nice_agent_remove_stream (agent, stream_id); - - g_assert (!g_pollable_input_stream_is_readable (pollable_input_stream)); - g_assert (!g_pollable_output_stream_is_writable (pollable_output_stream)); - - g_assert ( - g_pollable_input_stream_read_nonblocking (pollable_input_stream, - buf, sizeof (buf), NULL, &error) == 0); - g_assert_no_error (error); - - g_assert ( - g_pollable_output_stream_write_nonblocking (pollable_output_stream, - buf, sizeof (buf), NULL, &error) == -1); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED); - g_clear_error (&error); - - g_object_unref (io_stream); - g_object_unref (agent); -} - -static gboolean -source_cancel_cb (gpointer user_data) -{ - GCancellable *cancellable = user_data; - - g_cancellable_cancel (cancellable); - - return FALSE; -} - -static gboolean -source_cancelled_cb (GObject *pollable_stream, gpointer user_data) -{ - GMainLoop *main_loop = user_data; - - /* Try and check that the callback was invoked due to cancellation rather than - * a poll() event on the socket itself. */ - if (G_IS_POLLABLE_INPUT_STREAM (pollable_stream)) { - g_assert ( - !g_pollable_input_stream_is_readable ( - G_POLLABLE_INPUT_STREAM (pollable_stream))); - } else { - g_assert ( - !g_pollable_output_stream_is_writable ( - G_POLLABLE_OUTPUT_STREAM (pollable_stream))); - } - - g_main_loop_quit (main_loop); - - return FALSE; -} - -static gboolean -source_timeout_cb (gpointer user_data) -{ - g_error ("check_pollable_source_cancellation() took too long. Aborting."); - - return FALSE; -} - -/* Check that cancelling a GCancellable which is associated with a pollable - * stream’s GSource invokes a callback from that source in the main loop. This - * uses a main context with three sources: the pollable source, an idle source - * to trigger the cancellation, and a timeout source to fail the test if it - * takes too long. */ -static void -check_pollable_source_cancellation (GSource *pollable_source, - GCancellable *cancellable) -{ - GMainContext *main_context; - GMainLoop *main_loop; - GSource *idle_source, *timeout_source; - - main_context = g_main_context_new (); - main_loop = g_main_loop_new (main_context, FALSE); - - /* Set up the pollable source. */ - g_source_set_callback (pollable_source, G_SOURCE_FUNC (source_cancelled_cb), - main_loop, NULL); - g_source_attach (pollable_source, main_context); - - /* Idle source to cancel the cancellable. */ - idle_source = g_idle_source_new (); - g_source_set_callback (idle_source, (GSourceFunc) source_cancel_cb, - cancellable, NULL); - g_source_attach (idle_source, main_context); - g_source_unref (idle_source); - - /* Timeout. */ - timeout_source = g_timeout_source_new (30000); - g_source_set_callback (timeout_source, (GSourceFunc) source_timeout_cb, - NULL, NULL); - g_source_attach (timeout_source, main_context); - g_source_unref (timeout_source); - - /* Run the main loop and expect to quit it immediately as the pollable source - * is cancelled. */ - g_main_loop_run (main_loop); - - g_assert (g_cancellable_is_cancelled (cancellable)); - - g_main_loop_unref (main_loop); - g_main_context_unref (main_context); -} - -static void -test_pollable_cancellation (NiceAddress *addr) -{ - NiceAgent *agent; - guint stream_id; - GIOStream *io_stream; - GInputStream *input_stream; - GOutputStream *output_stream; - GPollableInputStream *pollable_input_stream; - GPollableOutputStream *pollable_output_stream; - guint8 buf[65536]; - GError *error = NULL; - GSource *stream_source; - GCancellable *cancellable; - - agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245); - g_object_set (G_OBJECT (agent), "upnp", FALSE, NULL); - nice_agent_add_local_address (agent, addr); - - /* Add a stream. */ - stream_id = nice_agent_add_stream (agent, 1); - - /* Try building an I/O stream around it. */ - io_stream = nice_agent_get_io_stream (agent, stream_id, 1); - g_assert (G_IS_IO_STREAM (io_stream)); - g_assert (NICE_IS_IO_STREAM (io_stream)); - - /* Grab the input and output streams. */ - input_stream = g_io_stream_get_input_stream (G_IO_STREAM (io_stream)); - g_assert (G_IS_POLLABLE_INPUT_STREAM (input_stream)); - pollable_input_stream = G_POLLABLE_INPUT_STREAM (input_stream); - - output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream)); - g_assert (G_IS_POLLABLE_OUTPUT_STREAM (output_stream)); - pollable_output_stream = G_POLLABLE_OUTPUT_STREAM (output_stream); - - /* Check the non-blocking read() and write() return immediately if called with - * a cancelled cancellable. */ - cancellable = g_cancellable_new (); - g_cancellable_cancel (cancellable); - - g_assert ( - g_pollable_input_stream_read_nonblocking (pollable_input_stream, - buf, sizeof (buf), cancellable, &error) == -1); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); - g_clear_error (&error); - - g_assert ( - g_pollable_output_stream_write_nonblocking (pollable_output_stream, - buf, sizeof (buf), cancellable, &error) == -1); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); - g_clear_error (&error); - - g_object_unref (cancellable); - - /* Check the GSources invoke a callback when run with the cancellable - * cancelled. */ - cancellable = g_cancellable_new (); - stream_source = - g_pollable_input_stream_create_source (pollable_input_stream, - cancellable); - - check_pollable_source_cancellation (stream_source, cancellable); - - g_source_unref (stream_source); - g_object_unref (cancellable); - - /* And for the output stream. */ - cancellable = g_cancellable_new (); - stream_source = - g_pollable_output_stream_create_source (pollable_output_stream, - cancellable); - - check_pollable_source_cancellation (stream_source, cancellable); - - g_object_unref (io_stream); - g_source_unref (stream_source); - g_object_unref (cancellable); - g_object_unref (agent); -} - -static void -test_zero_length_reads_writes (NiceAddress *addr) -{ - NiceAgent *agent; - guint stream_id; - GIOStream *io_stream; - GInputStream *input_stream; - GOutputStream *output_stream; - GPollableInputStream *pollable_input_stream; - GPollableOutputStream *pollable_output_stream; - GError *error = NULL; - guint8 buf[1]; /* should never be accessed */ - - agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245); - g_object_set (G_OBJECT (agent), "upnp", FALSE, NULL); - nice_agent_add_local_address (agent, addr); - - /* Add a stream. */ - stream_id = nice_agent_add_stream (agent, 1); - - /* Try building an I/O stream around it. */ - io_stream = nice_agent_get_io_stream (agent, stream_id, 1); - g_assert (G_IS_IO_STREAM (io_stream)); - g_assert (NICE_IS_IO_STREAM (io_stream)); - - input_stream = g_io_stream_get_input_stream (G_IO_STREAM (io_stream)); - output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream)); - pollable_input_stream = G_POLLABLE_INPUT_STREAM (input_stream); - pollable_output_stream = G_POLLABLE_OUTPUT_STREAM (output_stream); - - /* Check zero-length reads and writes complete immediately without error. */ - g_assert_cmpint (g_input_stream_read (input_stream, buf, 0, NULL, &error), ==, 0); - g_assert_no_error (error); - - g_assert_cmpint (g_output_stream_write (output_stream, buf, 0, NULL, &error), ==, 0); - g_assert_no_error (error); - - g_assert ( - g_pollable_input_stream_read_nonblocking (pollable_input_stream, - buf, 0, NULL, &error) == 0); - g_assert_no_error (error); - - g_assert ( - g_pollable_output_stream_write_nonblocking (pollable_output_stream, - buf, 0, NULL, &error) == 0); - g_assert_no_error (error); - - /* Remove the component and check that zero-length reads and writes still - * result in a 0 response, rather than any error. */ - nice_agent_remove_stream (agent, stream_id); - g_assert (g_io_stream_is_closed (G_IO_STREAM (io_stream))); - - g_assert_cmpint (g_input_stream_read (input_stream, buf, 0, NULL, &error), ==, 0); - g_assert_no_error (error); - - g_assert_cmpint (g_output_stream_write (output_stream, buf, 0, NULL, &error), ==, 0); - g_assert_no_error (error); - - g_assert ( - g_pollable_input_stream_read_nonblocking (pollable_input_stream, - buf, 0, NULL, &error) == 0); - g_assert_no_error (error); - - g_assert ( - g_pollable_output_stream_write_nonblocking (pollable_output_stream, - buf, 0, NULL, &error) == 0); - g_assert_no_error (error); - - g_object_unref (io_stream); - g_object_unref (agent); -} - -int -main (void) -{ - NiceAddress addr; - -#ifdef G_OS_WIN32 - WSADATA w; - WSAStartup (0x0202, &w); -#endif - nice_address_init (&addr); - - g_assert (nice_address_set_from_string (&addr, "127.0.0.1")); - - test_invalid_stream (&addr); - test_io_stream_properties (&addr); - test_pollable_properties (&addr); - test_pollable_cancellation (&addr); - test_zero_length_reads_writes (&addr); - -#ifdef G_OS_WIN32 - WSACleanup (); -#endif - - return 0; -} - diff --git a/tests/test-credentials.c b/tests/test-credentials.c deleted file mode 100644 index d11da6d..0000000 --- a/tests/test-credentials.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2015 Rohan Garg - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "agent-priv.h" -#include -#include - -#define LEFT_AGENT GINT_TO_POINTER(1) -#define RIGHT_AGENT GINT_TO_POINTER(2) -#define USE_UPNP 0 - -static GMainLoop *loop = NULL; - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - g_debug ("test-credentials:%s: %p", G_STRFUNC, user_data); -} - -static void set_credentials(NiceAgent *lagent, NiceAgent *ragent) -{ - gchar *ufrag = NULL, *password = NULL; - - g_debug ("test-credentials:%s", G_STRFUNC); - - nice_agent_get_local_credentials (lagent, 1, &ufrag, &password); - nice_agent_set_remote_credentials (ragent, 1, ufrag, password); - - g_free (ufrag); - g_free (password); - - nice_agent_get_local_credentials (ragent, 1, &ufrag, &password); - nice_agent_set_remote_credentials (lagent, 1, ufrag, password); - - g_free (ufrag); - g_free (password); -} - -static void swap_candidates(NiceAgent *local, guint local_id, NiceAgent *remote, guint remote_id) -{ - GSList *cands = NULL; - - g_debug ("test-credentials:%s", G_STRFUNC); - cands = nice_agent_get_local_candidates(local, local_id, - NICE_COMPONENT_TYPE_RTP); - g_assert (nice_agent_set_remote_candidates(remote, remote_id, - NICE_COMPONENT_TYPE_RTP, cands)); - - g_slist_free_full (cands, (GDestroyNotify) nice_candidate_free); -} - - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - static gboolean L_CAND_DONE = false, R_CAND_DONE = false; - static NiceAgent *lagent = NULL, *ragent = NULL; - - g_debug ("test-credentials:%s: %p", G_STRFUNC, data); - if (GPOINTER_TO_UINT(data) == 1) { - g_debug ("lagent finished gathering candidates"); - L_CAND_DONE = true; - lagent = agent; - } else if (GPOINTER_TO_UINT(data) == 2) { - g_debug ("ragent finished gathering candidates"); - R_CAND_DONE = true; - ragent = agent; - } - - if (L_CAND_DONE && R_CAND_DONE) { - set_credentials (lagent, ragent); - swap_candidates (lagent, 1, ragent, 1); - swap_candidates (ragent, 1, lagent, 1); - } -} - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - if (state == NICE_COMPONENT_STATE_READY) { - g_main_loop_quit(loop); - } -} - -static void setup(NiceAgent *lagent, NiceAgent *ragent) -{ - NiceAddress addr; - - g_assert_cmpuint (nice_agent_add_stream (lagent, 1), ==, 1); - g_assert_cmpuint (nice_agent_add_stream (ragent, 1), ==, 1); - g_assert (NULL != lagent->streams); - g_assert (NULL != ragent->streams); - - nice_address_init (&addr); - g_assert (nice_address_set_from_string (&addr, "127.0.0.1")); - nice_agent_add_local_address (lagent, &addr); - nice_agent_add_local_address (ragent, &addr); - - nice_agent_attach_recv (lagent, 1, NICE_COMPONENT_TYPE_RTP, - g_main_context_default (), - cb_nice_recv, LEFT_AGENT); - nice_agent_attach_recv (ragent, 1, NICE_COMPONENT_TYPE_RTP, - g_main_context_default (), - cb_nice_recv, RIGHT_AGENT); - - g_signal_connect(G_OBJECT(lagent), "candidate-gathering-done", - G_CALLBACK(cb_candidate_gathering_done), LEFT_AGENT); - g_signal_connect(G_OBJECT(ragent), "candidate-gathering-done", - G_CALLBACK(cb_candidate_gathering_done), RIGHT_AGENT); - - g_signal_connect(G_OBJECT(lagent), "component-state-changed", - G_CALLBACK(cb_component_state_changed), LEFT_AGENT); - - g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL); - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - g_object_set (G_OBJECT (lagent), "upnp", USE_UPNP, NULL); - g_object_set (G_OBJECT (ragent), "upnp", USE_UPNP, NULL); - - g_object_set_data (G_OBJECT (lagent), "other-agent", ragent); - g_object_set_data (G_OBJECT (ragent), "other-agent", lagent); -} - -static void teardown(NiceAgent *lagent, NiceAgent *ragent) -{ - nice_agent_remove_stream (lagent, 1); - nice_agent_remove_stream (ragent, 1); -} - -int main (void) -{ - NiceAgent *lagent = NULL, *ragent = NULL; - gchar *ufrag = NULL, *password = NULL; - -#ifdef G_OS_WIN32 - WSADATA w; - WSAStartup(0x0202, &w); -#endif - - loop = g_main_loop_new (NULL, FALSE); - - lagent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); - ragent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); - - setup (lagent, ragent); - - nice_agent_set_local_credentials (lagent, 1, "unicorns", "awesome"); - nice_agent_get_local_credentials (lagent, 1, &ufrag, &password); - g_assert_cmpstr ("unicorns", ==, ufrag); - g_assert_cmpstr ("awesome", ==, password); - g_free (ufrag); - g_free (password); - - nice_agent_gather_candidates (lagent, 1); - nice_agent_gather_candidates (ragent, 1); - - g_main_loop_run (loop); - - teardown (lagent, ragent); - - g_object_unref (lagent); - g_object_unref (ragent); - -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return 0; -} diff --git a/tests/test-different-number-streams.c b/tests/test-different-number-streams.c deleted file mode 100644 index 81be822..0000000 --- a/tests/test-different-number-streams.c +++ /dev/null @@ -1,218 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" - -#include -#include - -#define ADD_2_STREAMS TRUE -#define USE_SECOND_STREAM TRUE - -static GMainLoop *global_mainloop = NULL; - -static guint global_components_ready = 0; -static guint global_components_ready_exit = 0; - -static gboolean timer_cb (gpointer pointer) -{ - g_debug ("test-different-number-streams:%s: %p", G_STRFUNC, pointer); - - /* signal status via a global variable */ - - /* note: should not be reached, abort */ - g_error ("ERROR: test has got stuck, aborting..."); - - return FALSE; -} - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("%p: gathering done (stream_id: %u)", agent, stream_id); -} - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - g_debug ("%p: component state changed (stream_id: %u, component_id: %u, state: %s)", - agent, stream_id, component_id, nice_component_state_to_string (state)); - - if (state == NICE_COMPONENT_STATE_READY) { - global_components_ready++; - } - - /* signal status via a global variable */ - if (global_components_ready == global_components_ready_exit) { - g_debug ("Components ready/failed achieved. Stopping mailoop"); - g_main_loop_quit (global_mainloop); - } -} - -static void set_candidates (NiceAgent *from, guint from_stream, - NiceAgent *to, guint to_stream, guint component) -{ - GSList *cands = NULL, *i; - - cands = nice_agent_get_local_candidates (from, from_stream, component); - nice_agent_set_remote_candidates (to, to_stream, component, cands); - - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); -} - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - g_debug ("%p: recv (stream_id: %u, component_id: %u)", agent, stream_id, component_id); -} - -int main (void) -{ - NiceAgent *lagent, *ragent; - guint timer_id; - guint ls_id, rs_id_1, rs_id_2; - gchar *lufrag = NULL, *lpassword = NULL; - gchar *rufrag1 = NULL, *rpassword1 = NULL, *rufrag2 = NULL, *rpassword2 = NULL; - NiceAddress addr; - - -#ifdef G_OS_WIN32 - WSADATA w; - - WSAStartup(0x0202, &w); -#endif - - /* Initialize nice agents */ - nice_address_init (&addr); - nice_address_set_from_string (&addr, "127.0.0.1"); - - global_mainloop = g_main_loop_new (NULL, FALSE); - - /* step: create the agents L and R */ - lagent = nice_agent_new (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY_GOOGLE); - g_debug ("lagent: %p", lagent); - - nice_agent_add_local_address (lagent, &addr); - nice_agent_set_software (lagent, "test-different-number-streams, Left Agent"); - g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL); - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); - g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), NULL); - g_signal_connect (G_OBJECT (lagent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), NULL); - - ragent = nice_agent_new (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY_GOOGLE); - g_debug ("ragent: %p", ragent); - - nice_agent_add_local_address (ragent, &addr); - nice_agent_set_software (ragent, "test-different-number-streams, Right Agent"); - g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); - g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), NULL); - g_signal_connect (G_OBJECT (ragent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), NULL); - - /* step: add a timer to catch state changes triggered by signals */ - timer_id = g_timeout_add (30000, timer_cb, NULL); - - ls_id = nice_agent_add_stream (lagent, 2); - g_assert_cmpuint (ls_id, >, 0); - nice_agent_get_local_credentials(lagent, ls_id, &lufrag, &lpassword); - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, NULL); - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, NULL); - - global_components_ready_exit = 4; - - if (ADD_2_STREAMS) { - rs_id_1 = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (rs_id_1, >, 0); - nice_agent_get_local_credentials(ragent, rs_id_1, &rufrag1, &rpassword1); - - rs_id_2 = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (rs_id_2, >, 0); - nice_agent_get_local_credentials(ragent, rs_id_2, &rufrag2, &rpassword2); - - nice_agent_set_remote_credentials (ragent, rs_id_2, lufrag, lpassword); - nice_agent_set_remote_credentials (lagent, ls_id, rufrag2, rpassword2); - - g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE); - g_assert (nice_agent_gather_candidates (ragent, rs_id_2) == TRUE); - g_assert (nice_agent_gather_candidates (ragent, rs_id_1) == TRUE); - - if (USE_SECOND_STREAM) { - set_candidates (ragent, rs_id_2, lagent, ls_id, NICE_COMPONENT_TYPE_RTP); - set_candidates (ragent, rs_id_2, lagent, ls_id, NICE_COMPONENT_TYPE_RTCP); - set_candidates (lagent, ls_id, ragent, rs_id_2, NICE_COMPONENT_TYPE_RTP); - set_candidates (lagent, ls_id, ragent, rs_id_2, NICE_COMPONENT_TYPE_RTCP); - } else { - set_candidates (ragent, rs_id_1, lagent, ls_id, NICE_COMPONENT_TYPE_RTP); - set_candidates (ragent, rs_id_1, lagent, ls_id, NICE_COMPONENT_TYPE_RTCP); - set_candidates (lagent, ls_id, ragent, rs_id_1, NICE_COMPONENT_TYPE_RTP); - set_candidates (lagent, ls_id, ragent, rs_id_1, NICE_COMPONENT_TYPE_RTCP); - } - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (ragent, rs_id_1, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, NULL); - nice_agent_attach_recv (ragent, rs_id_1, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, NULL); - nice_agent_attach_recv (ragent, rs_id_2, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, NULL); - nice_agent_attach_recv (ragent, rs_id_2, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, NULL); - } else { - rs_id_1 = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (rs_id_1, >, 0); - nice_agent_get_local_credentials(ragent, rs_id_1, &rufrag1, &rpassword1); - - nice_agent_set_remote_credentials (ragent, rs_id_1, lufrag, lpassword); - nice_agent_set_remote_credentials (lagent, ls_id, rufrag1, rpassword1); - - g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE); - g_assert (nice_agent_gather_candidates (ragent, rs_id_1) == TRUE); - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (ragent, rs_id_1, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, NULL); - nice_agent_attach_recv (ragent, rs_id_1, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, NULL); - - set_candidates (ragent, rs_id_1, lagent, ls_id, NICE_COMPONENT_TYPE_RTP); - set_candidates (ragent, rs_id_1, lagent, ls_id, NICE_COMPONENT_TYPE_RTCP); - set_candidates (lagent, ls_id, ragent, rs_id_1, NICE_COMPONENT_TYPE_RTP); - set_candidates (lagent, ls_id, ragent, rs_id_1, NICE_COMPONENT_TYPE_RTCP); - } - - /* step: run the mainloop until connectivity checks succeed - * (see timer_cb() above) */ - g_main_loop_run (global_mainloop); - - g_free (lufrag); - g_free (lpassword); - g_free (rufrag1); - g_free (rpassword1); - g_free (rufrag2); - g_free (rpassword2); - g_object_unref (lagent); - g_object_unref (ragent); - - g_main_loop_unref (global_mainloop); - global_mainloop = NULL; - - g_source_remove (timer_id); - -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - - return 0; -} diff --git a/tests/test-drop-invalid.c b/tests/test-drop-invalid.c deleted file mode 100644 index 88907ac..0000000 --- a/tests/test-drop-invalid.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * Unit test for ICE full-mode related features. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * (C) 2017 Collabora Ltd - * Contact: Olivier Crete - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" - -#include "socket/socket.h" - -#include -#include - - - -static NiceComponentState global_lagent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST }; -static NiceComponentState global_ragent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST }; -static guint global_components_ready = 0; -static guint global_components_ready_exit = 0; -static guint global_components_failed = 0; -static guint global_components_failed_exit = 0; -static GMainLoop *global_mainloop = NULL; -static gboolean global_lagent_gathering_done = FALSE; -static gboolean global_ragent_gathering_done = FALSE; -static gboolean global_lagent_ibr_received = FALSE; -static gboolean global_ragent_ibr_received = FALSE; -static int global_lagent_cands = 0; -static int global_ragent_cands = 0; -static gint global_ragent_read = 0; -static guint global_exit_when_ibr_received = 0; - -static void priv_print_global_status (void) -{ - g_debug ("\tgathering_done=%d", global_lagent_gathering_done && global_ragent_gathering_done); - g_debug ("\tlstate[rtp]=%d [rtcp]=%d", global_lagent_state[0], global_lagent_state[1]); - g_debug ("\trstate[rtp]=%d [rtcp]=%d", global_ragent_state[0], global_ragent_state[1]); - g_debug ("\tL cands=%d R cands=%d", global_lagent_cands, global_ragent_cands); -} - -static gboolean timer_cb (gpointer pointer) -{ - g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, pointer); - - /* signal status via a global variable */ - - /* note: should not be reached, abort */ - g_error ("ERROR: test has got stuck, aborting..."); - - return FALSE; -} - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, user_data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)buf; - - /* Core of the test - * Assert on any unreleated packet received. This would include anything - * send before the negotiation is over. - */ - g_assert_cmpuint (len, ==, 16); - g_assert (strncmp ("1234567812345678", buf, 16) == 0); - - if (component_id == 2) - return; - - if (GPOINTER_TO_UINT (user_data) == 2) { - g_debug ("right agent received %d bytes, stopping mainloop", len); - global_ragent_read = len; - g_main_loop_quit (global_mainloop); - } -} - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - global_lagent_gathering_done = TRUE; - else if (GPOINTER_TO_UINT (data) == 2) - global_ragent_gathering_done = TRUE; - - if (global_lagent_gathering_done && - global_ragent_gathering_done) - g_main_loop_quit (global_mainloop); - - /* XXX: dear compiler, these are for you: */ - (void)agent; -} - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - gboolean ready_to_connected = FALSE; - g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) { - if (global_lagent_state[component_id - 1] == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_lagent_state[component_id - 1] = state; - } else if (GPOINTER_TO_UINT (data) == 2) { - if (global_ragent_state[component_id - 1] == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_ragent_state[component_id - 1] = state; - } - - if (state == NICE_COMPONENT_STATE_READY) - global_components_ready++; - else if (state == NICE_COMPONENT_STATE_CONNECTED && ready_to_connected) - global_components_ready--; - if (state == NICE_COMPONENT_STATE_FAILED) - global_components_failed++; - - g_debug ("test-drop-invalid: checks READY/EXIT-AT %u/%u.", global_components_ready, global_components_ready_exit); - g_debug ("test-drop-invalid: checks FAILED/EXIT-AT %u/%u.", global_components_failed, global_components_failed_exit); - - /* signal status via a global variable */ - if (global_components_ready == global_components_ready_exit && - global_components_failed == global_components_failed_exit) { - g_debug ("Components ready/failed achieved. Stopping mailoop"); - g_main_loop_quit (global_mainloop); - return; - } - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; -} - -static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id, - gchar *lfoundation, gchar* rfoundation, gpointer data) -{ - g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - ++global_lagent_cands; - else if (GPOINTER_TO_UINT (data) == 2) - ++global_ragent_cands; - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)lfoundation; (void)rfoundation; -} - -static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, - gchar *foundation, gpointer data) -{ - g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; (void)foundation; -} - -static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - global_lagent_ibr_received = TRUE; - else if (GPOINTER_TO_UINT (data) == 2) - global_ragent_ibr_received = TRUE; - - if (global_exit_when_ibr_received) { - g_debug ("Received initial binding request. Stopping mailoop"); - g_main_loop_quit (global_mainloop); - } - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; -} - -static void set_candidates (NiceAgent *from, guint from_stream, - NiceAgent *to, guint to_stream, guint component) -{ - GSList *cands = NULL; - GSList *peer_cands = NULL; - GSList *item1, *item2; - - cands = nice_agent_get_local_candidates (from, from_stream, component); - peer_cands = nice_agent_get_local_candidates (to, to_stream, component); - - /* - * Core of the test: - * - * Send packets that shoudl be dropped. - */ - - for (item1 = cands; item1; item1 = item1->next) { - NiceCandidate *cand = item1->data; - NiceSocket *nicesock = cand->sockptr; - - g_assert (nicesock); - - for (item2 = peer_cands; item2; item2 = item2->next) { - NiceCandidate *target_cand = item2->data; - - nice_socket_send (nicesock, &target_cand->addr, 12, "123456789AB"); - } - - } - - nice_agent_set_remote_candidates (to, to_stream, component, cands); - - g_slist_free_full (cands, (GDestroyNotify) nice_candidate_free); - g_slist_free_full (peer_cands, (GDestroyNotify) nice_candidate_free); -} - -static void set_credentials (NiceAgent *lagent, guint lstream, - NiceAgent *ragent, guint rstream) -{ - gchar *ufrag = NULL, *password = NULL; - - nice_agent_get_local_credentials(lagent, lstream, &ufrag, &password); - nice_agent_set_remote_credentials (ragent, rstream, ufrag, password); - g_free (ufrag); - g_free (password); - nice_agent_get_local_credentials(ragent, rstream, &ufrag, &password); - nice_agent_set_remote_credentials (lagent, lstream, ufrag, password); - g_free (ufrag); - g_free (password); -} - -static guint16 -get_port (NiceAgent *agent, guint stream_id, guint component_id) -{ - GSList *cands = nice_agent_get_local_candidates (agent, stream_id, - component_id); - GSList *item; - guint16 port = 0; - - g_assert (cands != NULL); - - for (item = cands; item; item = item->next) { - NiceCandidate *cand = item->data; - port = nice_address_get_port (&cand->addr); - break; - } - g_assert (port != 0); - - g_slist_free_full (cands, (GDestroyNotify) nice_candidate_free); - - return port; -} - -static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr, guint ready, guint failed) -{ - guint ls_id, rs_id; - gint ret; - guint16 port; - - /* XXX: dear compiler, this is for you */ - (void)baseaddr; - - /* step: initialize variables modified by the callbacks */ - global_components_ready = 0; - global_components_ready_exit = ready; - global_components_failed = 0; - global_components_failed_exit = failed; - global_lagent_gathering_done = FALSE; - global_ragent_gathering_done = FALSE; - global_lagent_ibr_received = - global_ragent_ibr_received = FALSE; - global_lagent_cands = - global_ragent_cands = 0; - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - /* step: add one stream, with RTP+RTCP components, to each agent */ - ls_id = nice_agent_add_stream (lagent, 2); - - rs_id = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - - /* Gather candidates and test nice_agent_set_port_range */ - nice_agent_set_port_range (lagent, ls_id, 1, 10000, 11000); - nice_agent_set_port_range (lagent, ls_id, 2, 11000, 12000); - g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE); - - port = get_port (lagent, ls_id, 1); - nice_agent_set_port_range (ragent, rs_id, 1, 12000, 13000); - nice_agent_set_port_range (ragent, rs_id, 2, port, port); - g_assert (nice_agent_gather_candidates (ragent, rs_id) == FALSE); - g_assert (nice_agent_get_local_candidates (ragent, rs_id, 1) == NULL); - g_assert (nice_agent_get_local_candidates (ragent, rs_id, 2) == NULL); - nice_agent_set_port_range (ragent, rs_id, 2, 13000, 14000); - g_assert (nice_agent_gather_candidates (ragent, rs_id) == TRUE); - - { - GSList *cands = NULL, *i; - NiceCandidate *cand = NULL; - - cands = nice_agent_get_local_candidates (lagent, ls_id, 1); - g_assert_cmpuint (g_slist_length (cands), ==, 1); - cand = cands->data; - g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST); - g_assert_cmpuint (nice_address_get_port (&cand->addr), >=, 10000); - g_assert_cmpuint (nice_address_get_port (&cand->addr), <=, 11000); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - cands = nice_agent_get_local_candidates (lagent, ls_id, 2); - g_assert_cmpuint (g_slist_length (cands), ==, 1); - cand = cands->data; - g_assert_cmpuint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST); - g_assert_cmpuint (nice_address_get_port (&cand->addr), >=, 11000); - g_assert_cmpuint (nice_address_get_port (&cand->addr), <=, 12000); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - cands = nice_agent_get_local_candidates (ragent, rs_id, 1); - g_assert_cmpuint (g_slist_length (cands), ==, 1); - cand = cands->data; - g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST); - g_assert_cmpuint (nice_address_get_port (&cand->addr), >=, 12000); - g_assert_cmpuint (nice_address_get_port (&cand->addr), <=, 13000); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - cands = nice_agent_get_local_candidates (ragent, rs_id, 2); - g_assert_cmpuint (g_slist_length (cands), ==, 1); - cand = cands->data; - g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST); - g_assert_cmpuint (nice_address_get_port (&cand->addr), >=, 13000); - g_assert_cmpuint (nice_address_get_port (&cand->addr), <=, 14000); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - } - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - - /* step: run mainloop until local candidates are ready - * (see timer_cb() above) */ - if (global_lagent_gathering_done != TRUE || - global_ragent_gathering_done != TRUE) { - g_debug ("test-drop-invalid: Added streams, running mainloop until 'candidate-gathering-done'..."); - g_main_loop_run (global_mainloop); - g_assert (global_lagent_gathering_done == TRUE); - g_assert (global_ragent_gathering_done == TRUE); - } - - set_credentials (lagent, ls_id, ragent, rs_id); - - /* step: pass the remote candidates to agents */ - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP); - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTCP); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTCP); - - g_debug ("test-drop-invalid: Set properties, next running mainloop until connectivity checks succeed..."); - - /* step: run the mainloop until connectivity checks succeed - * (see timer_cb() above) */ - g_main_loop_run (global_mainloop); - - /* note: verify that STUN binding requests were sent */ - g_assert (global_lagent_ibr_received == TRUE); - g_assert (global_ragent_ibr_received == TRUE); - - /* note: Send a packet from another address */ - /* These should also be ignored */ - { - NiceCandidate *local_cand = NULL; - NiceCandidate *remote_cand = NULL; - NiceSocket *tmpsock; - - g_assert (nice_agent_get_selected_pair (lagent, ls_id, 1, &local_cand, - &remote_cand)); - g_assert (local_cand); - g_assert (remote_cand); - - tmpsock = nice_udp_bsd_socket_new (NULL); - nice_socket_send (tmpsock, &remote_cand->addr, 4, "ABCD"); - nice_socket_send (tmpsock, &local_cand->addr, 5, "ABCDE"); - nice_socket_free (tmpsock); - } - - /* note: test payload send and receive */ - global_ragent_read = 0; - ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"); - g_assert (ret != -1); - g_debug ("Sent %d bytes", ret); - g_assert_cmpint (ret, ==, 16); - while (global_ragent_read != 16) - g_main_context_iteration (NULL, TRUE); - g_assert_cmpint (global_ragent_read, ==, 16); - - g_debug ("test-drop-invalid: Ran mainloop, removing streams..."); - - /* step: clean up resources and exit */ - - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - return 0; -} - -int main (void) -{ - NiceAgent *lagent, *ragent; /* agent's L and R */ - NiceAddress baseaddr; - int result; - guint timer_id; - -#ifdef G_OS_WIN32 - WSADATA w; - - WSAStartup(0x0202, &w); -#endif - - global_mainloop = g_main_loop_new (NULL, FALSE); - - /* step: create the agents L and R */ - lagent = nice_agent_new (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY_RFC5245); - ragent = nice_agent_new (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY_RFC5245); - - g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL); - - g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); - - nice_agent_set_software (lagent, "test-drop-invalid, Left Agent"); - nice_agent_set_software (ragent, "test-drop-invalid, Right Agent"); - - /* step: add a timer to catch state changes triggered by signals */ - timer_id = g_timeout_add (30000, timer_cb, NULL); - - /* step: specify which local interface to use */ - if (!nice_address_set_from_string (&baseaddr, "127.0.0.1")) - g_assert_not_reached (); - nice_agent_add_local_address (lagent, &baseaddr); - nice_agent_add_local_address (ragent, &baseaddr); - - g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "new-candidate", - G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "new-candidate", - G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), - GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), - GUINT_TO_POINTER (2)); - - g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); - - - /* step: run test the first time */ - g_debug ("test-drop-invalid: TEST STARTS / running test for the 1st time"); - result = run_full_test (lagent, ragent, &baseaddr, 4 ,0); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY); - /* When using TURN, we get peer reflexive candidates for the host cands - that we removed so we can get another new_selected_pair signal later - depending on timing/racing, we could double (or not) the amount we expected - */ - - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (global_lagent_cands, ==, 2); - g_assert_cmpint (global_ragent_cands, ==, 2); - - g_object_unref (lagent); - g_object_unref (ragent); - - g_main_loop_unref (global_mainloop); - global_mainloop = NULL; - - g_source_remove (timer_id); -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return result; -} diff --git a/tests/test-fallback.c b/tests/test-fallback.c deleted file mode 100644 index 02aa22e..0000000 --- a/tests/test-fallback.c +++ /dev/null @@ -1,575 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * Contains a unit test for functionality to fallback to non-ICE - * operation if remote party does not support ICE. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "agent-priv.h" /* for testing purposes */ - -#include -#include -#ifdef _WIN32 -#include -#endif - - -static NiceComponentState global_lagent_state = NICE_COMPONENT_STATE_LAST; -static NiceComponentState global_ragent_state = NICE_COMPONENT_STATE_LAST; -static guint global_components_ready = 0; -static guint global_components_ready_exit = 0; -static guint global_components_failed = 0; -static guint global_components_failed_exit = 0; -static GMainLoop *global_mainloop = NULL; -static gboolean global_lagent_gathering_done = FALSE; -static gboolean global_ragent_gathering_done = FALSE; -static gboolean global_lagent_ibr_received = FALSE; -static gboolean global_ragent_ibr_received = FALSE; -static int global_lagent_cands = 0; -static int global_ragent_cands = 0; -static gint global_ragent_read = 0; -static gint global_ragent_read_exit = 0; -static gboolean global_accept_non_data = TRUE; - -static void priv_print_global_status (void) -{ - g_debug ("\tgathering_done=%d", global_lagent_gathering_done && global_ragent_gathering_done); - g_debug ("\tlstate=%d", global_lagent_state); - g_debug ("\trstate=%d", global_ragent_state); -} - -static gboolean timer_cb (gpointer pointer) -{ - g_debug ("test-fallback:%s: %p", G_STRFUNC, pointer); - - /* signal status via a global variable */ - - /* note: should not be reached, abort */ - g_error ("ERROR: test has got stuck, aborting..."); - - return FALSE; -} - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - g_debug ("test-fallback:%s: %p", G_STRFUNC, user_data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)buf; - - /* - * Lets ignore stun packets that got through - */ - if (len != 16 || strncmp ("1234567812345678", buf, 16)) { - if (global_accept_non_data) - return; - else - g_error ("Got non-data packet of lenght %u", len); - } - - if ((intptr_t)user_data == 2) { - global_ragent_read += len; - - if (global_ragent_read == global_ragent_read_exit) - g_main_loop_quit (global_mainloop); - } -} - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-fallback:%s: %p", G_STRFUNC, data); - - if ((intptr_t)data == 1) - global_lagent_gathering_done = TRUE; - else if ((intptr_t)data == 2) - global_ragent_gathering_done = TRUE; - - if (global_lagent_gathering_done && - global_ragent_gathering_done) - g_main_loop_quit (global_mainloop); - - /* XXX: dear compiler, these are for you: */ - (void)agent; -} - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - g_debug ("test-fallback:%s: %p", G_STRFUNC, data); - - if ((intptr_t)data == 1) - global_lagent_state = state; - else if ((intptr_t)data == 2) - global_ragent_state = state; - - if (state == NICE_COMPONENT_STATE_READY) - global_components_ready++; - if (state == NICE_COMPONENT_STATE_FAILED) - global_components_failed++; - - g_debug ("test-fallback: READY %u exit at %u.", global_components_ready, global_components_ready_exit); - - /* signal status via a global variable */ - if (global_components_ready == global_components_ready_exit) { - g_main_loop_quit (global_mainloop); - return; - } - - /* signal status via a global variable */ - if (global_components_failed == global_components_failed_exit) { - g_main_loop_quit (global_mainloop); - return; - } - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; -} - -static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id, - gchar *lfoundation, gchar* rfoundation, gpointer data) -{ - g_debug ("test-fallback:%s: %p", G_STRFUNC, data); - - if ((intptr_t)data == 1) - ++global_lagent_cands; - else if ((intptr_t)data == 2) - ++global_ragent_cands; - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)lfoundation; (void)rfoundation; -} - -static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, - gchar *foundation, gpointer data) -{ - g_debug ("test-fallback:%s: %p", G_STRFUNC, data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; (void)foundation; -} - -static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-fallback:%s: %p", G_STRFUNC, data); - - if ((intptr_t)data == 1) - global_lagent_ibr_received = TRUE; - else if ((intptr_t)data == 2) - global_ragent_ibr_received = TRUE; - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; -} - -static void priv_get_local_addr (NiceAgent *agent, guint stream_id, guint component_id, NiceAddress *dstaddr) -{ - GSList *cands, *i; - cands = nice_agent_get_local_candidates(agent, stream_id, component_id); - for (i = cands; i; i = i->next) { - NiceCandidate *cand = i->data; - if (cand) { - g_assert (dstaddr); - *dstaddr = cand->addr; - break; - } - } - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); -} - -static int run_fallback_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr) -{ - NiceAddress laddr, raddr, laddr_rtcp, raddr_rtcp; - NiceCandidate cdes; - GSList *cands; - guint ls_id, rs_id; - - memset (&cdes, 0, sizeof(NiceCandidate)); - cdes.priority = 100000; - strcpy (cdes.foundation, "1"); - cdes.type = NICE_CANDIDATE_TYPE_HOST; - cdes.transport = NICE_CANDIDATE_TRANSPORT_UDP; - cdes.base_addr = *baseaddr; - - /* step: initialize variables modified by the callbacks */ - global_components_ready = 0; - global_components_ready_exit = 4; - global_components_failed = 0; - global_components_failed_exit = 4; - global_lagent_gathering_done = FALSE; - global_ragent_gathering_done = FALSE; - global_lagent_ibr_received = - global_ragent_ibr_received = FALSE; - global_lagent_cands = - global_ragent_cands = 0; - global_ragent_read_exit = -1; - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - /* step: add one stream, with RTP+RTCP components, to each agent */ - ls_id = nice_agent_add_stream (lagent, 2); - rs_id = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - - nice_agent_gather_candidates (lagent, ls_id); - nice_agent_gather_candidates (ragent, rs_id); - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)1); - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)1); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)2); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)2); - - /* step: run mainloop until local candidates are ready - * (see timer_cb() above) */ - if (global_lagent_gathering_done != TRUE || - global_ragent_gathering_done != TRUE) { - g_debug ("test-fallback: Added streams, running mainloop until 'candidate-gathering-done'..."); - g_main_loop_run (global_mainloop); - g_assert (global_lagent_gathering_done == TRUE); - g_assert (global_ragent_gathering_done == TRUE); - } - - /* step: find out the local candidates of each agent */ - - priv_get_local_addr (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, &raddr); - g_debug ("test-fallback: local RTP port R %u", - nice_address_get_port (&raddr)); - - priv_get_local_addr (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, &laddr); - g_debug ("test-fallback: local RTP port L %u", - nice_address_get_port (&laddr)); - - priv_get_local_addr (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, &raddr_rtcp); - g_debug ("test-fallback: local RTCP port R %u", - nice_address_get_port (&raddr_rtcp)); - - priv_get_local_addr (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, &laddr_rtcp); - g_debug ("test-fallback: local RTCP port L %u", - nice_address_get_port (&laddr_rtcp)); - - /* step: exchange candidate information but not the credentials */ - - cands = g_slist_append (NULL, &cdes); - cdes.component_id = NICE_COMPONENT_TYPE_RTP; - cdes.addr = raddr; - nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, cands); - cdes.addr = laddr; - nice_agent_set_remote_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, cands); - cdes.component_id = NICE_COMPONENT_TYPE_RTCP; - cdes.addr = raddr_rtcp; - nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, cands); - cdes.addr = laddr_rtcp; - nice_agent_set_remote_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, cands); - - /* step: fall back to non-ICE mode on both sides */ - g_assert (nice_agent_set_selected_pair (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, "1", "1") == TRUE); - g_assert (nice_agent_set_selected_pair (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, "1", "1") == TRUE); - g_assert (nice_agent_set_selected_pair (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, "1", "1") == TRUE); - g_assert (nice_agent_set_selected_pair (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, "1", "1") == TRUE); - - g_debug ("test-fallback: Requested for fallback, running mainloop until component state change is completed..."); - - /* step: run the mainloop until connectivity checks succeed - * (see timer_cb() above) */ - if (global_components_ready < global_components_ready_exit) - g_main_loop_run (global_mainloop); - - /* note: verify that agents are in correct state */ - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, ==, NICE_COMPONENT_STATE_READY); - - /* step: next send a packet -> should work even if no ICE processing - * has been done */ - - g_debug ("test-fallback: Sent a payload packet, run mainloop until packet received."); - - /* step: send a new test packet from L ot R */ - global_ragent_read = 0; - g_assert_cmpint (nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"), ==, 16); - global_ragent_read_exit = 16; - g_main_loop_run (global_mainloop); - - /* note: verify that payload was succesfully received */ - g_assert_cmpint (global_ragent_read, ==, 16); - - g_debug ("test-fallback: Ran mainloop, removing streams..."); - - /* step: clean up resources and exit */ - - g_slist_free (cands); - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - g_debug ("test-fallback: test COMPLETED"); - - return 0; -} - - -static int run_safe_fallback_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr) -{ - NiceAddress laddr, raddr, laddr_rtcp, raddr_rtcp; - NiceCandidate cdes; - guint ls_id, rs_id; - - memset (&cdes, 0, sizeof(NiceCandidate)); - cdes.priority = 100000; - strcpy (cdes.foundation, "1"); - cdes.type = NICE_CANDIDATE_TYPE_HOST; - cdes.transport = NICE_CANDIDATE_TRANSPORT_UDP; - cdes.base_addr = *baseaddr; - - /* step: initialize variables modified by the callbacks */ - global_components_ready = 0; - global_components_ready_exit = 4; - global_components_failed = 0; - global_components_failed_exit = 4; - global_lagent_gathering_done = FALSE; - global_ragent_gathering_done = FALSE; - global_lagent_ibr_received = - global_ragent_ibr_received = FALSE; - global_lagent_cands = - global_ragent_cands = 0; - global_ragent_read_exit = -1; - global_accept_non_data = FALSE; - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - /* step: add one stream, with RTP+RTCP components, to each agent */ - ls_id = nice_agent_add_stream (lagent, 2); - rs_id = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - - nice_agent_gather_candidates (lagent, ls_id); - nice_agent_gather_candidates (ragent, rs_id); - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)1); - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)1); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)2); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)2); - - /* step: run mainloop until local candidates are ready - * (see timer_cb() above) */ - if (global_lagent_gathering_done != TRUE || - global_ragent_gathering_done != TRUE) { - g_debug ("test-fallback: Added streams, running mainloop until 'candidate-gathering-done'..."); - g_main_loop_run (global_mainloop); - g_assert (global_lagent_gathering_done == TRUE); - g_assert (global_ragent_gathering_done == TRUE); - } - - /* step: find out the local candidates of each agent */ - - priv_get_local_addr (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, &raddr); - g_debug ("test-fallback: local RTP port R %u", - nice_address_get_port (&raddr)); - - priv_get_local_addr (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, &laddr); - g_debug ("test-fallback: local RTP port L %u", - nice_address_get_port (&laddr)); - - priv_get_local_addr (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, &raddr_rtcp); - g_debug ("test-fallback: local RTCP port R %u", - nice_address_get_port (&raddr_rtcp)); - - priv_get_local_addr (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, &laddr_rtcp); - g_debug ("test-fallback: local RTCP port L %u", - nice_address_get_port (&laddr_rtcp)); - - /* step: exchange candidate information but not the credentials */ - - cdes.component_id = NICE_COMPONENT_TYPE_RTP; - cdes.addr = raddr; - g_assert (nice_agent_set_selected_remote_candidate (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, &cdes)); - - cdes.addr = laddr; - g_assert (nice_agent_set_selected_remote_candidate (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, &cdes)); - - cdes.component_id = NICE_COMPONENT_TYPE_RTCP; - cdes.addr = raddr_rtcp; - g_assert (nice_agent_set_selected_remote_candidate (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, &cdes)); - - cdes.addr = laddr_rtcp; - g_assert (nice_agent_set_selected_remote_candidate (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, &cdes)); - - g_debug ("test-fallback: Requested for fallback, running mainloop until component state change is completed..."); - - /* step: run the mainloop until connectivity checks succeed - * (see timer_cb() above) */ - if (global_components_ready < global_components_ready_exit) - g_main_loop_run (global_mainloop); - - /* note: verify that agents are in correct state */ - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, ==, NICE_COMPONENT_STATE_READY); - - /* step: next send a packet -> should work even if no ICE processing - * has been done */ - - g_debug ("test-fallback: Sent a payload packet, run mainloop until packet received."); - - /* step: send a new test packet from L ot R */ - global_ragent_read = 0; - g_assert_cmpint (nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"), ==, 16); - global_ragent_read_exit = 16; - g_main_loop_run (global_mainloop); - - /* note: verify that payload was succesfully received */ - g_assert_cmpint (global_ragent_read, ==, 16); - - g_debug ("test-fallback: Ran mainloop, removing streams..."); - - /* step: clean up resources and exit */ - - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - g_debug ("test-fallback: test COMPLETED"); - - return 0; -} - -int main (void) -{ - NiceAgent *lagent, *ragent; /* agent's L and R */ - NiceAddress baseaddr; - int result; - guint timer_id; - const char *stun_server = NULL, *stun_server_port = NULL; - -#ifdef G_OS_WIN32 - WSADATA w; - - WSAStartup(0x0202, &w); -#endif - - global_mainloop = g_main_loop_new (NULL, FALSE); - - /* Note: impl limits ... - * - no multi-stream support - * - no IPv6 support - */ - - /* step: create the agents L and R */ - lagent = nice_agent_new (g_main_loop_get_context (global_mainloop), NICE_COMPATIBILITY_RFC5245); - ragent = nice_agent_new (g_main_loop_get_context (global_mainloop), NICE_COMPATIBILITY_RFC5245); - - g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); - - /* step: add a timer to catch state changes triggered by signals */ - timer_id = g_timeout_add (30000, timer_cb, NULL); - - /* step: specify which local interface to use */ - if (!nice_address_set_from_string (&baseaddr, "127.0.0.1")) - g_assert_not_reached (); - nice_agent_add_local_address (lagent, &baseaddr); - nice_agent_add_local_address (ragent, &baseaddr); - - g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), (gpointer)1); - g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), (gpointer)2); - g_signal_connect (G_OBJECT (lagent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), (gpointer)1); - g_signal_connect (G_OBJECT (ragent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), (gpointer)2); - g_signal_connect (G_OBJECT (lagent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), (gpointer)1); - g_signal_connect (G_OBJECT (ragent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), (gpointer)2); - g_signal_connect (G_OBJECT (lagent), "new-candidate", - G_CALLBACK (cb_new_candidate), (gpointer)1); - g_signal_connect (G_OBJECT (ragent), "new-candidate", - G_CALLBACK (cb_new_candidate), (gpointer)2); - g_signal_connect (G_OBJECT (lagent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), (gpointer)1); - g_signal_connect (G_OBJECT (ragent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), (gpointer)2); - - stun_server = getenv ("NICE_STUN_SERVER"); - stun_server_port = getenv ("NICE_STUN_SERVER_PORT"); - if (stun_server) { - g_object_set (G_OBJECT (lagent), "stun-server", stun_server, NULL); - g_object_set (G_OBJECT (lagent), "stun-server-port", atoi (stun_server_port), NULL); - g_object_set (G_OBJECT (ragent), "stun-server", stun_server, NULL); - g_object_set (G_OBJECT (ragent), "stun-server-port", atoi (stun_server_port), NULL); - } - - /* step: run test the first time */ - g_debug ("test-fallback: TEST STARTS / fallback test"); - result = run_fallback_test (lagent, ragent, &baseaddr); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, ==, NICE_COMPONENT_STATE_READY); - - /* step: run the safe test without sending any stnu */ - g_debug ("test-fallback: TEST STARTS / safe fallback test"); - result = run_safe_fallback_test (lagent, ragent, &baseaddr); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, ==, NICE_COMPONENT_STATE_READY); - - g_object_unref (lagent); - g_object_unref (ragent); - - g_main_loop_unref (global_mainloop); - global_mainloop = NULL; - - g_source_remove (timer_id); -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return result; -} diff --git a/tests/test-fullmode-with-stun.c b/tests/test-fullmode-with-stun.c deleted file mode 100644 index 280d421..0000000 --- a/tests/test-fullmode-with-stun.c +++ /dev/null @@ -1,51 +0,0 @@ -#include - -int -main (int argc, char ** argv) -{ - int retval = 0; - char *stund; - char *test_fullmode; - GSubprocess *stund_proc, *test_subprocess; - const gchar NICE_STUN_SERVER[] = "127.0.0.1"; - const gchar NICE_STUN_SERVER_PORT[] = "3800"; - GError *gerr = NULL; - - if (argc < 3) { - g_printerr ("Usage: %s \n", - argv[0]); - return 77; - } - - stund = argv[1]; - test_fullmode = argv[2]; - - g_print ("Starting ICE full-mode with STUN unit test.\n"); - g_print ("Launching %s on port %s.\n", stund, NICE_STUN_SERVER_PORT); - - - stund_proc = g_subprocess_new (G_SUBPROCESS_FLAGS_NONE, &gerr, - stund, NICE_STUN_SERVER_PORT, NULL); - - g_usleep(G_USEC_PER_SEC); - - g_setenv("NICE_STUN_SERVER", NICE_STUN_SERVER, TRUE); - g_setenv("NICE_STUN_SERVER_PORT", NICE_STUN_SERVER_PORT, TRUE); - - g_print ("Running test fullmode as %s\n", test_fullmode); - test_subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_NONE, &gerr, - test_fullmode, NULL); - g_assert_no_error (gerr); - g_subprocess_wait (test_subprocess, NULL, &gerr); - g_assert_no_error (gerr); - retval = g_subprocess_get_exit_status (test_subprocess); - g_print ("Test process returned %d\n", retval); - g_object_unref (test_subprocess); - - g_subprocess_force_exit (stund_proc); - g_subprocess_wait (stund_proc, NULL, &gerr); - g_assert_no_error (gerr); - g_object_unref(stund_proc); - - return retval; -} diff --git a/tests/test-fullmode.c b/tests/test-fullmode.c deleted file mode 100644 index 4bcec49..0000000 --- a/tests/test-fullmode.c +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * Unit test for ICE full-mode related features. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" - -#include -#include - - -#define USE_TURN 0 -#define USE_LOOPBACK 1 -#define USE_PROXY 0 -#define USE_UPNP 0 -#define USE_RELIABLE 0 -#define TEST_GOOGLE 0 - -#define PROXY_IP "127.0.0.1" -#define PROXY_PORT 1080 -#define PROXY_USERNAME NULL -#define PROXY_PASSWORD NULL - -#if USE_PROXY -#define PROXY_TYPE NICE_PROXY_TYPE_SOCKS5 -#else -#define PROXY_TYPE NICE_PROXY_TYPE_NONE -#endif - -#if TEST_GOOGLE -#define NICE_COMPATIBILITY NICE_COMPATIBILITY_GOOGLE - -#if USE_TURN -#undef USE_LOOPBACK -#define USE_LOOPBACK 0 - -#define TURN_IP "209.85.163.126" -#define TURN_PORT 443 -#define TURN_USER "ih9ppiM0P6vN34DB" -#define TURN_PASS "" -#define TURN_USER2 TURN_USER -#define TURN_PASS2 TURN_PASS -#define TURN_TYPE NICE_RELAY_TYPE_TURN_TLS - -#endif - -#else -#define NICE_COMPATIBILITY NICE_COMPATIBILITY_RFC5245 -#if USE_LOOPBACK -#define USE_TURN_SERVER_ORG 1 -#else -#define USE_TURN_SERVER_ORG 0 -#endif - -#define NUMB_IP "64.251.22.149" -#define NUMB_PORT 3478 -#define NUMB_USER "youness.alaoui@collabora.co.uk" -#define NUMB_PASS "badger" - -#define TSORG_IP "127.0.0.1" -#define TSORG_PORT 3478 -#define TSORG_USER "toto" -#define TSORG_PASS "password" - - -#if USE_TURN_SERVER_ORG -#define TURN_IP TSORG_IP -#define TURN_PORT TSORG_PORT -#define TURN_USER TSORG_USER -#define TURN_PASS TSORG_PASS -#define TURN_USER2 TSORG_USER -#define TURN_PASS2 TSORG_PASS -#define TURN_TYPE NICE_RELAY_TYPE_TURN_TCP -#else -#define TURN_IP NUMB_IP -#define TURN_PORT NUMB_PORT -#define TURN_USER NUMB_USER -#define TURN_PASS NUMB_PASS -#define TURN_USER2 NUMB_USER -#define TURN_PASS2 NUMB_PASS -#define TURN_TYPE NICE_RELAY_TYPE_TURN_UDP -#endif - -#endif - - -static NiceComponentState global_lagent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST }; -static NiceComponentState global_ragent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST }; -static guint global_components_ready = 0; -static guint global_components_ready_exit = 0; -static guint global_components_failed = 0; -static guint global_components_failed_exit = 0; -static GMainLoop *global_mainloop = NULL; -static gboolean global_lagent_gathering_done = FALSE; -static gboolean global_ragent_gathering_done = FALSE; -static gboolean global_lagent_ibr_received = FALSE; -static gboolean global_ragent_ibr_received = FALSE; -static int global_lagent_cands = 0; -static int global_ragent_cands = 0; -static gint global_ragent_read = 0; -static guint global_exit_when_ibr_received = 0; - -static void priv_print_global_status (void) -{ - g_debug ("\tgathering_done=%d", global_lagent_gathering_done && global_ragent_gathering_done); - g_debug ("\tlstate[rtp]=%d [rtcp]=%d", global_lagent_state[0], global_lagent_state[1]); - g_debug ("\trstate[rtp]=%d [rtcp]=%d", global_ragent_state[0], global_ragent_state[1]); - g_debug ("\tL cands=%d R cands=%d", global_lagent_cands, global_ragent_cands); -} - -static gboolean timer_cb (gpointer pointer) -{ - g_debug ("test-fullmode:%s: %p", G_STRFUNC, pointer); - - /* signal status via a global variable */ - - /* note: should not be reached, abort */ - g_error ("ERROR: test has got stuck, aborting..."); - - return FALSE; -} - -static void cb_writable (NiceAgent*agent, guint stream_id, guint component_id, - gpointer user_data) -{ - guint *ls_id = user_data; - - if (stream_id == *ls_id && component_id == 1) { - g_debug ("Transport is now writable, stopping mainloop"); - *ls_id = 0; - } -} - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - g_debug ("test-fullmode:%s: %p", G_STRFUNC, user_data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)buf; - - /* - * Lets ignore stun packets that got through - */ - if (len < 8) - return; - if (strncmp ("12345678", buf, 8)) - return; - - if (component_id == 2) - return; - - if (GPOINTER_TO_UINT (user_data) == 2) { - g_debug ("right agent received %d bytes, stopping mainloop", len); - global_ragent_read = len; - g_main_loop_quit (global_mainloop); - } -} - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-fullmode:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - global_lagent_gathering_done = TRUE; - else if (GPOINTER_TO_UINT (data) == 2) - global_ragent_gathering_done = TRUE; - - if (global_lagent_gathering_done && - global_ragent_gathering_done) - g_main_loop_quit (global_mainloop); - - /* XXX: dear compiler, these are for you: */ - (void)agent; -} - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - gboolean ready_to_connected = FALSE; - g_debug ("test-fullmode:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) { - if (global_lagent_state[component_id - 1] == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_lagent_state[component_id - 1] = state; - } else if (GPOINTER_TO_UINT (data) == 2) { - if (global_ragent_state[component_id - 1] == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_ragent_state[component_id - 1] = state; - } - - if (state == NICE_COMPONENT_STATE_READY) - global_components_ready++; - else if (state == NICE_COMPONENT_STATE_CONNECTED && ready_to_connected) - global_components_ready--; - if (state == NICE_COMPONENT_STATE_FAILED) - global_components_failed++; - - g_debug ("test-fullmode: checks READY/EXIT-AT %u/%u.", global_components_ready, global_components_ready_exit); - g_debug ("test-fullmode: checks FAILED/EXIT-AT %u/%u.", global_components_failed, global_components_failed_exit); - - /* signal status via a global variable */ - if (global_components_ready == global_components_ready_exit && - global_components_failed == global_components_failed_exit) { - g_debug ("Components ready/failed achieved. Stopping mailoop"); - g_main_loop_quit (global_mainloop); - return; - } - -#if 0 - /* signal status via a global variable */ - if (global_components_failed == global_components_failed_exit) { - g_main_loop_quit (global_mainloop); - return; - } -#endif - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; -} - -static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id, - gchar *lfoundation, gchar* rfoundation, gpointer data) -{ - g_debug ("test-fullmode:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - ++global_lagent_cands; - else if (GPOINTER_TO_UINT (data) == 2) - ++global_ragent_cands; - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)lfoundation; (void)rfoundation; -} - -static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, - gchar *foundation, gpointer data) -{ - g_debug ("test-fullmode:%s: %p", G_STRFUNC, data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; (void)foundation; -} - -static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-fullmode:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - global_lagent_ibr_received = TRUE; - else if (GPOINTER_TO_UINT (data) == 2) - global_ragent_ibr_received = TRUE; - - if (global_exit_when_ibr_received) { - g_debug ("Received initial binding request. Stopping mailoop"); - g_main_loop_quit (global_mainloop); - } - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; -} - -static void cb_closed (GObject *src, GAsyncResult *result, gpointer data) -{ - NiceAgent *agent = NICE_AGENT (src); - - g_debug ("test-fullmode:%s: %p", G_STRFUNC, agent); - - *((gboolean *)data) = TRUE; -} - -static void set_candidates (NiceAgent *from, guint from_stream, - NiceAgent *to, guint to_stream, guint component, gboolean remove_non_relay) -{ - GSList *cands = NULL, *i; - - cands = nice_agent_get_local_candidates (from, from_stream, component); - if (remove_non_relay) { - restart: - for (i = cands; i; i = i->next) { - NiceCandidate *cand = i->data; - if (cand->type != NICE_CANDIDATE_TYPE_RELAYED) { - cands = g_slist_remove (cands, cand); - nice_candidate_free (cand); - goto restart; - } - } - } - nice_agent_set_remote_candidates (to, to_stream, component, cands); - - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); -} - -static void set_credentials (NiceAgent *lagent, guint lstream, - NiceAgent *ragent, guint rstream) -{ - gchar *ufrag = NULL, *password = NULL; - - nice_agent_get_local_credentials(lagent, lstream, &ufrag, &password); - nice_agent_set_remote_credentials (ragent, rstream, ufrag, password); - g_free (ufrag); - g_free (password); - nice_agent_get_local_credentials(ragent, rstream, &ufrag, &password); - nice_agent_set_remote_credentials (lagent, lstream, ufrag, password); - g_free (ufrag); - g_free (password); -} - -static guint16 -get_port (NiceAgent *agent, guint stream_id, guint component_id) -{ - GSList *cands = nice_agent_get_local_candidates (agent, stream_id, - component_id); - GSList *item; - guint16 port = 0; - - g_assert (cands != NULL); - - for (item = cands; item; item = item->next) { - NiceCandidate *cand = item->data; - port = nice_address_get_port (&cand->addr); - break; - } - g_assert (port != 0); - - g_slist_free_full (cands, (GDestroyNotify) nice_candidate_free); - - return port; -} - -static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr, guint ready, guint failed) -{ - guint ls_id, rs_id; - gint ret; - guint16 port; - - /* XXX: dear compiler, this is for you */ - (void)baseaddr; - - /* step: initialize variables modified by the callbacks */ - global_components_ready = 0; - global_components_ready_exit = ready; - global_components_failed = 0; - global_components_failed_exit = failed; - global_lagent_gathering_done = FALSE; - global_ragent_gathering_done = FALSE; - global_lagent_ibr_received = - global_ragent_ibr_received = FALSE; - global_lagent_cands = - global_ragent_cands = 0; - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - /* step: add one stream, with RTP+RTCP components, to each agent */ - ls_id = nice_agent_add_stream (lagent, 2); - - rs_id = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); -#if USE_TURN - nice_agent_set_relay_info(lagent, ls_id, 1, - TURN_IP, TURN_PORT, TURN_USER, TURN_PASS, TURN_TYPE); - nice_agent_set_relay_info(lagent, ls_id, 2, - TURN_IP, TURN_PORT, TURN_USER, TURN_PASS, TURN_TYPE); - nice_agent_set_relay_info(ragent, rs_id, 1, - TURN_IP, TURN_PORT, TURN_USER2, TURN_PASS2, TURN_TYPE); - nice_agent_set_relay_info(ragent, rs_id, 2, - TURN_IP, TURN_PORT, TURN_USER2, TURN_PASS2, TURN_TYPE); -#endif - - - /* Gather candidates and test nice_agent_set_port_range */ - for (port = 10000; port < 60000; port++) { - nice_agent_set_port_range (lagent, ls_id, 1, port, port); - if (nice_agent_gather_candidates (lagent, ls_id)) - break; - } - - g_assert_cmpuint (port, ==, get_port (lagent, ls_id, 1)); - - nice_agent_set_port_range (ragent, rs_id, 2, port, port); - - g_assert (nice_agent_gather_candidates (ragent, rs_id) == FALSE); - g_assert (nice_agent_get_local_candidates (ragent, rs_id, 1) == NULL); - g_assert (nice_agent_get_local_candidates (ragent, rs_id, 2) == NULL); - nice_agent_set_port_range (ragent, rs_id, 2, 0, 0); - g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE); - g_assert (nice_agent_gather_candidates (ragent, rs_id) == TRUE); - -#if USE_LOOPBACK - { - GSList *cands = NULL, *i; - NiceCandidate *cand = NULL; - - cands = nice_agent_get_local_candidates (lagent, ls_id, 1); - g_assert_cmpuint (g_slist_length (cands), ==, 1); - cand = cands->data; - g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - cands = nice_agent_get_local_candidates (lagent, ls_id, 2); - g_assert_cmpuint (g_slist_length (cands), ==, 1); - cand = cands->data; - g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - cands = nice_agent_get_local_candidates (ragent, rs_id, 1); - g_assert_cmpuint (g_slist_length (cands), ==, 1); - cand = cands->data; - g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - cands = nice_agent_get_local_candidates (ragent, rs_id, 2); - g_assert_cmpuint (g_slist_length (cands), ==, 1); - cand = cands->data; - g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - } -#endif - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - - /* step: run mainloop until local candidates are ready - * (see timer_cb() above) */ - if (global_lagent_gathering_done != TRUE || - global_ragent_gathering_done != TRUE) { - g_debug ("test-fullmode: Added streams, running mainloop until 'candidate-gathering-done'..."); - g_main_loop_run (global_mainloop); - g_assert (global_lagent_gathering_done == TRUE); - g_assert (global_ragent_gathering_done == TRUE); - } - - set_credentials (lagent, ls_id, ragent, rs_id); - - /* step: pass the remote candidates to agents */ - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP, USE_TURN); - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, USE_TURN); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP, USE_TURN); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, USE_TURN); - - g_debug ("test-fullmode: Set properties, next running mainloop until connectivity checks succeed..."); - - /* step: run the mainloop until connectivity checks succeed - * (see timer_cb() above) */ - g_main_loop_run (global_mainloop); - - /* note: verify that STUN binding requests were sent */ - g_assert (global_lagent_ibr_received == TRUE); - g_assert (global_ragent_ibr_received == TRUE); - - /* note: test payload send and receive */ - global_ragent_read = 0; - ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"); - if (ret == -1) - { - gboolean reliable = FALSE; - g_object_get (G_OBJECT (lagent), "reliable", &reliable, NULL); - g_debug ("Sending data returned -1 in %s mode", reliable?"Reliable":"Non-reliable"); - if (reliable) { - gulong signal_handler; - guint ls_id_copy = ls_id; - - signal_handler = g_signal_connect (G_OBJECT (lagent), - "reliable-transport-writable", G_CALLBACK (cb_writable), &ls_id_copy); - g_debug ("Running mainloop until transport is writable"); - while (ls_id_copy == ls_id) - g_main_context_iteration (NULL, TRUE); - g_signal_handler_disconnect(G_OBJECT (lagent), signal_handler); - - ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"); - } - } - g_debug ("Sent %d bytes", ret); - g_assert_cmpint (ret, ==, 16); - while (global_ragent_read != 16) - g_main_context_iteration (NULL, TRUE); - g_assert_cmpint (global_ragent_read, ==, 16); - - g_debug ("test-fullmode: Ran mainloop, removing streams..."); - - /* step: clean up resources and exit */ - - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - return 0; -} - -/* - * Simulate the case where answer to the offer is delayed and - * some STUN connectivity checks reach the offering party - * before it gets the remote SDP information. - */ -static int run_full_test_delayed_answer (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr, guint ready, guint failed) -{ - guint ls_id, rs_id; - gint ret; - - /* XXX: dear compiler, this is for you */ - (void)baseaddr; - - /* step: initialize variables modified by the callbacks */ - global_components_ready = 0; - global_components_ready_exit = ready; - global_components_failed = 0; - global_components_failed_exit = failed; - global_lagent_gathering_done = FALSE; - global_ragent_gathering_done = FALSE; - global_lagent_ibr_received = - global_ragent_ibr_received = FALSE; - global_exit_when_ibr_received = 1; - global_lagent_cands = - global_ragent_cands = 0; - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - /* step: add one stream, with RTP+RTCP components, to each agent */ - ls_id = nice_agent_add_stream (lagent, 2); - - rs_id = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - - /* We don't try this with TURN because as long as both agents don't - have the remote candidates, they won't be able to create the - permission on the TURN server, so the connchecks will never go through */ - - nice_agent_gather_candidates (lagent, ls_id); - nice_agent_gather_candidates (ragent, rs_id); - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - - /* step: run mainloop until local candidates are ready - * (see timer_cb() above) */ - if (global_lagent_gathering_done != TRUE || - global_ragent_gathering_done != TRUE) { - g_debug ("test-fullmode: Added streams, running mainloop until 'candidate-gathering-done'..."); - g_main_loop_run (global_mainloop); - g_assert (global_lagent_gathering_done == TRUE); - g_assert (global_ragent_gathering_done == TRUE); - } - - set_credentials (lagent, ls_id, ragent, rs_id); - - /* step: set remote candidates for agent R (answering party) */ - /* We have to disable TURN for this test because with the delayed answer, - we can't create turn permissions, so we won't receive any connchecks */ - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP, FALSE); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, FALSE); - - g_debug ("test-fullmode: Set properties, next running mainloop until first check is received..."); - - /* step: run the mainloop until first connectivity check receveid */ - g_main_loop_run (global_mainloop); - global_exit_when_ibr_received = 0; - - /* note: verify that STUN binding requests were sent */ - g_assert (global_lagent_ibr_received == TRUE); - - g_debug ("test-fullmode: Delayed answer received, continuing processing.."); - - /* step: pass remove candidates to agent L (offering party) */ - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP, FALSE); - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, FALSE); - - g_debug ("test-fullmode: Running mainloop until connectivity checks succeeed."); - - g_main_loop_run (global_mainloop); - g_assert (global_ragent_ibr_received == TRUE); - g_assert_cmpuint (global_components_failed, ==, 0); - - /* note: test payload send and receive */ - global_ragent_read = 0; - ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"); - if (ret == -1) { - gboolean reliable = FALSE; - g_object_get (G_OBJECT (lagent), "reliable", &reliable, NULL); - if (reliable) { - gulong signal_handler; - guint ls_id_copy = ls_id; - - signal_handler = g_signal_connect (G_OBJECT (lagent), - "reliable-transport-writable", G_CALLBACK (cb_writable), &ls_id_copy); - g_debug ("Running mainloop until transport is writable"); - while (ls_id_copy == ls_id) - g_main_context_iteration (NULL, TRUE); - g_signal_handler_disconnect(G_OBJECT (lagent), signal_handler); - - ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"); - } - } - global_ragent_read = 0; - g_assert_cmpint (ret, ==, 16); - g_main_loop_run (global_mainloop); - g_assert_cmpint (global_ragent_read, ==, 16); - - g_debug ("test-fullmode: Ran mainloop, removing streams..."); - - /* step: clean up resources and exit */ - - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - return 0; -} - -static int run_full_test_wrong_password (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr) -{ - guint ls_id, rs_id; - - /* XXX: dear compiler, this is for you */ - (void)baseaddr; - - global_components_ready = 0; - global_components_ready_exit = 0; - global_components_failed = 0; - global_components_failed_exit = 2; - global_lagent_state[0] = global_lagent_state[1] = - global_ragent_state[0] = global_ragent_state[1] - = NICE_COMPONENT_STATE_LAST; - global_lagent_gathering_done = - global_ragent_gathering_done = FALSE; - global_lagent_cands = - global_ragent_cands = 0; - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - /* step: add one stream, with one component, to each agent */ - ls_id = nice_agent_add_stream (lagent, 1); - - rs_id = nice_agent_add_stream (ragent, 1); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - -#if USE_TURN - nice_agent_set_relay_info(lagent, ls_id, 1, - TURN_IP, TURN_PORT, TURN_USER, TURN_PASS, TURN_TYPE); - nice_agent_set_relay_info(ragent, rs_id, 1, - TURN_IP, TURN_PORT, TURN_USER, TURN_PASS, TURN_TYPE); -#endif - - nice_agent_gather_candidates (lagent, ls_id); - nice_agent_gather_candidates (ragent, rs_id); - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - - /* step: run mainloop until local candidates are ready - * (see timer_cb() above) */ - if (global_lagent_gathering_done != TRUE || - global_ragent_gathering_done != TRUE) { - g_debug ("test-fullmode: Added streams, running mainloop until 'candidate-gathering-done'..."); - g_main_loop_run (global_mainloop); - g_assert (global_lagent_gathering_done == TRUE); - g_assert (global_ragent_gathering_done == TRUE); - } - - g_debug ("test-fullmode: Got local candidates..."); - - set_credentials (lagent, ls_id, ragent, rs_id); - nice_agent_set_remote_credentials (ragent, rs_id, "wrong", "password"); - nice_agent_set_remote_credentials (lagent, ls_id, "wrong2", "password2"); - - - /* step: pass the remote candidates to agents */ - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP, USE_TURN); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP, USE_TURN); - - g_debug ("test-fullmode: Set properties, next running mainloop until connectivity checks succeed..."); - - /* step: run the mainloop until connectivity checks succeed - * (see timer_cb() above) */ - g_main_loop_run (global_mainloop); - - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (global_lagent_cands, ==, 0); - g_assert_cmpint (global_ragent_cands, ==, 0); - - g_debug ("test-fullmode: Ran mainloop, removing streams..."); - - /* step: clean up resources and exit */ - - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - return 0; -} - -static int run_full_test_control_conflict (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr, gboolean role) -{ - guint ls_id, rs_id; - - /* XXX: dear compiler, this is for you */ - (void)baseaddr; - - global_components_ready = 0; - global_components_ready_exit = 2; - global_components_failed = 0; - global_components_failed_exit = 0; - global_lagent_gathering_done = - global_ragent_gathering_done = FALSE; - global_lagent_cands = - global_ragent_cands = 0; - global_lagent_ibr_received = - global_ragent_ibr_received = FALSE; - - g_object_set (G_OBJECT (lagent), "controlling-mode", role, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", role, NULL); - - /* step: add one stream, with one component, to each agent */ - ls_id = nice_agent_add_stream (lagent, 1); - - rs_id = nice_agent_add_stream (ragent, 1); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - -#if USE_TURN - nice_agent_set_relay_info(lagent, ls_id, 1, - TURN_IP, TURN_PORT, TURN_USER, TURN_PASS, TURN_TYPE); - nice_agent_set_relay_info(ragent, rs_id, 1, - TURN_IP, TURN_PORT, TURN_USER, TURN_PASS, TURN_TYPE); -#endif - - nice_agent_gather_candidates (lagent, ls_id); - nice_agent_gather_candidates (ragent, rs_id); - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - - /* step: run mainloop until local candidates are ready - * (see timer_cb() above) */ - if (global_lagent_gathering_done != TRUE || - global_ragent_gathering_done != TRUE) { - g_debug ("test-fullmode: Added streams, running mainloop until 'candidate-gathering-done'..."); - g_main_loop_run (global_mainloop); - g_assert (global_lagent_gathering_done == TRUE); - g_assert (global_ragent_gathering_done == TRUE); - } - - g_debug ("test-fullmode: Got local candidates..."); - - set_credentials (lagent, ls_id, ragent, rs_id); - - /* step: pass the remote candidates to agents */ - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP, USE_TURN); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP, USE_TURN); - - g_debug ("test-fullmode: Set properties, next running mainloop until connectivity checks succeed..."); - - /* step: run the mainloop until connectivity checks succeed - * (see timer_cb() above) */ - g_main_loop_run (global_mainloop); - - /* When using TURN, we get peer reflexive candidates for the host cands - that we removed so we can get another new_selected_pair signal later - depending on timing/racing, we could double (or not) the amount we expected - */ -#if !(USE_TURN) - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (global_lagent_cands, ==, 1); - g_assert_cmpint (global_ragent_cands, ==, 1); -#endif - - g_debug ("test-fullmode: Ran mainloop, removing streams..."); - - /* step: clean up resources and exit */ - - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - return 0; -} - -int main (void) -{ - NiceAgent *lagent, *ragent; /* agent's L and R */ - NiceAddress baseaddr; - int result; - guint timer_id; - const char *stun_server = NULL, *stun_server_port = NULL; - gboolean lagent_closed = FALSE; - gboolean ragent_closed = FALSE; - -#ifdef G_OS_WIN32 - WSADATA w; - - WSAStartup(0x0202, &w); -#endif - - global_mainloop = g_main_loop_new (NULL, FALSE); - - /* Note: impl limits ... - * - no multi-stream support - * - no IPv6 support - */ - - /* step: create the agents L and R */ -#if USE_RELIABLE - lagent = nice_agent_new_reliable (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY); - ragent = nice_agent_new_reliable (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY); -#else - lagent = nice_agent_new (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY); - ragent = nice_agent_new (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY); -#endif - - g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL); - - - nice_agent_set_software (lagent, "Test-fullmode, Left Agent"); - nice_agent_set_software (ragent, "Test-fullmode, Right Agent"); - - /* step: add a timer to catch state changes triggered by signals */ -#if USE_TURN - timer_id = g_timeout_add (300000, timer_cb, NULL); -#else - timer_id = g_timeout_add (30000, timer_cb, NULL); -#endif - - /* step: specify which local interface to use */ -#if USE_LOOPBACK - if (!nice_address_set_from_string (&baseaddr, "127.0.0.1")) - g_assert_not_reached (); - nice_agent_add_local_address (lagent, &baseaddr); - nice_agent_add_local_address (ragent, &baseaddr); -#endif - - g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "new-candidate", - G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "new-candidate", - G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), - GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), - GUINT_TO_POINTER (2)); - - stun_server = getenv ("NICE_STUN_SERVER"); - stun_server_port = getenv ("NICE_STUN_SERVER_PORT"); - if (stun_server) { - g_object_set (G_OBJECT (lagent), "stun-server", stun_server, NULL); - g_object_set (G_OBJECT (lagent), "stun-server-port", atoi (stun_server_port), NULL); - g_object_set (G_OBJECT (ragent), "stun-server", stun_server, NULL); - g_object_set (G_OBJECT (ragent), "stun-server-port", atoi (stun_server_port), NULL); - } - - g_object_set (G_OBJECT (lagent), "upnp", USE_UPNP, NULL); - g_object_set (G_OBJECT (lagent), "proxy-ip", PROXY_IP, NULL); - g_object_set (G_OBJECT (lagent), "proxy-port", PROXY_PORT, NULL); - g_object_set (G_OBJECT (lagent), "proxy-type", PROXY_TYPE, NULL); - g_object_set (G_OBJECT (lagent), "proxy-username", PROXY_USERNAME, NULL); - g_object_set (G_OBJECT (lagent), "proxy-password", PROXY_PASSWORD, NULL); - g_object_set (G_OBJECT (ragent), "upnp", USE_UPNP, NULL); - g_object_set (G_OBJECT (ragent), "proxy-ip", PROXY_IP, NULL); - g_object_set (G_OBJECT (ragent), "proxy-port", PROXY_PORT, NULL); - g_object_set (G_OBJECT (ragent), "proxy-type", PROXY_TYPE, NULL); - g_object_set (G_OBJECT (ragent), "proxy-username", PROXY_USERNAME, NULL); - g_object_set (G_OBJECT (ragent), "proxy-password", PROXY_PASSWORD, NULL); - - /* step: test setter/getter functions for properties */ - { - guint max_checks = 0; - gchar *string = NULL; - guint port = 0; - gboolean mode = FALSE; - g_object_get (G_OBJECT (lagent), "stun-server", &string, NULL); - g_assert (stun_server == NULL || strcmp (string, stun_server) == 0); - g_free (string); - g_object_get (G_OBJECT (lagent), "stun-server-port", &port, NULL); - g_assert (stun_server_port == NULL || port == (guint)atoi (stun_server_port)); - g_object_get (G_OBJECT (lagent), "proxy-ip", &string, NULL); - g_assert_cmpstr (string, ==, PROXY_IP); - g_free (string); - g_object_get (G_OBJECT (lagent), "proxy-port", &port, NULL); - g_assert_cmpuint (port, ==, PROXY_PORT); - g_object_get (G_OBJECT (lagent), "controlling-mode", &mode, NULL); - g_assert (mode == TRUE); - g_object_set (G_OBJECT (lagent), "max-connectivity-checks", 300, NULL); - g_object_get (G_OBJECT (lagent), "max-connectivity-checks", &max_checks, NULL); - g_assert_cmpuint (max_checks, ==, 300); - } - - /* step: run test the first time */ - g_debug ("test-fullmode: TEST STARTS / running test for the 1st time"); - result = run_full_test (lagent, ragent, &baseaddr, 4 ,0); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY); - /* When using TURN, we get peer reflexive candidates for the host cands - that we removed so we can get another new_selected_pair signal later - depending on timing/racing, we could double (or not) the amount we expected - */ -#if !(USE_TURN) - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (global_lagent_cands, ==, 2); - g_assert_cmpint (global_ragent_cands, ==, 2); -#endif - - - /* step: run test again without unref'ing agents */ - g_debug ("test-fullmode: TEST STARTS / running test for the 2nd time"); - result = run_full_test (lagent, ragent, &baseaddr, 4, 0); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY); - /* When using TURN, we get peer reflexive candidates for the host cands - that we removed so we can get another new_selected_pair signal later - depending on timing/racing, we could double (or not) the amount we expected - */ -#if !(USE_TURN) - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (global_lagent_cands, ==, 2); - g_assert_cmpint (global_ragent_cands, ==, 2); -#endif - - - /* step: run test simulating delayed SDP answer */ - g_debug ("test-fullmode: TEST STARTS / delayed SDP answer"); - result = run_full_test_delayed_answer (lagent, ragent, &baseaddr, 4, 0); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY); - /* note: verify that correct number of local candidates were reported */ - /* When using TURN, we get peer reflexive candidates for the host cands - that we removed so we can get another new_selected_pair signal later - depending on timing/racing, we could double (or not) the amount we expected - */ -#if !(USE_TURN) - g_assert_cmpint (global_lagent_cands, ==, 2); - g_assert_cmpint (global_ragent_cands, ==, 2); -#endif - -#if TEST_GOOGLE - return result; -#endif - - /* run test with incorrect credentials (make sure process fails) */ - g_debug ("test-fullmode: TEST STARTS / incorrect credentials"); - result = run_full_test_wrong_password (lagent, ragent, &baseaddr); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_FAILED); - g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_LAST); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_FAILED); - g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_LAST); - - /* The max connectivity checks test can't be run with TURN because - we'll have 3 local candidates instead of 1 and the checks will - be random, so we can't predict how many will fail/succeed */ -#if USE_TURN == 0 - - /* step: run test with a hard limit for connecitivity checks */ - g_debug ("test-fullmode: TEST STARTS / max connectivity checks"); - g_object_set (G_OBJECT (lagent), "max-connectivity-checks", 1, NULL); - g_object_set (G_OBJECT (ragent), "max-connectivity-checks", 1, NULL); - result = run_full_test (lagent, ragent, &baseaddr, 2, 2); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - /* should FAIL as agent L can't send any checks: */ - g_assert (global_lagent_state[0] == NICE_COMPONENT_STATE_FAILED || - global_lagent_state[1] == NICE_COMPONENT_STATE_FAILED); - g_assert (global_lagent_state[0] == NICE_COMPONENT_STATE_FAILED || - global_lagent_state[1] == NICE_COMPONENT_STATE_FAILED); -#endif - - g_object_set (G_OBJECT (lagent), "max-connectivity-checks", 100, NULL); - g_object_set (G_OBJECT (ragent), "max-connectivity-checks", 100, NULL); - result = run_full_test (lagent, ragent, &baseaddr, 4, 0); - priv_print_global_status (); - /* should SUCCEED as agent L can send the checks: */ - g_assert_cmpint (result, ==, 0); - g_assert (global_lagent_state[0] == NICE_COMPONENT_STATE_CONNECTED || - global_lagent_state[0] == NICE_COMPONENT_STATE_READY); - g_assert (global_lagent_state[1] == NICE_COMPONENT_STATE_CONNECTED || - global_lagent_state[1] == NICE_COMPONENT_STATE_READY); - g_assert (global_ragent_state[0] == NICE_COMPONENT_STATE_CONNECTED || - global_ragent_state[0] == NICE_COMPONENT_STATE_READY); - g_assert(global_ragent_state[1] == NICE_COMPONENT_STATE_CONNECTED || - global_ragent_state[1] == NICE_COMPONENT_STATE_READY); - g_object_set (G_OBJECT (lagent), "max-connectivity-checks", 100, NULL); - - /* run test with a conflict in controlling mode: controlling-controlling */ - g_debug ("test-fullmode: TEST STARTS / controlling mode conflict case-1"); - result = run_full_test_control_conflict (lagent, ragent, &baseaddr, TRUE); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY); - - /* run test with a conflict in controlling mode: controlled-controlled */ - g_debug ("test-fullmode: TEST STARTS / controlling mode conflict case-2"); - result = run_full_test_control_conflict (lagent, ragent, &baseaddr, FALSE); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY); - - nice_agent_close_async (lagent, cb_closed, &lagent_closed); - nice_agent_close_async (ragent, cb_closed, &ragent_closed); - g_object_unref (lagent); - g_object_unref (ragent); - - while (!ragent_closed || !ragent_closed) { - g_main_context_iteration (NULL, TRUE); - } - - - g_main_loop_unref (global_mainloop); - global_mainloop = NULL; - - g_source_remove (timer_id); -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return result; -} diff --git a/tests/test-gstreamer.c b/tests/test-gstreamer.c deleted file mode 100644 index 3b6275b..0000000 --- a/tests/test-gstreamer.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2015 Kurento. - * Contact: Jose Antonio Santos Cadenas - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Jose Antonio Santos Cadenas, Kurento. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#include -#include "agent.h" - -#define RTP_HEADER_SIZE 12 -#define RTP_PAYLOAD_SIZE 1024 - -static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -GMainLoop *loop; -static gint ready = 0; - - -static GCond cond; -static guint bytes_received; -static guint data_size; - - -static gboolean -count_bytes (GstBuffer ** buffer, guint idx, gpointer data) -{ - gsize size = gst_buffer_get_size (*buffer); - - g_debug ("received %" G_GSIZE_FORMAT " bytes", size); - g_mutex_lock(&mutex); - bytes_received += size; - g_cond_signal (&cond); - g_mutex_unlock (&mutex); - - return TRUE; -} - -static GstFlowReturn -sink_chain_list_function (GstPad * pad, GstObject * parent, - GstBufferList * list) -{ - gst_buffer_list_foreach (list, count_bytes, NULL); - - gst_buffer_list_unref (list); - - return GST_FLOW_OK; -} - -static GstFlowReturn -sink_chain_function (GstPad * pad, GstObject * parent, GstBuffer * buffer) -{ - gsize size = gst_buffer_get_size (buffer); - - g_debug ("received %" G_GSIZE_FORMAT " bytes", size); - g_mutex_lock(&mutex); - bytes_received += size; - g_cond_signal (&cond); - g_mutex_unlock (&mutex); - - gst_buffer_unref (buffer); - - return GST_FLOW_OK; -} - -/* - * This function is get from gst-plugins-good tests tests/check/elements/udpsink.c - */ -static GstBufferList * -create_buffer_list (void) -{ - GstBufferList *list; - GstBuffer *rtp_buffer; - GstBuffer *data_buffer; - - list = gst_buffer_list_new (); - - /*** First group, i.e. first packet. **/ - - /* Create the RTP header buffer */ - rtp_buffer = gst_buffer_new_allocate (NULL, RTP_HEADER_SIZE, NULL); - gst_buffer_memset (rtp_buffer, 0, 0, RTP_HEADER_SIZE); - - /* Create the buffer that holds the payload */ - data_buffer = gst_buffer_new_allocate (NULL, RTP_PAYLOAD_SIZE, NULL); - gst_buffer_memset (data_buffer, 0, 0, RTP_PAYLOAD_SIZE); - - /* Create a new group to hold the rtp header and the payload */ - gst_buffer_list_add (list, gst_buffer_append (rtp_buffer, data_buffer)); - - /*** Second group, i.e. second packet. ***/ - - /* Create the RTP header buffer */ - rtp_buffer = gst_buffer_new_allocate (NULL, RTP_HEADER_SIZE, NULL); - gst_buffer_memset (rtp_buffer, 0, 0, RTP_HEADER_SIZE); - - /* Create the buffer that holds the payload */ - data_buffer = gst_buffer_new_allocate (NULL, RTP_PAYLOAD_SIZE, NULL); - gst_buffer_memset (data_buffer, 0, 0, RTP_PAYLOAD_SIZE); - - /* Create a new group to hold the rtp header and the payload */ - gst_buffer_list_add (list, gst_buffer_append (rtp_buffer, data_buffer)); - - /* Calculate the size of the data */ - data_size = 2 * RTP_HEADER_SIZE + 2 * RTP_PAYLOAD_SIZE; - - return list; -} - -static void -recv_cb (NiceAgent * agent, - guint stream_id, guint component_id, guint len, gchar * buf, gpointer data) -{ - g_debug ("Received data on agent %p, stream: %d, compoment: %d", agent, - stream_id, component_id); -} - -static void -print_candidate (gpointer data, gpointer user_data) -{ - NiceCandidate *cand = data; - gchar str_addr[INET6_ADDRSTRLEN]; - - nice_address_to_string (&cand->addr, str_addr); - g_debug ("Candidate: %s:%d", str_addr, nice_address_get_port (&cand->addr)); -} - -static void -cb_candidate_gathering_done (NiceAgent * agent, guint stream_id, gpointer data) -{ - GSList *candidates; - - g_debug ("Candidates gathered on agent %p, stream: %d", - agent, stream_id); - - candidates = nice_agent_get_local_candidates (agent, stream_id, 1); - - nice_agent_set_remote_candidates (NICE_AGENT (data), stream_id, 1, - candidates); - - g_debug ("Got %d candidates", g_slist_length (candidates)); - g_slist_foreach (candidates, print_candidate, NULL); - - g_slist_free_full (candidates, (GDestroyNotify) nice_candidate_free); -} - -static void -credentials_negotiation (NiceAgent * a_agent, NiceAgent * b_agent, - guint a_stream, guint b_stream) -{ - gchar *user = NULL; - gchar *passwd = NULL; - - nice_agent_get_local_credentials (a_agent, a_stream, &user, &passwd); - nice_agent_set_remote_credentials (b_agent, b_stream, user, passwd); - g_debug ("Agent: %p User: %s", a_agent, user); - g_debug ("Agent: %p Passwd: %s", a_agent, passwd); - - g_free (user); - g_free (passwd); -} - -static void -cb_component_state_changed (NiceAgent * agent, guint stream_id, - guint component_id, guint state, gpointer user_data) -{ - g_debug ("State changed: %p to %s", agent, - nice_component_state_to_string (state)); - - if (state == NICE_COMPONENT_STATE_READY) { - ready++; - if (ready >= 2) { - g_main_loop_quit (loop); - } - } -} - -GST_START_TEST (buffer_list_test) -{ - GstSegment segment; - GstElement *nicesink, *nicesrc; - GstPad *srcpad, *sinkpad; - GstBufferList *list; - NiceAgent *sink_agent, *src_agent; - guint sink_stream, src_stream; - NiceAddress *addr; - - loop = g_main_loop_new (NULL, TRUE); - - /* Initialize nice agents */ - addr = nice_address_new (); - nice_address_set_from_string (addr, "127.0.0.1"); - - sink_agent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); - src_agent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); - - g_object_set (G_OBJECT (sink_agent), "upnp", FALSE, NULL); - g_object_set (G_OBJECT (src_agent), "upnp", FALSE, NULL); - - nice_agent_add_local_address (sink_agent, addr); - nice_agent_add_local_address (src_agent, addr); - - sink_stream = nice_agent_add_stream (sink_agent, 1); - src_stream = nice_agent_add_stream (src_agent, 1); - - nice_agent_attach_recv (sink_agent, sink_stream, NICE_COMPONENT_TYPE_RTP, - NULL, recv_cb, NULL); - nice_agent_attach_recv (src_agent, src_stream, NICE_COMPONENT_TYPE_RTP, - NULL, recv_cb, NULL); - - g_signal_connect (G_OBJECT (sink_agent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), src_agent); - g_signal_connect (G_OBJECT (src_agent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), sink_agent); - - g_signal_connect (G_OBJECT (sink_agent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), NULL); - g_signal_connect (G_OBJECT (src_agent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), NULL); - - credentials_negotiation (sink_agent, src_agent, sink_stream, src_stream); - credentials_negotiation (src_agent, sink_agent, src_stream, src_stream); - - nice_agent_gather_candidates (sink_agent, sink_stream); - nice_agent_gather_candidates (src_agent, src_stream); - - /* Create gstreamer elements */ - nicesink = gst_check_setup_element ("nicesink"); - nicesrc = gst_check_setup_element ("nicesrc"); - - g_object_set (nicesink, "agent", sink_agent, "stream", sink_stream, - "component", 1, NULL); - g_object_set (nicesrc, "agent", src_agent, "stream", src_stream, "component", - 1, NULL); - - srcpad = gst_check_setup_src_pad_by_name (nicesink, &srctemplate, "sink"); - sinkpad = gst_check_setup_sink_pad_by_name (nicesrc, &sinktemplate, "src"); - - gst_pad_set_chain_list_function_full (sinkpad, sink_chain_list_function, NULL, - NULL); - gst_pad_set_chain_function_full (sinkpad, sink_chain_function, NULL, NULL); - - gst_element_set_state (nicesink, GST_STATE_PLAYING); - gst_pad_set_active (srcpad, TRUE); - - gst_element_set_state (nicesrc, GST_STATE_PLAYING); - gst_pad_set_active (sinkpad, TRUE); - - gst_pad_push_event (srcpad, gst_event_new_stream_start ("test")); - - gst_segment_init (&segment, GST_FORMAT_TIME); - gst_pad_push_event (srcpad, gst_event_new_segment (&segment)); - - list = create_buffer_list (); - - g_debug ("Waiting for agents to be ready ready"); - - g_main_loop_run (loop); - - fail_unless_equals_int (gst_pad_push_list (srcpad, list), GST_FLOW_OK); - - g_debug ("Waiting for buffers"); - - g_mutex_lock (&mutex); - while (bytes_received < data_size) { - g_cond_wait (&cond, &mutex); - } - g_mutex_unlock (&mutex); - - g_assert_cmpuint (bytes_received, ==, data_size); - g_debug ("We received expected data size"); - - fail_unless_equals_int (data_size, bytes_received); - - gst_check_teardown_pad_by_name (nicesink, "sink"); - gst_check_teardown_element (nicesink); - - gst_check_teardown_pad_by_name (nicesrc, "src"); - gst_check_teardown_element (nicesrc); - - nice_address_free (addr); - g_main_loop_unref (loop); -} - -GST_END_TEST; - -static Suite * -udpsink_suite (void) -{ - Suite *s = suite_create ("nice_gstreamer_test"); - TCase *tc_chain = tcase_create ("nice"); - - suite_add_tcase (s, tc_chain); - - tcase_add_test (tc_chain, buffer_list_test); - - return s; -} - -GST_CHECK_MAIN (udpsink) diff --git a/tests/test-icetcp.c b/tests/test-icetcp.c deleted file mode 100644 index 25f4043..0000000 --- a/tests/test-icetcp.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * Unit test for ICE full-mode related features. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" - -#include -#include - -static NiceComponentState global_lagent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST }; -static NiceComponentState global_ragent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST }; -static guint global_components_ready = 0; -static guint global_components_ready_exit = 0; -static guint global_components_failed = 0; -static guint global_components_failed_exit = 0; -static GMainLoop *global_mainloop = NULL; -static gboolean global_lagent_gathering_done = FALSE; -static gboolean global_ragent_gathering_done = FALSE; -static gboolean global_lagent_ibr_received = FALSE; -static gboolean global_ragent_ibr_received = FALSE; -static gboolean global_ready_reached = FALSE; -static int global_lagent_cands = 0; -static int global_ragent_cands = 0; -static gint global_ragent_read = 0; -static guint global_exit_when_ibr_received = 0; - -static void priv_print_global_status (void) -{ - g_debug ("\tgathering_done=%d", global_lagent_gathering_done && global_ragent_gathering_done); - g_debug ("\tlstate[rtp]=%d [rtcp]=%d", global_lagent_state[0], global_lagent_state[1]); - g_debug ("\trstate[rtp]=%d [rtcp]=%d", global_ragent_state[0], global_ragent_state[1]); - g_debug ("\tL cands=%d R cands=%d", global_lagent_cands, global_ragent_cands); -} - -static gboolean timer_cb (gpointer pointer) -{ - g_debug ("test-icetcp:%s: %p", G_STRFUNC, pointer); - - /* signal status via a global variable */ - - /* note: should not be reached, abort */ - g_error ("ERROR: test has got stuck, aborting..."); - - return FALSE; -} - -static void cb_writable (NiceAgent*agent, guint stream_id, guint component_id) -{ - g_debug ("Transport is now writable, stopping mainloop"); - g_main_loop_quit (global_mainloop); -} - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - g_debug ("test-icetcp:%s: %p", G_STRFUNC, user_data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)buf; - - /* - * Lets ignore stun packets that got through - */ - if (len < 8) - return; - if (strncmp ("12345678", buf, 8)) - return; - - if (GPOINTER_TO_UINT (user_data) == 2) { - g_debug ("right agent received %d bytes, stopping mainloop", len); - global_ragent_read = len; - g_main_loop_quit (global_mainloop); - } -} - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-icetcp:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - global_lagent_gathering_done = TRUE; - else if (GPOINTER_TO_UINT (data) == 2) - global_ragent_gathering_done = TRUE; - - if (global_lagent_gathering_done && - global_ragent_gathering_done) - g_main_loop_quit (global_mainloop); - - /* XXX: dear compiler, these are for you: */ - (void)agent; -} - -static void check_loop_quit_condition (void) -{ - if (global_ready_reached && - global_lagent_cands >= 2 && global_ragent_cands >= 2) { - g_main_loop_quit (global_mainloop); - } -} - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - gboolean ready_to_connected = FALSE; - g_debug ("test-icetcp:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) { - if (global_lagent_state[component_id - 1] == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_lagent_state[component_id - 1] = state; - } else if (GPOINTER_TO_UINT (data) == 2) { - if (global_ragent_state[component_id - 1] == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_ragent_state[component_id - 1] = state; - } - - if (state == NICE_COMPONENT_STATE_READY) - global_components_ready++; - else if (state == NICE_COMPONENT_STATE_CONNECTED && ready_to_connected) - global_components_ready--; - if (state == NICE_COMPONENT_STATE_FAILED) - global_components_failed++; - - g_debug ("test-icetcp: checks READY/EXIT-AT %u/%u.", global_components_ready, global_components_ready_exit); - g_debug ("test-icetcp: checks FAILED/EXIT-AT %u/%u.", global_components_failed, global_components_failed_exit); - - /* signal status via a global variable */ - if (global_components_ready == global_components_ready_exit && - global_components_failed == global_components_failed_exit && - global_ready_reached == FALSE) { - g_debug ("Components ready/failed achieved. Stopping mailoop"); - global_ready_reached = TRUE; - } - - check_loop_quit_condition (); - -#if 0 - /* signal status via a global variable */ - if (global_components_failed == global_components_failed_exit) { - g_main_loop_quit (global_mainloop); - return; - } -#endif - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; -} - -static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id, - gchar *lfoundation, gchar* rfoundation, gpointer data) -{ - g_debug ("test-icetcp:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - ++global_lagent_cands; - else if (GPOINTER_TO_UINT (data) == 2) - ++global_ragent_cands; - - check_loop_quit_condition (); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)lfoundation; (void)rfoundation; -} - -static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, - gchar *foundation, gpointer data) -{ - g_debug ("test-icetcp:%s: %p", G_STRFUNC, data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; (void)foundation; -} - -static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-icetcp:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - global_lagent_ibr_received = TRUE; - else if (GPOINTER_TO_UINT (data) == 2) - global_ragent_ibr_received = TRUE; - - if (global_exit_when_ibr_received) { - g_debug ("Received initial binding request. Stopping mailoop"); - g_main_loop_quit (global_mainloop); - } - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; -} - -static void set_candidates (NiceAgent *from, guint from_stream, - NiceAgent *to, guint to_stream, guint component) -{ - GSList *cands = NULL, *i; - - cands = nice_agent_get_local_candidates (from, from_stream, component); - - restart: - for (i = cands; i; i = i->next) { - NiceCandidate *cand = i->data; - if (cand->transport == NICE_CANDIDATE_TRANSPORT_UDP) { - cands = g_slist_remove (cands, cand); - nice_candidate_free (cand); - goto restart; - } - } - - - nice_agent_set_remote_candidates (to, to_stream, component, cands); - - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); -} - -static void set_credentials (NiceAgent *lagent, guint lstream, - NiceAgent *ragent, guint rstream) -{ - gchar *ufrag = NULL, *password = NULL; - - nice_agent_get_local_credentials(lagent, lstream, &ufrag, &password); - nice_agent_set_remote_credentials (ragent, rstream, ufrag, password); - g_free (ufrag); - g_free (password); - nice_agent_get_local_credentials(ragent, rstream, &ufrag, &password); - nice_agent_set_remote_credentials (lagent, lstream, ufrag, password); - g_free (ufrag); - g_free (password); -} - -static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr, guint ready, guint failed) -{ - guint ls_id, rs_id; - gint ret; - - /* XXX: dear compiler, this is for you */ - (void)baseaddr; - - /* step: initialize variables modified by the callbacks */ - global_components_ready = 0; - global_components_ready_exit = ready; - global_components_failed = 0; - global_components_failed_exit = failed; - global_lagent_gathering_done = FALSE; - global_ragent_gathering_done = FALSE; - global_lagent_ibr_received = - global_ragent_ibr_received = FALSE; - global_lagent_cands = - global_ragent_cands = 0; - global_ready_reached = FALSE; - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - /* step: add one stream, with RTP+RTCP components, to each agent */ - ls_id = nice_agent_add_stream (lagent, 2); - - rs_id = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - - /* Gather candidates */ - g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE); - g_assert (nice_agent_gather_candidates (ragent, rs_id) == TRUE); - - { - GSList *cands = NULL, *i; - NiceCandidate *cand = NULL; - - cands = nice_agent_get_local_candidates (lagent, ls_id, 1); - g_assert_cmpuint (g_slist_length (cands), ==, 2); - cand = cands->data; - g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST); - g_assert (cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE || - cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE); - cand = cands->next->data; - g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST); - g_assert (cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE || - cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - } - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - - /* step: run mainloop until local candidates are ready - * (see timer_cb() above) */ - if (global_lagent_gathering_done != TRUE || - global_ragent_gathering_done != TRUE) { - g_debug ("test-icetcp: Added streams, running mainloop until 'candidate-gathering-done'..."); - g_main_loop_run (global_mainloop); - g_assert (global_lagent_gathering_done == TRUE); - g_assert (global_ragent_gathering_done == TRUE); - } - - set_credentials (lagent, ls_id, ragent, rs_id); - - /* step: pass the remote candidates to agents */ - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP); - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTCP); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTCP); - - g_debug ("test-icetcp: Set properties, next running mainloop until connectivity checks succeed..."); - - /* step: run the mainloop until connectivity checks succeed - * (see timer_cb() above) */ - g_main_loop_run (global_mainloop); - - /* note: verify that STUN binding requests were sent */ - g_assert (global_lagent_ibr_received == TRUE); - g_assert (global_ragent_ibr_received == TRUE); - - /* note: test payload send and receive */ - global_ragent_read = 0; - ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"); - if (ret == -1) - { - gboolean reliable = FALSE; - g_object_get (G_OBJECT (lagent), "reliable", &reliable, NULL); - g_debug ("Sending data returned -1 in %s mode", reliable?"Reliable":"Non-reliable"); - if (reliable) { - gulong signal_handler; - signal_handler = g_signal_connect (G_OBJECT (lagent), - "reliable-transport-writable", G_CALLBACK (cb_writable), NULL); - g_debug ("Running mainloop until transport is writable"); - g_main_loop_run (global_mainloop); - g_signal_handler_disconnect(G_OBJECT (lagent), signal_handler); - - ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"); - } - } - g_debug ("Sent %d bytes", ret); - g_assert_cmpint (ret, ==, 16); - g_main_loop_run (global_mainloop); - g_assert_cmpint (global_ragent_read, ==, 16); - - g_debug ("test-icetcp: Ran mainloop, removing streams..."); - - /* step: clean up resources and exit */ - - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - return 0; -} - -int main (void) -{ - NiceAgent *lagent, *ragent; /* agent's L and R */ - NiceAddress baseaddr; - int result; - guint timer_id; - -#ifdef G_OS_WIN32 - WSADATA w; - - WSAStartup(0x0202, &w); -#endif - - global_mainloop = g_main_loop_new (NULL, FALSE); - - /* step: create the agents L and R */ - lagent = nice_agent_new (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY_RFC5245); - ragent = nice_agent_new (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY_RFC5245); - - g_object_set (G_OBJECT (lagent), "ice-udp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "ice-udp", FALSE, NULL); - g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); - nice_agent_set_software (lagent, "Test-icetcp, Left Agent"); - nice_agent_set_software (ragent, "Test-icetcp, Right Agent"); - - /* step: add a timer to catch state changes triggered by signals */ - timer_id = g_timeout_add (30000, timer_cb, NULL); - - /* step: specify which local interface to use */ - if (!nice_address_set_from_string (&baseaddr, "127.0.0.1")) - g_assert_not_reached (); - nice_agent_add_local_address (lagent, &baseaddr); - nice_agent_add_local_address (ragent, &baseaddr); - - g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "new-candidate", - G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "new-candidate", - G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), - GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), - GUINT_TO_POINTER (2)); - - /* step: run test the first time */ - g_debug ("test-icetcp: TEST STARTS / running test for the 1st time"); - result = run_full_test (lagent, ragent, &baseaddr, 4 ,0); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY); - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (global_lagent_cands, >=, 2); - g_assert_cmpint (global_ragent_cands, >=, 2); - - - /* step: run test again without unref'ing agents */ - g_debug ("test-icetcp: TEST STARTS / running test for the 2nd time"); - result = run_full_test (lagent, ragent, &baseaddr, 4, 0); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY); - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (global_lagent_cands, >=, 2); - g_assert_cmpint (global_ragent_cands, >=, 2); - - g_object_unref (lagent); - g_object_unref (ragent); - - g_main_loop_unref (global_mainloop); - global_mainloop = NULL; - - g_source_remove (timer_id); -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return result; -} diff --git a/tests/test-interfaces.c b/tests/test-interfaces.c deleted file mode 100644 index dba3b68..0000000 --- a/tests/test-interfaces.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2020 Fabrice Bellet - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include "../agent/interfaces.c" - -#ifdef G_OS_UNIX -static void -test_ipv4 (void) -{ - NiceAddress addr; - union { - struct sockaddr addr; - struct sockaddr_in in; - struct sockaddr_in6 in6; - } sin; - - /* test private addresses */ - nice_address_set_from_string (&addr, "10.1.2.3"); - nice_address_copy_to_sockaddr (&addr, &sin.addr); - g_assert (nice_interfaces_is_private_ip (&sin.addr)); - - nice_address_set_from_string (&addr, "172.22.22.22"); - nice_address_copy_to_sockaddr (&addr, &sin.addr); - g_assert (nice_interfaces_is_private_ip (&sin.addr)); - - nice_address_set_from_string (&addr, "192.168.122.1"); - nice_address_copy_to_sockaddr (&addr, &sin.addr); - g_assert (nice_interfaces_is_private_ip (&sin.addr)); - - nice_address_set_from_string (&addr, "169.254.1.2"); - nice_address_copy_to_sockaddr (&addr, &sin.addr); - g_assert (nice_interfaces_is_private_ip (&sin.addr)); - - /* test public addresses */ - nice_address_set_from_string (&addr, "1.2.3.4"); - nice_address_copy_to_sockaddr (&addr, &sin.addr); - g_assert (nice_interfaces_is_private_ip (&sin.addr) == FALSE); - -} - -static void -test_ipv6 (void) -{ - NiceAddress addr; - union { - struct sockaddr addr; - struct sockaddr_in in; - struct sockaddr_in6 in6; - } sin; - - /* test private addresses */ - nice_address_set_from_string (&addr, - "fe8f:2233:4455:6677:8899:aabb:ccdd:eeff"); - nice_address_copy_to_sockaddr (&addr, &sin.addr); - g_assert (nice_interfaces_is_private_ip (&sin.addr)); - - /* test public addresses */ - nice_address_set_from_string (&addr, - "11:2233:4455:6677:8899:aabb:ccdd:eeff"); - nice_address_copy_to_sockaddr (&addr, &sin.addr); - g_assert (nice_interfaces_is_private_ip (&sin.addr) == FALSE); -} -#endif /* G_OS_UNIX */ - -int -main (void) -{ -#ifdef G_OS_UNIX - test_ipv4 (); - test_ipv6 (); -#endif - return 0; -} - diff --git a/tests/test-io-stream-cancelling.c b/tests/test-io-stream-cancelling.c deleted file mode 100644 index 809fd98..0000000 --- a/tests/test-io-stream-cancelling.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2014 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "test-io-stream-common.h" - -#include -#include -#ifndef G_OS_WIN32 -#include -#endif - -typedef struct { - GCancellable *cancellable; /* owned */ - - GCond cond; - GMutex mutex; - gboolean blocking; /* protected by @mutex */ -} CancellationData; - -static gpointer -cancellation_thread_cb (gpointer user_data) -{ - CancellationData *data = user_data; - - /* Wait to be signalled from read_thread_cb(). */ - g_mutex_lock (&data->mutex); - while (!data->blocking) - g_cond_wait (&data->cond, &data->mutex); - g_mutex_unlock (&data->mutex); - - /* Try and ensure we cancel part-way through the read, rather than before the - * read function is called. */ - g_usleep (100000); - - g_cancellable_cancel (data->cancellable); - - return NULL; -} - -static void -read_thread_cb (GInputStream *input_stream, TestIOStreamThreadData *data) -{ - CancellationData *user_data = data->user_data; - GError *error = NULL; - guint8 buf[MESSAGE_SIZE]; - gssize len; - - /* Block on receiving some data or cancellation. */ - g_mutex_lock (&user_data->mutex); - user_data->blocking = TRUE; - g_cond_signal (&user_data->cond); - g_mutex_unlock (&user_data->mutex); - - len = g_input_stream_read (input_stream, buf, sizeof (buf), - user_data->cancellable, &error); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); - g_error_free (error); - g_assert_cmpint (len, ==, -1); - - g_main_loop_quit (data->error_loop); -} - -int main (void) -{ - GThread *l_cancellation_thread, *r_cancellation_thread; - CancellationData l_data, r_data; - - const TestIOStreamCallbacks callbacks = { - read_thread_cb, - NULL, - NULL, - NULL, - }; - -#ifdef G_OS_WIN32 - WSADATA w; - WSAStartup (0x0202, &w); -#endif - - l_data.cancellable = g_cancellable_new (); - l_data.blocking = FALSE; - g_cond_init (&l_data.cond); - g_mutex_init (&l_data.mutex); - - r_data.cancellable = g_cancellable_new (); - r_data.blocking = FALSE; - g_cond_init (&r_data.cond); - g_mutex_init (&r_data.mutex); - - l_cancellation_thread = spawn_thread ("libnice L cancel", - cancellation_thread_cb, &l_data); - r_cancellation_thread = spawn_thread ("libnice R cancel", - cancellation_thread_cb, &r_data); - - run_io_stream_test (30, TRUE, &callbacks, &l_data, NULL, &r_data, NULL); - - g_thread_join (l_cancellation_thread); - g_thread_join (r_cancellation_thread); - - /* Free things. */ - g_object_unref (r_data.cancellable); - g_object_unref (l_data.cancellable); - g_cond_clear (&l_data.cond); - g_cond_clear (&r_data.cond); - g_mutex_clear (&l_data.mutex); - g_mutex_clear (&r_data.mutex); - -#ifdef G_OS_WIN32 - WSACleanup (); -#endif - - return 0; -} diff --git a/tests/test-io-stream-closing-read.c b/tests/test-io-stream-closing-read.c deleted file mode 100644 index 5acddec..0000000 --- a/tests/test-io-stream-closing-read.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2014 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "test-io-stream-common.h" - -#include -#include -#ifndef G_OS_WIN32 -#include -#endif - -#define NUM_MESSAGES 10 - -guint count = 0; -GMutex count_lock; -GCond count_cond; - -static void -read_thread_cb (GInputStream *input_stream, TestIOStreamThreadData *data) -{ - GError *error = NULL; - gssize len; - guint8 buf[MESSAGE_SIZE]; - - - g_mutex_lock (&count_lock); - count++; - g_cond_broadcast (&count_cond); - g_mutex_unlock (&count_lock); - - /* Block on receiving some data. */ - do { - len = g_input_stream_read (input_stream, buf, sizeof (buf), NULL, &error); - if (!data->user_data) { - g_assert_cmpint (len, ==, sizeof(buf)); - return; - } - } while (len > 0); - g_assert_cmpint (len, ==, -1); - - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE); - g_clear_error (&error); - - stop_main_loop (data->error_loop); -} - -static void -write_thread_cb (GOutputStream *output_stream, TestIOStreamThreadData *data) -{ - gchar buf[MESSAGE_SIZE] = {0}; - gssize ret; - GError *error = NULL; - gpointer tmp; - guint stream_id; - - ret = g_output_stream_write (output_stream, buf, sizeof (buf), NULL, - &error); - - g_mutex_lock (&count_lock); - count++; - g_cond_broadcast (&count_cond); - if (data->user_data) { - g_assert_cmpint (ret, ==, sizeof(buf)); - g_mutex_unlock (&count_lock); - return; - } - - while (count != 4) - g_cond_wait (&count_cond, &count_lock); - g_mutex_unlock (&count_lock); - - - /* Now we remove the stream, lets see how the writer handles that */ - - tmp = g_object_get_data (G_OBJECT (data->other->agent), "stream-id"); - stream_id = GPOINTER_TO_UINT (tmp); - - nice_agent_remove_stream (data->other->agent, stream_id); -} - -int main (void) -{ - const TestIOStreamCallbacks callbacks = { - read_thread_cb, - write_thread_cb, - NULL, - NULL, - }; - -#ifdef G_OS_WIN32 - WSADATA w; - WSAStartup (0x0202, &w); -#endif - - run_io_stream_test (30, TRUE, &callbacks, (gpointer) TRUE, NULL, NULL, NULL); - -#ifdef G_OS_WIN32 - WSACleanup (); -#endif - - return 0; -} diff --git a/tests/test-io-stream-closing-write.c b/tests/test-io-stream-closing-write.c deleted file mode 100644 index 6f92f28..0000000 --- a/tests/test-io-stream-closing-write.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2014 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "test-io-stream-common.h" - -#include -#include -#ifndef G_OS_WIN32 -#include -#endif - -#define NUM_MESSAGES 10 - -guint count = 0; -GMutex count_lock; -GCond count_cond; - -static void -read_thread_cb (GInputStream *input_stream, TestIOStreamThreadData *data) -{ - gpointer tmp; - guint stream_id; - GError *error = NULL; - gssize len; - guint8 buf[MESSAGE_SIZE]; - - /* Block on receiving some data. */ - len = g_input_stream_read (input_stream, buf, sizeof (buf), NULL, &error); - g_assert_cmpint (len, ==, sizeof(buf)); - - g_mutex_lock (&count_lock); - count++; - g_cond_broadcast (&count_cond); - if (data->user_data) { - g_mutex_unlock (&count_lock); - return; - } - - while (count != 4) - g_cond_wait (&count_cond, &count_lock); - g_mutex_unlock (&count_lock); - - /* Now we remove the stream, lets see how the writer handles that */ - - tmp = g_object_get_data (G_OBJECT (data->other->agent), "stream-id"); - stream_id = GPOINTER_TO_UINT (tmp); - - nice_agent_remove_stream (data->other->agent, stream_id); -} - -static void -write_thread_cb (GOutputStream *output_stream, TestIOStreamThreadData *data) -{ - gchar buf[MESSAGE_SIZE] = {0}; - gssize ret; - GError *error = NULL; - - g_mutex_lock (&count_lock); - count++; - g_cond_broadcast (&count_cond); - g_mutex_unlock (&count_lock); - - do { - g_assert_no_error (error); - ret = g_output_stream_write (output_stream, buf, sizeof (buf), NULL, - &error); - - if (!data->user_data) { - g_assert_cmpint (ret, ==, sizeof (buf)); - return; - } - } while (ret > 0); - g_assert_cmpint (ret, ==, -1); - - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED); - g_clear_error (&error); - - stop_main_loop (data->error_loop); -} - -int main (void) -{ - const TestIOStreamCallbacks callbacks = { - read_thread_cb, - write_thread_cb, - NULL, - NULL, - }; - -#ifdef G_OS_WIN32 - WSADATA w; - WSAStartup (0x0202, &w); -#endif - - run_io_stream_test (30, TRUE, &callbacks, (gpointer) TRUE, NULL, NULL, NULL); - -#ifdef G_OS_WIN32 - WSACleanup (); -#endif - - return 0; -} diff --git a/tests/test-io-stream-common.c b/tests/test-io-stream-common.c deleted file mode 100644 index 35f0849..0000000 --- a/tests/test-io-stream-common.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2014 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "test-io-stream-common.h" - -#include -#include -#ifndef G_OS_WIN32 -#include -#endif - -GMutex start_mutex; -GCond start_cond; -gboolean started; - -/* Waits about 10 seconds for @var to be NULL/FALSE */ -#define WAIT_UNTIL_UNSET(var, context) \ - if (var) \ - { \ - int i; \ - \ - for (i = 0; i < 13 && (var); i++) \ - { \ - g_usleep (1000 * (1 << i)); \ - g_main_context_iteration (context, FALSE); \ - } \ - \ - g_assert (!(var)); \ - } - -static gboolean timer_cb (gpointer pointer) -{ - g_debug ("test-thread:%s: %p", G_STRFUNC, pointer); - - /* note: should not be reached, abort */ - g_debug ("ERROR: test has got stuck, aborting..."); - abort(); - exit (-1); -} - -static void -wait_for_start (TestIOStreamThreadData *data) -{ - g_mutex_lock (data->start_mutex); - (*data->start_count)--; - g_cond_broadcast (data->start_cond); - while (*data->start_count > 0) - g_cond_wait (data->start_cond, data->start_mutex); - g_mutex_unlock (data->start_mutex); -} - -static gpointer -write_thread_cb (gpointer user_data) -{ - TestIOStreamThreadData *data = user_data; - GMainContext *main_context; - GOutputStream *output_stream = NULL; - - main_context = g_main_context_new (); - g_main_context_push_thread_default (main_context); - - /* Synchronise thread starting. */ - wait_for_start (data); - - /* Wait for the stream to be writeable. */ - g_mutex_lock (&data->write_mutex); - while (!(data->stream_open && data->stream_ready)) - g_cond_wait (&data->write_cond, &data->write_mutex); - g_mutex_unlock (&data->write_mutex); - - if (data->reliable) - output_stream = g_io_stream_get_output_stream (data->io_stream); - data->callbacks->write_thread (output_stream, data); - - g_main_context_pop_thread_default (main_context); - g_main_context_unref (main_context); - - return NULL; -} - -static gpointer -read_thread_cb (gpointer user_data) -{ - TestIOStreamThreadData *data = user_data; - GMainContext *main_context; - GInputStream *input_stream = NULL; - - main_context = g_main_context_new (); - g_main_context_push_thread_default (main_context); - - /* Synchronise thread starting. */ - wait_for_start (data); - - if (data->reliable) - input_stream = g_io_stream_get_input_stream (data->io_stream); - data->callbacks->read_thread (input_stream, data); - - g_main_context_pop_thread_default (main_context); - g_main_context_unref (main_context); - - return NULL; -} - -static gpointer -main_thread_cb (gpointer user_data) -{ - TestIOStreamThreadData *data = user_data; - - g_main_context_push_thread_default (data->main_context); - - /* Synchronise thread starting. */ - wait_for_start (data); - - /* Run the main context. */ - g_main_loop_run (data->main_loop); - - g_main_context_pop_thread_default (data->main_context); - - return NULL; -} - -static void -candidate_gathering_done_cb (NiceAgent *agent, guint stream_id, - gpointer user_data) -{ - NiceAgent *other = g_object_get_data (G_OBJECT (agent), "other-agent"); - gchar *ufrag = NULL, *password = NULL; - GSList *cands, *i; - guint id, other_id; - gpointer tmp; - - tmp = g_object_get_data (G_OBJECT (agent), "stream-id"); - id = GPOINTER_TO_UINT (tmp); - tmp = g_object_get_data (G_OBJECT (other), "stream-id"); - other_id = GPOINTER_TO_UINT (tmp); - - nice_agent_get_local_credentials (agent, id, &ufrag, &password); - nice_agent_set_remote_credentials (other, - other_id, ufrag, password); - g_free (ufrag); - g_free (password); - - cands = nice_agent_get_local_candidates (agent, id, 1); - g_assert (cands != NULL); - - nice_agent_set_remote_candidates (other, other_id, 1, cands); - - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); -} - -static void -reliable_transport_writable_cb (NiceAgent *agent, guint stream_id, - guint component_id, gpointer user_data) -{ - TestIOStreamThreadData *data = user_data; - - g_assert (data->reliable); - - /* Signal writeability. */ - g_mutex_lock (&data->write_mutex); - data->stream_open = TRUE; - g_cond_broadcast (&data->write_cond); - g_mutex_unlock (&data->write_mutex); - - if (data->callbacks->reliable_transport_writable != NULL) { - GIOStream *io_stream; - GOutputStream *output_stream; - - io_stream = g_object_get_data (G_OBJECT (agent), "io-stream"); - g_assert (io_stream != NULL); - output_stream = g_io_stream_get_output_stream (io_stream); - - data->callbacks->reliable_transport_writable (output_stream, agent, - stream_id, component_id, data); - } -} - -static void -component_state_changed_cb (NiceAgent *agent, guint stream_id, - guint component_id, guint state, gpointer user_data) -{ - TestIOStreamThreadData *data = user_data; - - if (state != NICE_COMPONENT_STATE_READY) - return; - - /* Signal stream state. */ - g_mutex_lock (&data->write_mutex); - data->stream_ready = TRUE; - g_cond_broadcast (&data->write_cond); - g_mutex_unlock (&data->write_mutex); -} - -static void -new_selected_pair_cb (NiceAgent *agent, guint stream_id, guint component_id, - gchar *lfoundation, gchar *rfoundation, gpointer user_data) -{ - TestIOStreamThreadData *data = user_data; - - if (data->callbacks->new_selected_pair != NULL) { - data->callbacks->new_selected_pair (agent, stream_id, component_id, - lfoundation, rfoundation, data); - } -} - -static NiceAgent * -create_agent (gboolean controlling_mode, TestIOStreamThreadData *data, - GMainContext **main_context, GMainLoop **main_loop) -{ - NiceAgent *agent; - NiceAddress base_addr; - const gchar *stun_server, *stun_server_port; - - /* Create main contexts. */ - *main_context = g_main_context_new (); - *main_loop = g_main_loop_new (*main_context, FALSE); - - /* Use Google compatibility to ignore credentials. */ - if (data->reliable) - agent = nice_agent_new_reliable (*main_context, NICE_COMPATIBILITY_GOOGLE); - else - agent = nice_agent_new (*main_context, NICE_COMPATIBILITY_GOOGLE); - - g_object_set (G_OBJECT (agent), - "controlling-mode", controlling_mode, - "upnp", FALSE, - NULL); - - /* Specify which local interface to use. */ - g_assert (nice_address_set_from_string (&base_addr, "127.0.0.1")); - nice_agent_add_local_address (agent, &base_addr); - - /* Hook up signals. */ - g_signal_connect (G_OBJECT (agent), "candidate-gathering-done", - (GCallback) candidate_gathering_done_cb, - GUINT_TO_POINTER (controlling_mode)); - g_signal_connect (G_OBJECT (agent), "new-selected-pair", - (GCallback) new_selected_pair_cb, data); - g_signal_connect (G_OBJECT (agent), "component-state-changed", - (GCallback) component_state_changed_cb, data); - - if (data->reliable) { - g_signal_connect (G_OBJECT (agent), "reliable-transport-writable", - (GCallback) reliable_transport_writable_cb, data); - } else { - data->stream_open = TRUE; - } - - /* Configure the STUN server. */ - stun_server = g_getenv ("NICE_STUN_SERVER"); - stun_server_port = g_getenv ("NICE_STUN_SERVER_PORT"); - - if (stun_server != NULL) { - g_object_set (G_OBJECT (agent), - "stun-server", stun_server, - "stun-server-port", atoi (stun_server_port), - NULL); - } - - return agent; -} - -static void -add_stream (NiceAgent *agent) -{ - guint stream_id; - - stream_id = nice_agent_add_stream (agent, 2); - g_assert_cmpuint (stream_id, >, 0); - - g_object_set_data (G_OBJECT (agent), "stream-id", - GUINT_TO_POINTER (stream_id)); -} - -static void -run_agent (TestIOStreamThreadData *data, NiceAgent *agent) -{ - guint stream_id; - gpointer tmp; - - tmp = g_object_get_data (G_OBJECT (agent), "stream-id"); - stream_id = GPOINTER_TO_UINT (tmp); - - nice_agent_gather_candidates (agent, stream_id); - - if (data->reliable) { - data->io_stream = - G_IO_STREAM (nice_agent_get_io_stream (agent, stream_id, 1)); - g_object_set_data (G_OBJECT (agent), "io-stream", data->io_stream); - } else { - data->io_stream = NULL; - } -} - -GThread * -spawn_thread (const gchar *thread_name, GThreadFunc thread_func, - gpointer user_data) -{ - GThread *thread; - - thread = g_thread_new (thread_name, thread_func, user_data); - g_assert (thread); - - return thread; -} - -void -run_io_stream_test (guint deadlock_timeout, gboolean reliable, - const TestIOStreamCallbacks *callbacks, - gpointer l_user_data, GDestroyNotify l_user_data_free, - gpointer r_user_data, GDestroyNotify r_user_data_free) -{ - GMainLoop *error_loop; - GThread *l_main_thread, *r_main_thread; - GThread *l_write_thread, *l_read_thread, *r_write_thread, *r_read_thread; - TestIOStreamThreadData l_data = { NULL }, r_data = { NULL }; - GMutex mutex; - GCond cond; - guint start_count = 6; - guint stream_id; - - g_mutex_init (&mutex); - g_cond_init (&cond); - - error_loop = g_main_loop_new (NULL, FALSE); - - /* Set up data structures. */ - l_data.reliable = reliable; - l_data.error_loop = error_loop; - l_data.callbacks = callbacks; - l_data.user_data = l_user_data; - l_data.user_data_free = l_user_data_free; - - g_cond_init (&l_data.write_cond); - g_mutex_init (&l_data.write_mutex); - l_data.stream_open = FALSE; - l_data.stream_ready = FALSE; - l_data.start_mutex = &mutex; - l_data.start_cond = &cond; - l_data.start_count = &start_count; - - r_data.reliable = reliable; - r_data.error_loop = error_loop; - r_data.callbacks = callbacks; - r_data.user_data = r_user_data; - r_data.user_data_free = r_user_data_free; - - g_cond_init (&r_data.write_cond); - g_mutex_init (&r_data.write_mutex); - r_data.stream_open = FALSE; - r_data.stream_ready = FALSE; - r_data.start_mutex = &mutex; - r_data.start_cond = &cond; - r_data.start_count = &start_count; - - l_data.other = &r_data; - r_data.other = &l_data; - - /* Create the L and R agents. */ - l_data.agent = create_agent (TRUE, &l_data, - &l_data.main_context, &l_data.main_loop); - r_data.agent = create_agent (FALSE, &r_data, - &r_data.main_context, &r_data.main_loop); - - g_object_set_data (G_OBJECT (l_data.agent), "other-agent", r_data.agent); - g_object_set_data (G_OBJECT (r_data.agent), "other-agent", l_data.agent); - - /* Add a timer to catch deadlocks. */ - g_timeout_add_seconds (deadlock_timeout, timer_cb, NULL); - - l_main_thread = spawn_thread ("libnice L main", main_thread_cb, &l_data); - r_main_thread = spawn_thread ("libnice R main", main_thread_cb, &r_data); - - add_stream (l_data.agent); - add_stream (r_data.agent); - run_agent (&l_data, l_data.agent); - run_agent (&r_data, r_data.agent); - - l_read_thread = spawn_thread ("libnice L read", read_thread_cb, &l_data); - r_read_thread = spawn_thread ("libnice R read", read_thread_cb, &r_data); - - if (callbacks->write_thread != NULL) { - l_write_thread = spawn_thread ("libnice L write", write_thread_cb, &l_data); - r_write_thread = spawn_thread ("libnice R write", write_thread_cb, &r_data); - } else { - g_mutex_lock (&mutex); - start_count -= 2; - g_cond_broadcast (&cond); - g_mutex_unlock (&mutex); - - l_write_thread = NULL; - r_write_thread = NULL; - } - - /* Run loop for error timer */ - g_main_loop_run (error_loop); - - /* Clean up the main loops and threads. */ - stop_main_loop (l_data.main_loop); - stop_main_loop (r_data.main_loop); - - g_thread_join (l_read_thread); - g_thread_join (r_read_thread); - if (l_write_thread != NULL) - g_thread_join (l_write_thread); - if (r_write_thread != NULL) - g_thread_join (r_write_thread); - g_thread_join (l_main_thread); - g_thread_join (r_main_thread); - - /* Free things. */ - if (r_data.user_data_free != NULL) - r_data.user_data_free (r_data.user_data); - - if (l_data.user_data_free != NULL) - l_data.user_data_free (l_data.user_data); - - g_cond_clear (&r_data.write_cond); - g_mutex_clear (&r_data.write_mutex); - g_cond_clear (&l_data.write_cond); - g_mutex_clear (&l_data.write_mutex); - - if (r_data.io_stream != NULL) - g_object_unref (r_data.io_stream); - if (l_data.io_stream != NULL) - g_object_unref (l_data.io_stream); - - stream_id = - GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (r_data.agent), "stream-id")); - if (stream_id != 0) - nice_agent_remove_stream (r_data.agent, stream_id); - stream_id = - GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (l_data.agent), "stream-id")); - if (stream_id != 0) - nice_agent_remove_stream (l_data.agent, stream_id); - - g_object_add_weak_pointer (G_OBJECT (r_data.agent), - (gpointer *) &r_data.agent); - g_object_add_weak_pointer (G_OBJECT (l_data.agent), - (gpointer *) &l_data.agent); - - g_object_unref (r_data.agent); - g_object_unref (l_data.agent); - - WAIT_UNTIL_UNSET (r_data.agent, r_data.main_context); - WAIT_UNTIL_UNSET (l_data.agent, l_data.main_context); - - g_main_loop_unref (r_data.main_loop); - g_main_loop_unref (l_data.main_loop); - - g_main_context_unref (r_data.main_context); - g_main_context_unref (l_data.main_context); - - g_main_loop_unref (error_loop); - - g_mutex_clear (&mutex); - g_cond_clear (&cond); -} - -/* Once we’ve received all the expected bytes, wait to finish sending all bytes, - * then send and wait for the close message. Finally, remove the stream. - * - * This must only be called from the read thread implementation. */ -void -check_for_termination (TestIOStreamThreadData *data, gsize *recv_count, - gsize *other_recv_count, volatile gsize *send_count, gsize expected_recv_count) -{ - guint stream_id; - gpointer tmp; - GError *error = NULL; - - /* Wait for transmission to complete. */ - while (*send_count < expected_recv_count) { - if (data->callbacks->wait_transmission_cb) { - data->callbacks->wait_transmission_cb (data->agent); - } - } - - /* Send a close message. */ - tmp = g_object_get_data (G_OBJECT (data->agent), "stream-id"); - stream_id = GPOINTER_TO_UINT (tmp); - - /* Can't be certain enough to test for termination on non-reliable streams. - * There may be packet losses, etc - */ - if (data->io_stream) { - gssize len; - - g_output_stream_close (g_io_stream_get_output_stream (data->io_stream), - NULL, &error); - - g_assert_no_error (error); - - len = g_input_stream_skip (g_io_stream_get_input_stream (data->io_stream), - 1024 * 1024, NULL, &error); - g_assert_no_error (error); - g_assert_cmpint (len, ==, 0); - } - - /* Remove the stream and run away. */ - nice_agent_remove_stream (data->agent, stream_id); - g_object_set_data (G_OBJECT (data->agent), "stream-id", GUINT_TO_POINTER (0)); - g_clear_object (&data->io_stream); - - data->done = TRUE; - if (data->other->done) - g_main_loop_quit (data->error_loop); - - /* If both sides have finished, quit the test main loop. */ - if (*recv_count > expected_recv_count && - *other_recv_count > expected_recv_count) { - g_main_loop_quit (data->error_loop); - } -} - -void -stop_main_loop (GMainLoop *loop) -{ - GSource *src = g_idle_source_new (); - g_source_set_callback (src, G_SOURCE_FUNC (g_main_loop_quit), - g_main_loop_ref (loop), (GDestroyNotify) g_main_loop_unref); - g_source_attach (src, g_main_loop_get_context (loop)); - g_source_unref (src); -} diff --git a/tests/test-io-stream-common.h b/tests/test-io-stream-common.h deleted file mode 100644 index 86f5dd0..0000000 --- a/tests/test-io-stream-common.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2014 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" - -#include -#include -#ifndef G_OS_WIN32 -#include -#endif - -#if !GLIB_CHECK_VERSION(2, 58, 0) -#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f)) -#endif - -/* Make the message sufficiently large to not hit Nagle’s algorithm in the - * pseudo-TCP implementation, and hence run really slowly. */ -#define MESSAGE_SIZE 1284 /* bytes */ - -typedef struct _TestIOStreamThreadData TestIOStreamThreadData; - -typedef struct { - void (*read_thread) (GInputStream *input_stream, - TestIOStreamThreadData *data); - void (*write_thread) (GOutputStream *output_stream, - TestIOStreamThreadData *data); - void (*reliable_transport_writable) (GOutputStream *output_stream, - NiceAgent *agent, guint stream_id, guint component_id, - TestIOStreamThreadData *data); - void (*new_selected_pair) (NiceAgent *agent, guint stream_id, - guint component_id, gchar *lfoundation, gchar *rfoundation, - TestIOStreamThreadData *data); - void (*wait_transmission_cb) (NiceAgent *agent); -} TestIOStreamCallbacks; - -struct _TestIOStreamThreadData { - NiceAgent *agent; - GIOStream *io_stream; - - gboolean reliable; - - GMainLoop *main_loop; - GMainLoop *error_loop; - - GMainContext *main_context; - GMainContext *write_context; - GMainContext *read_context; - - gpointer user_data; - GDestroyNotify user_data_free; - - TestIOStreamThreadData *other; - - /*< private >*/ - const TestIOStreamCallbacks *callbacks; - - gboolean done; - - /* Condition signalling for the stream being open/writeable. */ - gboolean stream_open; - gboolean stream_ready; - GCond write_cond; - GMutex write_mutex; - - GMutex *start_mutex; - GCond *start_cond; - guint *start_count; -}; - -GThread *spawn_thread (const gchar *thread_name, GThreadFunc thread_func, - gpointer user_data); -void run_io_stream_test (guint deadlock_timeout, gboolean reliable, - const TestIOStreamCallbacks *callbacks, - gpointer l_user_data, GDestroyNotify l_user_data_free, - gpointer r_user_data, GDestroyNotify r_user_data_free); -void check_for_termination (TestIOStreamThreadData *data, gsize *recv_count, - gsize *other_recv_count, volatile gsize *send_count, gsize expected_recv_count); - -void stop_main_loop (GMainLoop *loop); diff --git a/tests/test-io-stream-pollable.c b/tests/test-io-stream-pollable.c deleted file mode 100644 index 3f0a401..0000000 --- a/tests/test-io-stream-pollable.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2014 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "test-io-stream-common.h" - -#include -#include -#ifndef G_OS_WIN32 -#include -#endif - -typedef struct { - GMainLoop *read_loop; /* unowned */ - - gsize recv_count; - gsize *other_recv_count; - - gsize send_count; - gsize *other_send_count; -} ThreadData; - -static gboolean -read_stream_cb (GObject *pollable_stream, gpointer _user_data) -{ - TestIOStreamThreadData *data = _user_data; - ThreadData *user_data = data->user_data; - gchar expected_data[MESSAGE_SIZE]; - GError *error = NULL; - guint8 buf[MESSAGE_SIZE]; - gssize len; - - /* Try to receive some data. */ - len = g_pollable_input_stream_read_nonblocking ( - G_POLLABLE_INPUT_STREAM (pollable_stream), buf, sizeof (buf), NULL, - &error); - - if (len == -1) { - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK); - g_error_free (error); - return TRUE; - } - - g_assert_cmpint (len, ==, MESSAGE_SIZE); - - memset (expected_data, user_data->recv_count + '1', sizeof (expected_data)); - g_assert_cmpmem (buf, sizeof (expected_data), expected_data, sizeof (expected_data)); - - user_data->recv_count++; - - if (user_data->recv_count == 10) { - g_main_loop_quit (user_data->read_loop); - return FALSE; - } - - return TRUE; -} - -static void -read_thread_cb (GInputStream *input_stream, TestIOStreamThreadData *data) -{ - GMainContext *main_context; - GMainLoop *main_loop; - GSource *stream_source; - ThreadData *user_data = data->user_data; - - main_context = g_main_context_new (); - main_loop = g_main_loop_new (main_context, FALSE); - g_main_context_push_thread_default (main_context); - - stream_source = - g_pollable_input_stream_create_source ( - G_POLLABLE_INPUT_STREAM (input_stream), NULL); - - g_source_set_callback (stream_source, G_SOURCE_FUNC (read_stream_cb), - data, NULL); - g_source_attach (stream_source, main_context); - g_source_unref (stream_source); - - /* Run the main loop. */ - user_data->read_loop = main_loop; - g_main_loop_run (main_loop); - - g_main_context_pop_thread_default (main_context); - g_main_loop_unref (main_loop); - g_main_context_unref (main_context); - - check_for_termination (data, &user_data->recv_count, - user_data->other_recv_count, &user_data->send_count, 10); -} - -static void -write_thread_cb (GOutputStream *output_stream, TestIOStreamThreadData *data) -{ - ThreadData *user_data = data->user_data; - guint8 buf[MESSAGE_SIZE]; - - for (user_data->send_count = 0; - user_data->send_count < 10; - user_data->send_count++) { - GError *error = NULL; - - memset (buf, user_data->send_count + '1', MESSAGE_SIZE); - - g_pollable_output_stream_write_nonblocking ( - G_POLLABLE_OUTPUT_STREAM (output_stream), buf, sizeof (buf), NULL, - &error); - g_assert_no_error (error); - } -} - -int main (void) -{ - ThreadData *l_data, *r_data; - - const TestIOStreamCallbacks callbacks = { - read_thread_cb, - write_thread_cb, - NULL, - NULL, - }; - -#ifdef G_OS_WIN32 - WSADATA w; - WSAStartup (0x0202, &w); -#endif - - l_data = g_malloc0 (sizeof (ThreadData)); - r_data = g_malloc0 (sizeof (ThreadData)); - - l_data->recv_count = 0; - l_data->send_count = 0; - l_data->other_recv_count = &r_data->recv_count; - l_data->other_send_count = &r_data->send_count; - - r_data->recv_count = 0; - r_data->send_count = 0; - r_data->other_recv_count = &l_data->recv_count; - r_data->other_send_count = &l_data->send_count; - - run_io_stream_test (30, TRUE, &callbacks, l_data, NULL, r_data, NULL); - - g_free (r_data); - g_free (l_data); - -#ifdef G_OS_WIN32 - WSACleanup (); -#endif - return 0; -} diff --git a/tests/test-io-stream-thread.c b/tests/test-io-stream-thread.c deleted file mode 100644 index 49386eb..0000000 --- a/tests/test-io-stream-thread.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2013 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "test-io-stream-common.h" - -#include -#include -#ifndef G_OS_WIN32 -#include -#endif - -typedef struct { - guint cand_count; - guint *other_cand_count; - - gsize recv_count; - gsize *other_recv_count; - - gsize send_count; - gsize *other_send_count; -} ThreadData; - -static void -read_thread_cb (GInputStream *input_stream, TestIOStreamThreadData *data) -{ - ThreadData *user_data = data->user_data; - - for (user_data->recv_count = 0; - user_data->recv_count < 10; - user_data->recv_count++) { - guint8 expected_data[MESSAGE_SIZE]; - GError *error = NULL; - guint8 buf[MESSAGE_SIZE]; - gssize len; - - /* Block on receiving some data. */ - len = g_input_stream_read (input_stream, buf, sizeof (buf), NULL, &error); - g_assert_no_error (error); - g_assert_cmpint (len, ==, sizeof (buf)); - - memset (expected_data, user_data->recv_count + '1', sizeof (expected_data)); - g_assert_cmpmem (buf, sizeof (expected_data), expected_data, - sizeof (expected_data)); - } - - check_for_termination (data, &user_data->recv_count, - user_data->other_recv_count, &user_data->send_count, 10); -} - -static void -new_selected_pair_cb (NiceAgent *agent, guint stream_id, guint component_id, - gchar *lfoundation, gchar *rfoundation, TestIOStreamThreadData *data) -{ - ThreadData *user_data = data->user_data; - - g_atomic_int_inc (&user_data->cand_count); -} - -static void -write_thread_cb (GOutputStream *output_stream, TestIOStreamThreadData *data) -{ - ThreadData *user_data = data->user_data; - guint8 buf[MESSAGE_SIZE]; - - for (user_data->send_count = 0; - user_data->send_count < 10; - user_data->send_count++) { - GError *error = NULL; - - memset (buf, user_data->send_count + '1', MESSAGE_SIZE); - - g_output_stream_write (output_stream, buf, sizeof (buf), NULL, &error); - g_assert_no_error (error); - } -} - -int main (void) -{ - ThreadData *l_data, *r_data; - - const TestIOStreamCallbacks callbacks = { - read_thread_cb, - write_thread_cb, - NULL, - new_selected_pair_cb, - }; - -#ifdef G_OS_WIN32 - WSADATA w; - WSAStartup (0x0202, &w); -#endif - - l_data = g_malloc0 (sizeof (ThreadData)); - r_data = g_malloc0 (sizeof (ThreadData)); - - l_data->cand_count = 0; - l_data->other_cand_count = &r_data->cand_count; - l_data->recv_count = 0; - l_data->other_recv_count = &r_data->recv_count; - l_data->send_count = 0; - l_data->other_send_count = &r_data->send_count; - - r_data->cand_count = 0; - r_data->other_cand_count = &l_data->cand_count; - r_data->recv_count = 0; - r_data->other_recv_count = &l_data->recv_count; - r_data->send_count = 0; - r_data->other_send_count = &l_data->send_count; - - run_io_stream_test (30, TRUE, &callbacks, l_data, NULL, r_data, NULL); - - /* Verify that correct number of local candidates were reported. */ - g_assert_cmpuint (l_data->cand_count, ==, 1); - g_assert_cmpuint (r_data->cand_count, ==, 1); - - g_free (r_data); - g_free (l_data); - -#ifdef G_OS_WIN32 - WSACleanup (); -#endif - return 0; -} diff --git a/tests/test-new-trickle.c b/tests/test-new-trickle.c deleted file mode 100644 index ac3c026..0000000 --- a/tests/test-new-trickle.c +++ /dev/null @@ -1,806 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * Unit test for ICE in trickle mode (adding remote candidates while gathering - * local candidates). - * - * (C) 2012 Collabora Ltd. - * Contact: Rohan Garg - * Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. - * - * Contributors: - * Rohan Garg - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stunagent.h" -#include "agent-priv.h" -#include "agent.h" - -#define USE_UPNP 0 -#define LEFT_AGENT GINT_TO_POINTER(1) -#define RIGHT_AGENT GINT_TO_POINTER(2) - -static GMutex stun_mutex; -static GMutex *stun_mutex_ptr = &stun_mutex; -static GCond stun_signal; -static GCond *stun_signal_ptr = &stun_signal; -static GMutex stun_thread_mutex; -static GMutex *stun_thread_mutex_ptr = &stun_thread_mutex; -static GCond stun_thread_signal; -static GCond *stun_thread_signal_ptr = &stun_thread_signal; - -static NiceComponentState global_lagent_state = NICE_COMPONENT_STATE_LAST; -static NiceComponentState global_ragent_state = NICE_COMPONENT_STATE_LAST; -static GCancellable *global_cancellable; -static gboolean exit_stun_thread = FALSE; -static gboolean lagent_candidate_gathering_done = FALSE; -static gboolean ragent_candidate_gathering_done = FALSE; -static guint global_ls_id, global_rs_id; -static gboolean data_received = FALSE; -static gboolean drop_stun_packets = FALSE; -static gboolean got_stun_packet = FALSE; -static gboolean send_stun = FALSE; -static guint stun_port; - -static const uint16_t known_attributes[] = { - 0 -}; - -/* Waits about 10 seconds for @var to be NULL/FALSE */ -#define WAIT_UNTIL_UNSET(var, context) \ - if (var) \ - { \ - int _i; \ - \ - for (_i = 0; _i < 13 && (var); _i++) \ - { \ - g_usleep (1000 * (1 << _i)); \ - g_main_context_iteration (context, FALSE); \ - } \ - \ - g_assert (!(var)); \ - } - -/* - * Creates a listening socket - */ -static int listen_socket (unsigned int *port) -{ - union { - struct sockaddr_in in; - struct sockaddr addr; - } addr; - int fd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); - - if (fd == -1) { - perror ("Error opening IP port"); - return -1; - } - - memset (&addr, 0, sizeof (addr)); - addr.in.sin_family = AF_INET; - inet_pton(AF_INET, "127.0.0.1", &addr.in.sin_addr); - addr.in.sin_port = 0; - - if (bind (fd, &addr.addr, sizeof (struct sockaddr_in))) { - perror ("Error opening IP port"); - goto error; - } - - if (port) { - socklen_t socklen = sizeof(addr); - - if (getsockname (fd, &addr.addr, &socklen) < 0) - g_error ("getsockname failed: %s", strerror (errno)); - - g_assert_cmpint (socklen, ==, sizeof(struct sockaddr_in)); - *port = ntohs (addr.in.sin_port); - g_assert (*port != 0); - } - - return fd; - -error: - close (fd); - return -1; -} - -static int dgram_process (int sock, StunAgent *oldagent, StunAgent *newagent) -{ - union { - struct sockaddr_storage storage; - struct sockaddr addr; - } addr; - socklen_t addr_len; - uint8_t buf[STUN_MAX_MESSAGE_SIZE]; - size_t buf_len = 0; - size_t len = 0; - StunMessage request; - StunMessage response; - StunValidationStatus validation; - StunAgent *agent = NULL; - gint ret; - - addr_len = sizeof (struct sockaddr_in); - -recv_packet: - len = recvfrom (sock, buf, sizeof(buf), 0, - &addr.addr, &addr_len); - - if (drop_stun_packets) { - g_debug ("Dropping STUN packet as requested"); - return -1; - } - - if (len == (size_t)-1) { - return -1; - } - - validation = stun_agent_validate (newagent, &request, buf, len, NULL, 0); - - if (validation == STUN_VALIDATION_SUCCESS) { - agent = newagent; - } else { - validation = stun_agent_validate (oldagent, &request, buf, len, NULL, 0); - agent = oldagent; - } - - /* Unknown attributes */ - if (validation == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE) { - buf_len = stun_agent_build_unknown_attributes_error (agent, &response, buf, - sizeof (buf), &request); - goto send_buf; - } - - /* Mal-formatted packets */ - if (validation != STUN_VALIDATION_SUCCESS || - stun_message_get_class (&request) != STUN_REQUEST) { - goto recv_packet; - } - - switch (stun_message_get_method (&request)) { - case STUN_BINDING: - stun_agent_init_response (agent, &response, buf, sizeof (buf), &request); - if (stun_message_has_cookie (&request)) - stun_message_append_xor_addr (&response, - STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, - &addr.storage, addr_len); - else - stun_message_append_addr (&response, STUN_ATTRIBUTE_MAPPED_ADDRESS, - &addr.addr, addr_len); - break; - - case STUN_SHARED_SECRET: - case STUN_ALLOCATE: - case STUN_SET_ACTIVE_DST: - case STUN_CONNECT: - case STUN_OLD_SET_ACTIVE_DST: - case STUN_IND_DATA: - case STUN_IND_CONNECT_STATUS: - case STUN_CHANNELBIND: - default: - if (!stun_agent_init_error (agent, &response, buf, sizeof (buf), - &request, STUN_ERROR_BAD_REQUEST)) { - g_debug ("STUN error message not initialized properly"); - g_assert_not_reached(); - } - } - - buf_len = stun_agent_finish_message (agent, &response, NULL, 0); - -send_buf: - g_cancellable_cancel (global_cancellable); - g_debug ("Ready to send a STUN response"); - g_assert (g_mutex_trylock (stun_mutex_ptr)); - got_stun_packet = TRUE; - while (send_stun) { - g_debug ("Waiting for signal. State is %d", global_lagent_state); - g_cond_wait (stun_signal_ptr, stun_mutex_ptr); - } - g_mutex_unlock (stun_mutex_ptr); - len = sendto (sock, buf, buf_len, 0, - &addr.addr, addr_len); - g_debug ("STUN response sent"); - drop_stun_packets = TRUE; - ret = (len < buf_len) ? -1 : 0; - return ret; -} - - -static gpointer stun_thread_func (const gpointer user_data) -{ - StunAgent oldagent; - StunAgent newagent; - int sock = GPOINTER_TO_INT (user_data); - int exit_code = -1; - - g_mutex_lock (stun_thread_mutex_ptr); - g_cond_signal (stun_thread_signal_ptr); - g_mutex_unlock (stun_thread_mutex_ptr); - - stun_agent_init (&oldagent, known_attributes, - STUN_COMPATIBILITY_RFC3489, 0); - stun_agent_init (&newagent, known_attributes, - STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT); - - while (!exit_stun_thread) { - g_debug ("Ready to process next datagram"); - dgram_process (sock, &oldagent, &newagent); - } - - exit_code = close (sock); - g_thread_exit (GINT_TO_POINTER (exit_code)); - return NULL; -} - -static void swap_credentials (NiceAgent *lagent, guint lstream, - NiceAgent *ragent, guint rstream) -{ - gchar *ufrag = NULL, *password = NULL; - - nice_agent_get_local_credentials (lagent, lstream, &ufrag, &password); - nice_agent_set_remote_credentials (ragent, rstream, ufrag, password); - - g_free (ufrag); - g_free (password); -} - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-tricklemode:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT(data) == 1) { - g_debug ("lagent finished gathering candidates"); - lagent_candidate_gathering_done = TRUE; - } else if (GPOINTER_TO_UINT(data) == 2) { - g_debug ("ragent finished gathering candidates"); - ragent_candidate_gathering_done = TRUE; - } - g_cancellable_cancel (global_cancellable); -} - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - gint ret; - - g_debug ("test-tricklemode:%s: %p", G_STRFUNC, user_data); - - ret = strncmp ("0000", buf, 4); - if (ret == 0) { - ret = strncmp ("00001234567812345678", buf, 16); - g_assert_cmpint (ret, ==, 0); - - g_debug ("test-tricklemode:%s: ragent recieved %d bytes : quit mainloop", - G_STRFUNC, len); - data_received = TRUE; - g_cancellable_cancel (global_cancellable); - } -} - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - gint ret; - - g_debug ("test-tricklemode:%s: %p", G_STRFUNC, data); - - if(GPOINTER_TO_UINT(data) == 1) { - global_lagent_state = state; - g_debug ("lagent state is %d", state); - } else if (GPOINTER_TO_UINT(data) == 2) { - g_debug ("ragent state is %d", state); - global_ragent_state = state; - } - - if (GPOINTER_TO_UINT(data) == 1 && state == NICE_COMPONENT_STATE_FAILED) { - g_debug ("Signalling STUN response since connchecks failed"); - g_mutex_lock (stun_mutex_ptr); - send_stun = TRUE; - g_cond_signal (stun_signal_ptr); - g_mutex_unlock (stun_mutex_ptr); - g_cancellable_cancel (global_cancellable); - } - - if(GPOINTER_TO_UINT(data) == 1 && state == NICE_COMPONENT_STATE_READY) { - /* note: test payload send and receive */ - ret = nice_agent_send (agent, stream_id, component_id, - 20, "00001234567812345678"); - g_debug ("Sent %d bytes", ret); - g_assert_cmpint (ret, ==, 20); - } -} - -static void swap_candidates(NiceAgent *local, guint local_id, NiceAgent *remote, guint remote_id, gboolean signal_stun_reply) -{ - GSList *cands = NULL; - - g_debug ("test-tricklemode:%s", G_STRFUNC); - cands = nice_agent_get_local_candidates(local, local_id, - NICE_COMPONENT_TYPE_RTP); - g_assert (nice_agent_set_remote_candidates(remote, remote_id, - NICE_COMPONENT_TYPE_RTP, cands)); - - if (signal_stun_reply) { - g_mutex_lock (stun_mutex_ptr); - send_stun = TRUE; - g_cond_signal (stun_signal_ptr); - g_mutex_unlock (stun_mutex_ptr); - } - - g_slist_free_full (cands, (GDestroyNotify) nice_candidate_free); -} - -static void cb_agent_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation, gpointer user_data) -{ - NiceAgent *other = g_object_get_data (G_OBJECT (agent), "other-agent"); - GSList *cands = nice_agent_get_local_candidates (agent, stream_id, - component_id); - GSList *i = NULL; - GSList *remote_cands = NULL; - NiceCandidate* temp; - gpointer tmp; - guint id; - - g_debug ("test-tricklemode:%s: %p", G_STRFUNC, user_data); - - tmp = g_object_get_data (G_OBJECT (other), "id"); - id = GPOINTER_TO_UINT (tmp); - - for (i = cands; i; i = i->next) { - temp = (NiceCandidate*) i->data; - if (g_strcmp0(temp->foundation, foundation) == 0) { - g_debug ("Adding new local candidate to other agent's connchecks"); - remote_cands = g_slist_prepend (remote_cands, nice_candidate_copy(temp)); - g_assert (nice_agent_set_remote_candidates (other, id, - NICE_COMPONENT_TYPE_RTP, - remote_cands)); - } - } - - g_slist_free_full (remote_cands, (GDestroyNotify) nice_candidate_free); - g_slist_free_full (cands, (GDestroyNotify) nice_candidate_free); - -} - -static void add_bad_candidate (NiceAgent *agent, guint stream_id, NiceCandidate *cand) -{ - NiceAddress bad_addr; - GSList *cand_list = NULL; - - g_assert (nice_address_set_from_string (&bad_addr, "172.1.0.1")); - - cand = nice_candidate_new (NICE_CANDIDATE_TYPE_HOST); - cand->stream_id = stream_id; - cand->component_id = NICE_COMPONENT_TYPE_RTP; - cand->addr = bad_addr; - - nice_agent_get_local_credentials (agent, stream_id, - &cand->username, &cand->password); - cand_list = g_slist_prepend (cand_list, cand); - - g_debug ("Adding buggy candidate to the agent %p", agent); - g_assert (nice_agent_set_remote_candidates (agent, stream_id, - NICE_COMPONENT_TYPE_RTP, - cand_list)); - - g_slist_free_full (cand_list, (GDestroyNotify) nice_candidate_free); - -} - -static void init_test(NiceAgent *lagent, NiceAgent *ragent, gboolean connect_new_candidate_signal) -{ - global_lagent_state = NICE_COMPONENT_STATE_DISCONNECTED; - global_ragent_state = NICE_COMPONENT_STATE_DISCONNECTED; - - lagent_candidate_gathering_done = FALSE; - ragent_candidate_gathering_done = FALSE; - - global_ls_id = nice_agent_add_stream (lagent, 1); - global_rs_id = nice_agent_add_stream (ragent, 1); - - g_assert_cmpuint (global_ls_id, >, 0); - g_assert_cmpuint (global_rs_id, >, 0); - - g_debug ("lagent stream is : %d and ragent stream is %d", - global_ls_id, - global_rs_id); - - g_object_set_data (G_OBJECT (lagent), "id", GUINT_TO_POINTER (global_ls_id)); - g_object_set_data (G_OBJECT (ragent), "id", GUINT_TO_POINTER (global_rs_id)); - - if (connect_new_candidate_signal) { - g_signal_connect (G_OBJECT(lagent), "new-candidate", - G_CALLBACK(cb_agent_new_candidate), LEFT_AGENT); - g_signal_connect (G_OBJECT(ragent), "new-candidate", - G_CALLBACK(cb_agent_new_candidate), RIGHT_AGENT); - } else { - g_signal_handlers_disconnect_by_func (G_OBJECT(lagent), cb_agent_new_candidate, - LEFT_AGENT); - g_signal_handlers_disconnect_by_func (G_OBJECT(ragent), cb_agent_new_candidate, - RIGHT_AGENT); - } - - data_received = FALSE; - got_stun_packet = FALSE; - send_stun = FALSE; - - nice_agent_attach_recv (lagent, global_ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_context_default (), - cb_nice_recv, LEFT_AGENT); - nice_agent_attach_recv (ragent, global_rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_context_default (), - cb_nice_recv, RIGHT_AGENT); -} - -static void cleanup(NiceAgent *lagent, NiceAgent *ragent) -{ - g_debug ("Cleaning up"); - drop_stun_packets = FALSE; - nice_agent_remove_stream (lagent, global_ls_id); - nice_agent_remove_stream (ragent, global_rs_id); -} - -static void standard_test(NiceAgent *lagent, NiceAgent *ragent) -{ - g_debug ("test-tricklemode:%s", G_STRFUNC); - - got_stun_packet = FALSE; - init_test (lagent, ragent, FALSE); - - nice_agent_gather_candidates (lagent, global_ls_id); - while (!got_stun_packet) - g_main_context_iteration (NULL, TRUE); - g_assert (global_lagent_state == NICE_COMPONENT_STATE_GATHERING && - !lagent_candidate_gathering_done); - - nice_agent_gather_candidates (ragent, global_rs_id); - while (!ragent_candidate_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - g_assert (ragent_candidate_gathering_done); - g_assert (nice_agent_peer_candidate_gathering_done (lagent, global_ls_id)); - - - g_debug ("Setting local candidates of ragent as remote candidates of lagent"); - swap_candidates (ragent, global_rs_id, lagent, global_ls_id, TRUE); - swap_credentials (ragent, global_rs_id, lagent, global_ls_id); - - while (!data_received) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - g_assert (global_lagent_state >= NICE_COMPONENT_STATE_CONNECTED && - data_received); - - g_debug ("Setting local candidates of lagent as remote candidates of ragent"); - swap_candidates (lagent, global_ls_id, ragent, global_rs_id, FALSE); - swap_credentials (lagent, global_ls_id, ragent, global_rs_id); - - while (!lagent_candidate_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - - g_assert (lagent_candidate_gathering_done); - g_assert (nice_agent_peer_candidate_gathering_done (ragent, global_rs_id)); - - while (global_ragent_state < NICE_COMPONENT_STATE_CONNECTED) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, >=, NICE_COMPONENT_STATE_CONNECTED); - - cleanup (lagent, ragent); -} - -static void bad_credentials_test(NiceAgent *lagent, NiceAgent *ragent) -{ - g_debug ("test-tricklemode:%s", G_STRFUNC); - - init_test (lagent, ragent, FALSE); - - nice_agent_set_remote_credentials (lagent, global_ls_id, - "wrong", "wrong"); - nice_agent_set_remote_credentials (ragent, global_rs_id, - "wrong2", "wrong2"); - - nice_agent_gather_candidates (lagent, global_ls_id); - while (!got_stun_packet) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - g_assert (global_lagent_state == NICE_COMPONENT_STATE_GATHERING && - !lagent_candidate_gathering_done); - - nice_agent_gather_candidates (ragent, global_rs_id); - while (!ragent_candidate_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - g_assert (ragent_candidate_gathering_done); - g_assert (nice_agent_peer_candidate_gathering_done (lagent, global_ls_id)); - - g_debug ("Setting local candidates of ragent as remote candidates of lagent"); - swap_candidates (ragent, global_rs_id, lagent, global_ls_id, FALSE); - - while (global_lagent_state != NICE_COMPONENT_STATE_FAILED) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - - // Set the correct credentials and swap candidates - g_debug ("Setting local candidates of ragent as remote candidates of lagent"); - swap_candidates (ragent, global_rs_id, lagent, global_ls_id, FALSE); - swap_credentials (lagent, global_ls_id, ragent, global_rs_id); - - g_debug ("Setting local candidates of lagent as remote candidates of ragent"); - swap_candidates (lagent, global_ls_id, ragent, global_rs_id, FALSE); - swap_credentials (ragent, global_rs_id, lagent, global_ls_id); - - while (!data_received) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - - g_assert (data_received); - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, >=, NICE_COMPONENT_STATE_CONNECTED); - - // Wait for lagent to finish gathering candidates - while (!lagent_candidate_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - - g_assert (lagent_candidate_gathering_done); - g_assert (nice_agent_peer_candidate_gathering_done (ragent, global_rs_id)); - - cleanup (lagent, ragent); -} - -static void bad_candidate_test(NiceAgent *lagent,NiceAgent *ragent) -{ - NiceCandidate *cand = NULL; - - g_debug ("test-tricklemode:%s", G_STRFUNC); - - init_test (lagent, ragent, FALSE); - - nice_agent_gather_candidates (lagent, global_ls_id); - while (!got_stun_packet) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - g_assert (global_lagent_state == NICE_COMPONENT_STATE_GATHERING && - !lagent_candidate_gathering_done); - - nice_agent_gather_candidates (ragent, global_rs_id); - while (!ragent_candidate_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - - g_assert (ragent_candidate_gathering_done); - g_assert (nice_agent_peer_candidate_gathering_done (lagent, global_ls_id)); - - add_bad_candidate (lagent, global_ls_id, cand); - - // lagent will finish candidate gathering causing this mainloop to quit - while (!lagent_candidate_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - - g_assert (nice_agent_peer_candidate_gathering_done (ragent, global_rs_id)); - - // connchecks will fail causing this mainloop to quit - while (global_lagent_state != NICE_COMPONENT_STATE_FAILED) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - - g_assert (global_lagent_state == NICE_COMPONENT_STATE_FAILED && - !data_received); - - g_debug ("Setting local candidates of ragent as remote candidates of lagent"); - swap_candidates (ragent, global_rs_id, lagent, global_ls_id, FALSE); - swap_credentials (ragent, global_rs_id, lagent, global_ls_id); - - g_debug ("Setting local candidates of lagent as remote candidates of ragent"); - swap_candidates (lagent, global_ls_id, ragent, global_rs_id, FALSE); - swap_credentials (lagent, global_ls_id, ragent, global_rs_id); - - while (!data_received) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - - g_assert (lagent_candidate_gathering_done); - - g_assert_cmpint (global_lagent_state, >=, NICE_COMPONENT_STATE_CONNECTED); - g_assert_cmpint (global_ragent_state, >=, NICE_COMPONENT_STATE_CONNECTING); - - cleanup (lagent, ragent); -} - -static void new_candidate_test(NiceAgent *lagent, NiceAgent *ragent) -{ - g_debug ("test-tricklemode:%s", G_STRFUNC); - - init_test (lagent, ragent, TRUE); - swap_credentials (lagent, global_ls_id, ragent, global_rs_id); - swap_credentials (ragent, global_rs_id, lagent, global_ls_id); - - nice_agent_gather_candidates (lagent, global_ls_id); - while (!got_stun_packet) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - g_assert (global_lagent_state == NICE_COMPONENT_STATE_GATHERING && - !lagent_candidate_gathering_done); - - nice_agent_gather_candidates (ragent, global_rs_id); - while (!ragent_candidate_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - g_assert (nice_agent_peer_candidate_gathering_done (lagent, global_ls_id)); - - // Wait for data - while (!data_received) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - g_assert (data_received); - - // Data arrived, signal STUN thread to send STUN response - g_mutex_lock (stun_mutex_ptr); - send_stun = TRUE; - g_cond_signal (stun_signal_ptr); - g_mutex_unlock (stun_mutex_ptr); - - // Wait for lagent to finish gathering candidates - while (!lagent_candidate_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_cancellable_reset (global_cancellable); - g_assert (nice_agent_peer_candidate_gathering_done (ragent, global_rs_id)); - - g_assert (lagent_candidate_gathering_done); - g_assert (ragent_candidate_gathering_done); - - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, >=, NICE_COMPONENT_STATE_CONNECTED); - - cleanup (lagent, ragent); -} - -static void send_dummy_data(void) -{ - int sockfd = listen_socket (NULL); - union { - struct sockaddr_in in; - struct sockaddr addr; - } addr; - - memset (&addr, 0, sizeof (addr)); - addr.in.sin_family = AF_INET; - inet_pton(AF_INET, "127.0.0.1", &addr.in.sin_addr); - addr.in.sin_port = htons (stun_port); - - g_debug ("Sending dummy data to close STUN thread"); - sendto (sockfd, "close socket", 12, 0, - &addr.addr, sizeof (addr)); -} - -int main(void) -{ - NiceAgent *lagent = NULL, *ragent = NULL; - GThread *stun_thread = NULL; - NiceAddress baseaddr; - GSource *src; - int sock; - - global_cancellable = g_cancellable_new (); - src = g_cancellable_source_new (global_cancellable); - g_source_set_dummy_callback (src); - g_source_attach (src, NULL); - - sock = listen_socket (&stun_port); - - if (sock == -1) { - g_assert_not_reached (); - } - - - stun_thread = g_thread_new ("listen for STUN requests", - stun_thread_func, GINT_TO_POINTER (sock)); - - // Once the the thread is forked, we want to listen for a signal - // that the socket was opened successfully - g_mutex_lock (stun_thread_mutex_ptr); - g_cond_wait (stun_thread_signal_ptr, stun_thread_mutex_ptr); - - lagent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); - ragent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); - - g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL); - - g_object_set (G_OBJECT (lagent), "ice-trickle", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "ice-trickle", TRUE, NULL); - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - g_object_set (G_OBJECT (lagent), "upnp", USE_UPNP, NULL); - g_object_set (G_OBJECT (ragent), "upnp", USE_UPNP, NULL); - - g_object_set (G_OBJECT (lagent), "stun-server", "127.0.0.1", NULL); - g_object_set (G_OBJECT (lagent), "stun-server-port", stun_port, NULL); - - g_object_set_data (G_OBJECT (lagent), "other-agent", ragent); - g_object_set_data (G_OBJECT (ragent), "other-agent", lagent); - - g_assert (nice_address_set_from_string (&baseaddr, "127.0.0.1")); - nice_agent_add_local_address (lagent, &baseaddr); - nice_agent_add_local_address (ragent, &baseaddr); - - g_signal_connect(G_OBJECT(lagent), "candidate-gathering-done", - G_CALLBACK(cb_candidate_gathering_done), LEFT_AGENT); - g_signal_connect(G_OBJECT(ragent), "candidate-gathering-done", - G_CALLBACK(cb_candidate_gathering_done), RIGHT_AGENT); - g_signal_connect(G_OBJECT(lagent), "component-state-changed", - G_CALLBACK(cb_component_state_changed), LEFT_AGENT); - g_signal_connect(G_OBJECT(ragent), "component-state-changed", - G_CALLBACK(cb_component_state_changed), RIGHT_AGENT); - - standard_test (lagent, ragent); - bad_credentials_test (lagent, ragent); - bad_candidate_test (lagent, ragent); - new_candidate_test (lagent, ragent); - - // Do this to make sure the STUN thread exits - exit_stun_thread = TRUE; - drop_stun_packets = TRUE; - send_stun = FALSE; - send_dummy_data (); - g_cond_signal (stun_signal_ptr); - - g_object_add_weak_pointer (G_OBJECT (lagent), (gpointer *) &lagent); - g_object_add_weak_pointer (G_OBJECT (ragent), (gpointer *) &ragent); - - g_object_unref (lagent); - g_object_unref (ragent); - - g_thread_join (stun_thread); - g_object_unref (global_cancellable); - - g_source_destroy (src); - g_source_unref (src); - - WAIT_UNTIL_UNSET (lagent, NULL); - WAIT_UNTIL_UNSET (ragent, NULL); - - return 0; -} diff --git a/tests/test-nomination.c b/tests/test-nomination.c deleted file mode 100644 index 44764e3..0000000 --- a/tests/test-nomination.c +++ /dev/null @@ -1,266 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -static NiceComponentState global_lagent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST }; -static NiceComponentState global_ragent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST }; -static guint global_components_ready = 0; -static gboolean global_lagent_gathering_done = FALSE; -static gboolean global_ragent_gathering_done = FALSE; -static int global_lagent_cands = 0; -static int global_ragent_cands = 0; - -static gboolean timer_cb (gpointer pointer) -{ - g_debug ("test-nomination:%s: %p", G_STRFUNC, pointer); - - /* signal status via a global variable */ - - /* note: should not be reached, abort */ - g_error ("ERROR: test has got stuck, aborting..."); - - return FALSE; -} - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - g_debug ("test-nomination:%s: %p", G_STRFUNC, user_data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)buf; - - /* - * Lets ignore stun packets that got through - */ - if (len < 8) - return; - if (strncmp ("12345678", buf, 8)) - return; - - if (component_id != 1) - return; -} - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-nomination:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - global_lagent_gathering_done = TRUE; - else if (GPOINTER_TO_UINT (data) == 2) - global_ragent_gathering_done = TRUE; -} - - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - gboolean ready_to_connected = FALSE; - g_debug ("test-nomination:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) { - if (global_lagent_state[component_id - 1] == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_lagent_state[component_id - 1] = state; - } else if (GPOINTER_TO_UINT (data) == 2) { - if (global_ragent_state[component_id - 1] == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_ragent_state[component_id - 1] = state; - } - - if (state == NICE_COMPONENT_STATE_READY) - global_components_ready++; - else if (state == NICE_COMPONENT_STATE_CONNECTED && ready_to_connected) - global_components_ready--; - g_assert (state != NICE_COMPONENT_STATE_FAILED); - - g_debug ("test-nomination: checks READY %u.", global_components_ready); -} - -static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, - guint component_id, gchar *lfoundation, gchar* rfoundation, gpointer data) -{ - g_debug ("test-nomination:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - ++global_lagent_cands; - else if (GPOINTER_TO_UINT (data) == 2) - ++global_ragent_cands; -} - -static void set_candidates (NiceAgent *from, guint from_stream, - NiceAgent *to, guint to_stream, guint component) -{ - GSList *cands = NULL, *i; - - cands = nice_agent_get_local_candidates (from, from_stream, component); - nice_agent_set_remote_candidates (to, to_stream, component, cands); - - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); -} - -static void set_credentials (NiceAgent *lagent, guint lstream, - NiceAgent *ragent, guint rstream) -{ - gchar *ufrag = NULL, *password = NULL; - - nice_agent_get_local_credentials(lagent, lstream, &ufrag, &password); - nice_agent_set_remote_credentials (ragent, rstream, ufrag, password); - g_free (ufrag); - g_free (password); - nice_agent_get_local_credentials(ragent, rstream, &ufrag, &password); - nice_agent_set_remote_credentials (lagent, lstream, ufrag, password); - g_free (ufrag); - g_free (password); -} - -static void -run_test(NiceNominationMode l_nomination_mode, - NiceNominationMode r_nomination_mode) -{ - NiceAgent *lagent, *ragent; /* agent's L and R */ - const gchar *localhost; - NiceAddress localaddr; - guint ls_id, rs_id; - gulong timer_id; - - localhost = "127.0.0.1"; - - /* step: initialize variables modified by the callbacks */ - global_components_ready = 0; - global_lagent_gathering_done = FALSE; - global_ragent_gathering_done = FALSE; - global_lagent_cands = global_ragent_cands = 0; - - lagent = nice_agent_new_full (NULL, - NICE_COMPATIBILITY_RFC5245, - l_nomination_mode == NICE_NOMINATION_MODE_REGULAR ? - NICE_AGENT_OPTION_REGULAR_NOMINATION : 0); - - ragent = nice_agent_new_full (NULL, - NICE_COMPATIBILITY_RFC5245, - r_nomination_mode == NICE_NOMINATION_MODE_REGULAR ? - NICE_AGENT_OPTION_REGULAR_NOMINATION : 0); - - g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL); - - g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); - nice_agent_set_software (lagent, "Test-nomination, Left Agent"); - nice_agent_set_software (ragent, "Test-nomination, Right Agent"); - - timer_id = g_timeout_add (30000, timer_cb, NULL); - - if (!nice_address_set_from_string (&localaddr, localhost)) - g_assert_not_reached (); - nice_agent_add_local_address (lagent, &localaddr); - nice_agent_add_local_address (ragent, &localaddr); - - g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2)); - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - ls_id = nice_agent_add_stream (lagent, 1); - rs_id = nice_agent_add_stream (ragent, 1); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - - /* Gather candidates and test nice_agent_set_port_range */ - g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE); - g_assert (nice_agent_gather_candidates (ragent, rs_id) == TRUE); - - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_context_default (), cb_nice_recv, GUINT_TO_POINTER (1)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_context_default (), cb_nice_recv, GUINT_TO_POINTER (2)); - - g_debug ("test-nomination: Added streams, running context until 'candidate-gathering-done'..."); - while (!global_lagent_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_assert (global_lagent_gathering_done == TRUE); - while (!global_ragent_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_assert (global_ragent_gathering_done == TRUE); - - set_credentials (lagent, ls_id, ragent, rs_id); - - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP); - - while (global_lagent_state[0] != NICE_COMPONENT_STATE_READY || - global_ragent_state[0] != NICE_COMPONENT_STATE_READY) - g_main_context_iteration (NULL, TRUE); - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY); - - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - g_source_remove (timer_id); - - g_clear_object(&lagent); - g_clear_object(&ragent); -} - -static void -regular (void) -{ - run_test(NICE_NOMINATION_MODE_REGULAR, NICE_NOMINATION_MODE_REGULAR); -} - -static void -aggressive (void) -{ - run_test(NICE_NOMINATION_MODE_AGGRESSIVE, NICE_NOMINATION_MODE_AGGRESSIVE); -} - -static void -mixed_ra (void) -{ - run_test(NICE_NOMINATION_MODE_REGULAR, NICE_NOMINATION_MODE_AGGRESSIVE); -} - -static void -mixed_ar (void) -{ - run_test(NICE_NOMINATION_MODE_AGGRESSIVE, NICE_NOMINATION_MODE_REGULAR); -} - -int -main (int argc, char **argv) -{ - int ret; - - g_networking_init (); - - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/nice/nomination/regular", regular); - g_test_add_func ("/nice/nomination/aggressive", aggressive); - g_test_add_func ("/nice/nomination/mixed_ra", mixed_ra); - g_test_add_func ("/nice/nomination/mixed_ar", mixed_ar); - - ret = g_test_run (); - - return ret; -} diff --git a/tests/test-priority.c b/tests/test-priority.c deleted file mode 100644 index 822370a..0000000 --- a/tests/test-priority.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "agent-priv.h" -#include "interfaces.h" -#include "candidate.h" - - -int -main (void) -{ - NiceCandidate *candidate; - GList *ips, *i; - guint16 ip_local_preference = 0; - - candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_HOST); - nice_address_set_from_string (&candidate->addr, "127.0.0.1"); - nice_address_set_from_string (&candidate->base_addr, "127.0.0.1"); - - ips = nice_interfaces_get_local_ips (TRUE); - for (i = ips; i; i = i->next) { - if (g_strcmp0 (i->data, "127.0.0.1") == 0) - break; - ip_local_preference++; - } - g_list_free_full (ips, g_free); - - /* test 0 */ - g_assert_cmpuint (ip_local_preference, <, NICE_CANDIDATE_MAX_LOCAL_ADDRESSES); - - /* test 1 */ - g_assert_cmpuint (nice_candidate_jingle_priority (candidate), ==, 1000); - /* Host UDP */ - candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP; - candidate->component_id = 1; - g_assert_cmpuint (nice_candidate_ice_priority (candidate, FALSE, FALSE), ==, 0x782000FF + 0x100 * ip_local_preference ); - /* Host UDP reliable */ - g_assert_cmpuint (nice_candidate_ice_priority (candidate, TRUE, FALSE), ==, 0x3C2000FF + 0x100 * ip_local_preference ); - /* Host tcp-active unreliable */ - candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; - g_assert_cmpuint (nice_candidate_ice_priority (candidate, FALSE, FALSE) & 0xFFE000FF, ==, 0x3C8000FF); - /* Host tcp-active reliable */ - candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; - /* Host tcp-active reliable */ - g_assert_cmpuint (nice_candidate_ice_priority (candidate, TRUE, FALSE) & 0xFFE000FF, ==, 0x788000FF); - /* srv-reflexive tcp-active reliable */ - candidate->type = NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE; - candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; - g_assert_cmpuint (nice_candidate_ice_priority (candidate, TRUE, FALSE) & 0xFFE000FF, ==, 0x648000FF); - /* nat-assisted srv-reflexive tcp-active reliable */ - g_assert_cmpuint (nice_candidate_ice_priority (candidate, TRUE, TRUE) & 0xFFE000FF, ==, 0x698000FF); - nice_candidate_free (candidate); - - /* test 2 */ - /* 2^32*MIN(O,A) + 2*MAX(O,A) + (O>A?1:0) - = 2^32*1 + 2*5000 + 0 - = 4294977296 */ - g_assert_cmpuint (nice_candidate_pair_priority (1,5000), ==, 4294977296LL); - - /* 2^32*1 + 2*5000 + 1 = 4294977297 */ - g_assert_cmpuint (nice_candidate_pair_priority (5000, 1), ==, 4294977297LL); - - return 0; -} - diff --git a/tests/test-pseudotcp-fin.c b/tests/test-pseudotcp-fin.c deleted file mode 100644 index 743505d..0000000 --- a/tests/test-pseudotcp-fin.c +++ /dev/null @@ -1,1278 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * © 2014, 2015 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "pseudotcp.h" - - -typedef struct { - PseudoTcpSocket *left; /* owned */ - PseudoTcpSocket *right; /* owned */ - - guint32 left_current_time; - guint32 right_current_time; - - /* Data sent and received by each socket. */ - GQueue/**/ *left_sent; /* owned */ - GQueue/**/ *right_sent; /* owned */ -} Data; - -/* NOTE: Must match the on-the-wire flag values from pseudotcp.c. */ -typedef enum { - FLAG_NONE = 0, - FLAG_FIN = 1 << 0, - FLAG_SYN = 1 << 1, - FLAG_RST = 1 << 2, -} SegmentFlags; - -typedef void (*TestFunc) (Data *data, const void *next_funcs); - - -static void -data_clear (Data *data) -{ - if (data->left != NULL) - g_object_unref (data->left); - if (data->right != NULL) - g_object_unref (data->right); - - if (data->left_sent != NULL) - g_queue_free_full (data->left_sent, (GDestroyNotify) g_bytes_unref); - if (data->right_sent != NULL) - g_queue_free_full (data->right_sent, (GDestroyNotify) g_bytes_unref); -} - - -static gchar * -segment_flags_to_string (SegmentFlags flags) -{ - GString *str = g_string_new (NULL); - - if (flags & FLAG_SYN) - g_string_append (str, "SYN,"); - if (flags & FLAG_FIN) - g_string_append (str, "FIN,"); - if (flags & FLAG_RST) - g_string_append (str, "RST,"); - - /* Strip the trailing comma. */ - if (str->len > 0) - g_string_truncate (str, str->len - 1); - - if (str->len == 0) - g_string_append (str, "0"); - - return g_string_free (str, FALSE); -} - -static gchar * -segment_to_string (guint32 seq, guint32 ack, SegmentFlags flags) -{ - gchar *ctl, *out; - - ctl = segment_flags_to_string (flags); - out = g_strdup_printf ("", seq, ack, ctl); - g_free (ctl); - - return out; -} - -static gchar * -segment_bytes_to_string (const guint8 *bytes) -{ - union { - const guint8 *u8; - const guint32 *u32; - } b; - guint32 seq, ack; - guint8 flags; - - b.u8 = bytes; - - seq = ntohl (b.u32[1]); - ack = ntohl (b.u32[2]); - flags = b.u8[13]; - - return segment_to_string (seq, ack, flags); -} - - -static void -opened (PseudoTcpSocket *sock, gpointer data) -{ - g_debug ("Socket %p opened", sock); -} - -static void -readable (PseudoTcpSocket *sock, gpointer data) -{ - g_debug ("Socket %p readable", sock); -} - -static void -writable (PseudoTcpSocket *sock, gpointer data) -{ - g_debug ("Socket %p writeable", sock); -} - -static void -closed (PseudoTcpSocket *sock, guint32 err, gpointer data) -{ - g_debug ("Socket %p closed: %s", sock, strerror (err)); -} - -static PseudoTcpWriteResult -write_packet (PseudoTcpSocket *sock, const gchar *buffer, guint32 len, - gpointer user_data) -{ - Data *data = user_data; - gchar *str; /* owned */ - GQueue/**/ *queue; /* unowned */ - GBytes *segment; /* owned */ - - /* Debug output. */ - str = segment_bytes_to_string ((const guint8 *) buffer); - g_debug ("%p sent: %s", sock, str); - g_free (str); - - /* One of the sockets has outputted a packet. */ - if (sock == data->left) - queue = data->left_sent; - else if (sock == data->right) - queue = data->right_sent; - else - g_assert_not_reached (); - - segment = g_bytes_new (buffer, len); - g_queue_push_tail (queue, segment); - - return WR_SUCCESS; -} - - -static void -create_sockets (Data *data, gboolean support_fin_ack) -{ - PseudoTcpCallbacks cbs = { - data, opened, readable, writable, closed, write_packet - }; - - data->left = g_object_new (PSEUDO_TCP_SOCKET_TYPE, - "conversation", 0, - "callbacks", &cbs, - "support-fin-ack", support_fin_ack, - NULL); - data->right = g_object_new (PSEUDO_TCP_SOCKET_TYPE, - "conversation", 0, - "callbacks", &cbs, - "support-fin-ack", support_fin_ack, - NULL); - - g_debug ("Left: %p, right: %p", data->left, data->right); - - /* Control the socket clocks precisely. */ - pseudo_tcp_socket_set_time (data->left, 1); - pseudo_tcp_socket_set_time (data->right, 1); - - /* Sanity check the socket state. */ - g_assert_cmpint (pseudo_tcp_socket_send (data->left, "foo", 3), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (data->left), ==, ENOTCONN); - - g_assert_cmpint (pseudo_tcp_socket_send (data->right, "foo", 3), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (data->right), ==, ENOTCONN); - - data->left_sent = g_queue_new (); - data->right_sent = g_queue_new (); -} - -static void -expect_segment (PseudoTcpSocket *socket, GQueue/**/ *queue, - guint32 seq, guint32 ack, guint32 len, SegmentFlags flags) -{ - GBytes *bytes; /* unowned */ - union { - const guint8 *u8; - const guint32 *u32; - } b; - gsize size; - gchar *str; - - str = segment_to_string (seq, ack, flags); - g_debug ("%p expect: %s", socket, str); - g_free (str); - - /* Grab the segment. */ - bytes = g_queue_peek_head (queue); - g_assert (bytes != NULL); - - b.u8 = g_bytes_get_data (bytes, &size); - g_assert_cmpuint (size, >=, 24); /* minimum packet size */ - g_assert_cmpuint (size - 24, ==, len); - - /* Check the segment’s fields. */ - g_assert_cmpuint (ntohl (b.u32[1]), ==, seq); - g_assert_cmpuint (ntohl (b.u32[2]), ==, ack); - g_assert_cmpuint (b.u8[13], ==, flags); -} - -static void -expect_syn_sent (Data *data) -{ - expect_segment (data->left, data->left_sent, 0, 0, 7, FLAG_SYN); -} - -static void -expect_syn_received (Data *data) -{ - expect_segment (data->right, data->right_sent, 0, 7, 7, FLAG_SYN); -} - -static void -assert_empty_queues (Data *data) -{ - g_assert_cmpuint (g_queue_get_length (data->left_sent), ==, 0); - g_assert_cmpuint (g_queue_get_length (data->right_sent), ==, 0); -} - -/* Return whether the socket accepted the packet. */ -static gboolean -forward_segment (GQueue/**/ *from, PseudoTcpSocket *to) -{ - GBytes *segment; /* owned */ - const guint8 *b; - gsize size; - gboolean retval; - - segment = g_queue_pop_head (from); - g_assert (segment != NULL); - b = g_bytes_get_data (segment, &size); - retval = pseudo_tcp_socket_notify_packet (to, (const gchar *) b, size); - g_bytes_unref (segment); - - return retval; -} - -static void -forward_segment_ltr (Data *data) -{ - g_assert (forward_segment (data->left_sent, data->right)); -} - -static void -forward_segment_rtl (Data *data) -{ - g_assert (forward_segment (data->right_sent, data->left)); -} - -static void -duplicate_segment (GQueue/**/ *queue) -{ - GBytes *segment; /* unowned */ - - segment = g_queue_peek_head (queue); - g_assert (segment != NULL); - g_queue_push_head (queue, g_bytes_ref (segment)); -} - -static void -drop_segment (PseudoTcpSocket *socket, GQueue/**/ *queue) -{ - GBytes *segment; /* owned */ - gchar *str; - - segment = g_queue_pop_head (queue); - g_assert (segment != NULL); - - str = segment_bytes_to_string (g_bytes_get_data (segment, NULL)); - g_debug ("%p drop: %s", socket, str); - g_free (str); - - g_bytes_unref (segment); -} - -/* Swap the order of the head-most two segments in the @queue. */ -static void -reorder_segments (PseudoTcpSocket *socket, GQueue/**/ *queue) -{ - GBytes *segment1, *segment2; /* unowned */ - gchar *str; - - segment1 = g_queue_pop_head (queue); - g_assert (segment1 != NULL); - segment2 = g_queue_pop_head (queue); - g_assert (segment2 != NULL); - - str = segment_bytes_to_string (g_bytes_get_data (segment1, NULL)); - g_debug ("%p reorder: %s", socket, str); - g_free (str); - str = segment_bytes_to_string (g_bytes_get_data (segment2, NULL)); - g_debug ("%p after: %s", socket, str); - g_free (str); - - g_queue_push_head (queue, segment1); - g_queue_push_head (queue, segment2); -} - -static void -expect_socket_state (PseudoTcpSocket *socket, PseudoTcpState expected_state) -{ - PseudoTcpState state; - - g_object_get (socket, "state", &state, NULL); - g_assert_cmpuint (state, ==, expected_state); -} - -static void -expect_sockets_connected (Data *data) -{ - expect_socket_state (data->left, PSEUDO_TCP_ESTABLISHED); - expect_socket_state (data->right, PSEUDO_TCP_ESTABLISHED); -} - -static void -expect_sockets_closed (Data *data) -{ - guint8 buf[100]; - - expect_socket_state (data->left, PSEUDO_TCP_CLOSED); - expect_socket_state (data->right, PSEUDO_TCP_CLOSED); - - g_assert_cmpint (pseudo_tcp_socket_send (data->left, "foo", 3), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (data->left), ==, EPIPE); - g_assert_cmpint (pseudo_tcp_socket_recv (data->left, (char *) buf, sizeof (buf)), ==, 0); - - g_assert_cmpint (pseudo_tcp_socket_send (data->right, "foo", 3), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (data->right), ==, EPIPE); - g_assert_cmpint (pseudo_tcp_socket_recv (data->right, (char *) buf, sizeof (buf)), ==, 0); -} - -static void -increment_time (PseudoTcpSocket *socket, guint32 *counter, guint32 increment) -{ - g_debug ("Incrementing %p time by %u from %u to %u", socket, increment, - *counter, *counter + increment); - *counter = *counter + increment; - - pseudo_tcp_socket_set_time (socket, *counter); - pseudo_tcp_socket_notify_clock (socket); -} - -static void -increment_time_both (Data *data, guint32 increment) -{ - increment_time (data->left, &data->left_current_time, increment); - increment_time (data->right, &data->right_current_time, increment); -} - -static void -expect_fin (PseudoTcpSocket *socket, GQueue/**/ *queue, - guint32 seq, guint32 ack) -{ - expect_segment (socket, queue, seq, ack, 0, FLAG_FIN); -} - -static void -expect_rst (PseudoTcpSocket *socket, GQueue/**/ *queue, - guint32 seq, guint32 ack) -{ - expect_segment (socket, queue, seq, ack, 0, FLAG_RST); -} - -static void -expect_ack (PseudoTcpSocket *socket, GQueue/**/ *queue, - guint32 seq, guint32 ack) -{ - expect_segment (socket, queue, seq, ack, 0, FLAG_NONE); -} - -static void -expect_data (PseudoTcpSocket *socket, GQueue/**/ *queue, - guint32 seq, guint32 ack, guint32 len) -{ - expect_segment (socket, queue, seq, ack, len, FLAG_NONE); -} - -static void -close_socket (PseudoTcpSocket *socket) -{ - guint8 buf[100]; - - pseudo_tcp_socket_close (socket, FALSE); - - g_assert_cmpint (pseudo_tcp_socket_send (socket, "foo", 3), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (socket), ==, EPIPE); - g_assert_cmpint (pseudo_tcp_socket_recv (socket, (char *) buf, sizeof (buf)), ==, 0); -} - -/* Helper to create a socket pair and perform the SYN handshake. */ -static void -establish_connection (Data *data) -{ - create_sockets (data, TRUE); - pseudo_tcp_socket_connect (data->left); - expect_syn_sent (data); - forward_segment_ltr (data); - expect_syn_received (data); - forward_segment_rtl (data); - increment_time_both (data, 110); - expect_ack (data->left, data->left_sent, 7, 7); - forward_segment_ltr (data); - expect_sockets_connected (data); - - assert_empty_queues (data); -} - -/* Helper to close the LHS of a socket pair which has not transmitted any - * data (i.e. perform the first half of the FIN handshake). */ -static void -close_lhs (Data *data) -{ - pseudo_tcp_socket_close (data->left, FALSE); - - expect_fin (data->left, data->left_sent, 7, 7); - forward_segment_ltr (data); - - expect_ack (data->right, data->right_sent, 7, 8); - forward_segment_rtl (data); -} - -/* Helper to close the RHS of a socket pair which has not transmitted any - * data (i.e. perform the second half of the FIN handshake). */ -static void -close_rhs (Data *data) -{ - pseudo_tcp_socket_close (data->right, FALSE); - - expect_fin (data->right, data->right_sent, 7, 8); - forward_segment_rtl (data); - - increment_time_both (data, 10); /* TIME-WAIT */ - expect_ack (data->left, data->left_sent, 8, 8); - forward_segment_ltr (data); -} - -/* Check that establishing a connection then immediately closing it works, using - * normal handshakes (FIN, ACK, FIN, ACK). See: RFC 793, Figure 13. */ -static void -pseudotcp_close_normal (void) -{ - Data data = { 0, }; - guint8 buf[100]; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close it. Verify that sending fails. */ - close_socket (data.left); - - expect_fin (data.left, data.left_sent, 7, 7); - forward_segment_ltr (&data); - expect_ack (data.right, data.right_sent, 7, 8); - forward_segment_rtl (&data); - - /* Check the RHS is closed. */ - g_assert_cmpint (pseudo_tcp_socket_recv (data.right, (char *) buf, sizeof (buf)), ==, 0); - close_socket (data.right); - - expect_fin (data.right, data.right_sent, 7, 8); - forward_segment_rtl (&data); - increment_time_both (&data, 10); /* TIME-WAIT */ - expect_ack (data.left, data.left_sent, 8, 8); - forward_segment_ltr (&data); - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that establishing a connection then immediately closing it works, using - * simultaneous handshakes (FIN, FIN, ACK, ACK). See: RFC 793, Figure 14. */ -static void -pseudotcp_close_simultaneous (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close both sides simultaneously. Verify that sending fails. */ - close_socket (data.left); - close_socket (data.right); - - expect_fin (data.left, data.left_sent, 7, 7); - expect_fin (data.right, data.right_sent, 7, 7); - forward_segment_ltr (&data); - forward_segment_rtl (&data); - - expect_ack (data.left, data.left_sent, 8, 8); - expect_ack (data.right, data.right_sent, 8, 8); - forward_segment_ltr (&data); - forward_segment_rtl (&data); - - increment_time_both (&data, 10); /* TIME-WAIT */ - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that establishing a connection then immediately closing it works, using - * skewed handshakes. The segments are reordered so that the FIN and ACK from - * the LHS arrive at the RHS in reverse order. The RHS sees the ACK has a higher - * sequence number than the bytes it’s seen so far (as it hasn’t seen the LHS - * FIN at that point) and thus emits two sequential ACKs: one from before - * receiving the FIN (fast retransmit), and one from after. - * See: RFC 793, Figure 14. */ -static void -pseudotcp_close_skew1 (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close both sides simultaneously. Verify that sending fails. */ - close_socket (data.left); - close_socket (data.right); - - expect_fin (data.left, data.left_sent, 7, 7); - - expect_fin (data.right, data.right_sent, 7, 7); - forward_segment_rtl (&data); - - reorder_segments (data.left, data.left_sent); - expect_ack (data.left, data.left_sent, 8, 8); - forward_segment_ltr (&data); - forward_segment_ltr (&data); - - expect_ack (data.right, data.right_sent, 8, 7); - forward_segment_rtl (&data); - expect_ack (data.right, data.right_sent, 8, 8); - forward_segment_rtl (&data); - - increment_time_both (&data, 10); /* TIME-WAIT */ - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Same as pseudotcp_close_skew1() but with the packets reordered in a - * different way. */ -static void -pseudotcp_close_skew2 (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close both sides simultaneously. Verify that sending fails. */ - close_socket (data.left); - close_socket (data.right); - - expect_fin (data.right, data.right_sent, 7, 7); - - expect_fin (data.left, data.left_sent, 7, 7); - forward_segment_ltr (&data); - - reorder_segments (data.right, data.right_sent); - expect_ack (data.right, data.right_sent, 8, 8); - forward_segment_rtl (&data); - forward_segment_rtl (&data); - - expect_ack (data.left, data.left_sent, 8, 7); - forward_segment_ltr (&data); - expect_ack (data.left, data.left_sent, 8, 8); - forward_segment_ltr (&data); - - increment_time_both (&data, 10); /* TIME-WAIT */ - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that closing a connection recovers from the initial FIN segment being - * dropped. Based on: RFC 793, Figure 13. */ -static void -pseudotcp_close_normal_recovery1 (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close the LHS and drop the FIN segment. */ - close_socket (data.left); - - expect_fin (data.left, data.left_sent, 7, 7); - drop_segment (data.left, data.left_sent); - - increment_time_both (&data, 1100); /* retransmit timeout */ - - expect_fin (data.left, data.left_sent, 7, 7); - forward_segment_ltr (&data); - - expect_ack (data.right, data.right_sent, 7, 8); - forward_segment_rtl (&data); - - /* Close the RHS. */ - close_rhs (&data); - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that closing a connection recovers from the initial ACK segment being - * dropped. Based on: RFC 793, Figure 13. */ -static void -pseudotcp_close_normal_recovery2 (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close the LHS and drop the ACK segment. The LHS should retransmit the - * FIN. */ - close_socket (data.left); - - expect_fin (data.left, data.left_sent, 7, 7); - forward_segment_ltr (&data); - - expect_ack (data.right, data.right_sent, 7, 8); - drop_segment (data.right, data.right_sent); - increment_time_both (&data, 1100); /* retransmit timeout */ - expect_fin (data.left, data.left_sent, 7, 7); - forward_segment_ltr (&data); - expect_ack (data.right, data.right_sent, 7, 8); - forward_segment_rtl (&data); - - /* Close the RHS. */ - close_rhs (&data); - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that closing a connection recovers from the second FIN segment being - * dropped. Based on: RFC 793, Figure 13. */ -static void -pseudotcp_close_normal_recovery3 (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close the LHS. */ - close_lhs (&data); - - /* Close the RHS and drop the FIN segment. */ - close_socket (data.right); - - expect_fin (data.right, data.right_sent, 7, 8); - drop_segment (data.right, data.right_sent); - increment_time_both (&data, 300); /* retransmit timeout */ - expect_fin (data.right, data.right_sent, 7, 8); - forward_segment_rtl (&data); - - increment_time_both (&data, 10); /* TIME-WAIT */ - expect_ack (data.left, data.left_sent, 8, 8); - forward_segment_ltr (&data); - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that closing a connection recovers from the second ACK segment being - * dropped. Based on: RFC 793, Figure 13. */ -static void -pseudotcp_close_normal_recovery4 (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close the LHS. */ - close_lhs (&data); - - /* Close the RHS and drop the ACK segment. The RHS should retransmit the - * FIN. The timers for the two peers are manipulated separately so the LHS - * doesn’t exceed its TIME-WAIT while waiting for the retransmit. */ - close_socket (data.right); - - expect_fin (data.right, data.right_sent, 7, 8); - forward_segment_rtl (&data); - - expect_ack (data.left, data.left_sent, 8, 8); - drop_segment (data.left, data.left_sent); - increment_time (data.right, &data.right_current_time, 300); /* retransmit timeout */ - expect_fin (data.right, data.right_sent, 7, 8); - forward_segment_rtl (&data); - increment_time (data.left, &data.left_current_time, 10); /* TIME-WAIT */ - expect_ack (data.left, data.left_sent, 8, 8); - forward_segment_ltr (&data); - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that closing a connection recovers from a data segment being dropped - * immediately before the first FIN is sent. Based on: RFC 793, Figure 13. */ -static void -pseudotcp_close_normal_recovery_data (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Send some data from LHS to RHS, but drop the segment. */ - g_assert_cmpint (pseudo_tcp_socket_send (data.left, "foo", 3), ==, 3); - expect_data (data.left, data.left_sent, 7, 7, 3); - drop_segment (data.left, data.left_sent); - - assert_empty_queues(&data); - - /* Close the LHS. */ - g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.left), ==, 0); - g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.right), ==, 0); - close_socket (data.left); - - expect_socket_state (data.left, PSEUDO_TCP_FIN_WAIT_1); - expect_fin (data.left, data.left_sent, 10, 7); - forward_segment_ltr (&data); - - expect_socket_state (data.right, PSEUDO_TCP_ESTABLISHED); - expect_ack (data.right, data.right_sent, 7, 7); - forward_segment_rtl (&data); - - expect_socket_state (data.left, PSEUDO_TCP_FIN_WAIT_1); - - assert_empty_queues(&data); - - /* Close the RHS. */ - close_socket (data.right); - - expect_socket_state (data.right, PSEUDO_TCP_FIN_WAIT_1); - - expect_fin (data.right, data.right_sent, 7, 7); - forward_segment_rtl (&data); - - expect_socket_state (data.left, PSEUDO_TCP_CLOSING); - - expect_ack (data.left, data.left_sent, 11, 8); - forward_segment_ltr (&data); - - expect_socket_state (data.right, PSEUDO_TCP_FIN_WAIT_2); - - expect_data (data.right, data.right_sent, 8, 7, 0); - forward_segment_rtl (&data); - expect_socket_state (data.left, PSEUDO_TCP_CLOSING); - - expect_data (data.left, data.left_sent, 7, 8, 3); - forward_segment_ltr (&data); - expect_socket_state (data.right, PSEUDO_TCP_TIME_WAIT); - - increment_time_both (&data, 100); /* Delayed ACK */ - - expect_ack (data.right, data.right_sent, 8, 11); - forward_segment_rtl (&data); - expect_socket_state (data.left, PSEUDO_TCP_TIME_WAIT); - - increment_time_both (&data, 10); /* TIME-WAIT */ - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that if both FIN segments from a simultaneous FIN handshake are - * dropped, the handshake recovers and completes successfully. - * See: RFC 793, Figure 14. */ -static void -pseudotcp_close_simultaneous_recovery1 (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close both sides simultaneously and drop the FINs. */ - close_socket (data.left); - close_socket (data.right); - - expect_fin (data.left, data.left_sent, 7, 7); - expect_fin (data.right, data.right_sent, 7, 7); - drop_segment (data.left, data.left_sent); - drop_segment (data.right, data.right_sent); - - increment_time_both (&data, 1200); /* retransmit timeout */ - - expect_fin (data.left, data.left_sent, 7, 7); - expect_fin (data.right, data.right_sent, 7, 7); - forward_segment_ltr (&data); - forward_segment_rtl (&data); - - expect_ack (data.left, data.left_sent, 8, 8); - expect_ack (data.right, data.right_sent, 8, 8); - forward_segment_ltr (&data); - forward_segment_rtl (&data); - - increment_time_both (&data, 10); /* TIME-WAIT */ - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that if both ACK segments from a simultaneous FIN handshake are - * dropped, the handshake recovers and completes successfully. - * See: RFC 793, Figure 14. */ -static void -pseudotcp_close_simultaneous_recovery2 (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close both sides simultaneously and forward the FINs. */ - close_socket (data.left); - close_socket (data.right); - - expect_fin (data.left, data.left_sent, 7, 7); - expect_fin (data.right, data.right_sent, 7, 7); - forward_segment_ltr (&data); - forward_segment_rtl (&data); - - /* Drop the ACKs. */ - expect_ack (data.left, data.left_sent, 8, 8); - expect_ack (data.right, data.right_sent, 8, 8); - drop_segment (data.left, data.left_sent); - drop_segment (data.right, data.right_sent); - - increment_time_both (&data, 1200); /* retransmit timeout */ - - expect_fin (data.left, data.left_sent, 7, 8); - expect_fin (data.right, data.right_sent, 7, 8); - forward_segment_ltr (&data); - forward_segment_rtl (&data); - - expect_ack (data.left, data.left_sent, 8, 8); - expect_ack (data.right, data.right_sent, 8, 8); - forward_segment_ltr (&data); - forward_segment_rtl (&data); - - increment_time_both (&data, 10); /* TIME-WAIT */ - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that closing a connection ignores a duplicate FIN segment. - * Based on: RFC 793, Figure 13. */ -static void -pseudotcp_close_duplicate_fin (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close the LHS. */ - close_lhs (&data); - - /* Close the RHS and duplicate the FIN segment. */ - close_socket (data.right); - - expect_fin (data.right, data.right_sent, 7, 8); - duplicate_segment (data.right_sent); - forward_segment_rtl (&data); - forward_segment_rtl (&data); - - increment_time (data.left, &data.left_current_time, 10); /* TIME-WAIT */ - expect_ack (data.left, data.left_sent, 8, 8); - forward_segment_ltr (&data); - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that closing a connection ignores a duplicate ACK segment. - * Based on: RFC 793, Figure 13. */ -static void -pseudotcp_close_duplicate_ack (void) -{ - Data data = { 0, }; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close the LHS. */ - close_lhs (&data); - - /* Close the RHS and duplicate the ACK segment. The RHS should reject the - * duplicate with a RST segment. The LHS should then reject the RST. */ - close_socket (data.right); - - expect_fin (data.right, data.right_sent, 7, 8); - forward_segment_rtl (&data); - - increment_time (data.left, &data.left_current_time, 10); /* TIME-WAIT */ - expect_ack (data.left, data.left_sent, 8, 8); - duplicate_segment (data.left_sent); - forward_segment_ltr (&data); - g_assert (!forward_segment (data.left_sent, data.right)); - expect_rst (data.right, data.right_sent, 8, 8); - g_assert (!forward_segment (data.right_sent, data.left)); - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that forcefully closing a connection by sending a RST segment works. - * See: RFC 1122, §4.2.2.13. */ -static void -pseudotcp_close_rst (void) -{ - Data data = { 0, }; - guint8 buf[100]; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close the LHS. */ - pseudo_tcp_socket_close (data.left, TRUE); - - g_assert_cmpint (pseudo_tcp_socket_send (data.left, "foo", 3), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (data.left), ==, EPIPE); - g_assert_cmpint (pseudo_tcp_socket_recv (data.left, (char *) buf, sizeof (buf)), ==, 0); - - expect_rst (data.left, data.left_sent, 7, 7); - g_assert (!forward_segment (data.left_sent, data.right)); - - /* Check the RHS is closed. */ - g_assert_cmpint (pseudo_tcp_socket_send (data.right, "foo", 3), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (data.right), ==, EPIPE); - g_assert_cmpint (pseudo_tcp_socket_recv (data.right, (char *) buf, sizeof (buf)), ==, 0); - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that an RST is sent if a connection is closed with pending data in the - * local receive buffer. See: RFC 1122, §4.2.2.13. */ -static void -pseudotcp_close_pending_received (void) -{ - Data data = { 0, }; - guint8 buf[100]; - - /* Establish a connection. */ - establish_connection (&data); - - /* Send some data from RHS to LHS. Do *not* read the data from the LHS receive - * buffer. */ - g_assert_cmpint (pseudo_tcp_socket_send (data.right, "foo", 3), ==, 3); - expect_data (data.right, data.right_sent, 7, 7, 3); - forward_segment_rtl (&data); - - /* Close the LHS. */ - g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.left), ==, 3); - close_socket (data.left); - - expect_rst (data.left, data.left_sent, 7, 10); - g_assert (!forward_segment (data.left_sent, data.right)); - - /* Check the RHS is closed. */ - g_assert_cmpint (pseudo_tcp_socket_send (data.right, "foo", 3), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (data.right), ==, EPIPE); - g_assert_cmpint (pseudo_tcp_socket_recv (data.right, (char *) buf, sizeof (buf)), ==, 0); - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that an RST is sent if data is received on a socket after close() has - * been called. See: RFC 1122, §4.2.2.13. */ -static void -pseudotcp_close_rst_afterwards (void) -{ - Data data = { 0, }; - guint8 buf[100]; - - /* Establish a connection. */ - establish_connection (&data); - - /* Close the LHS. */ - g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.left), ==, 0); - pseudo_tcp_socket_close (data.left, TRUE); - close_socket (data.left); - - expect_rst (data.left, data.left_sent, 7, 7); - drop_segment (data.left, data.left_sent); /* just to get it out of the way */ - - assert_empty_queues(&data); - - /* Send some data from RHS to LHS, which should result in an RST. */ - g_assert_cmpint (pseudo_tcp_socket_send (data.right, "foo", 3), ==, 3); - expect_data (data.right, data.right_sent, 7, 7, 3); - g_assert (!forward_segment (data.right_sent, data.left)); - - expect_rst (data.left, data.left_sent, 7, 7); - g_assert (!forward_segment (data.left_sent, data.right)); - - /* Check the RHS is closed. */ - g_assert_cmpint (pseudo_tcp_socket_send (data.right, "foo", 3), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (data.right), ==, EPIPE); - g_assert_cmpint (pseudo_tcp_socket_recv (data.right, (char *) buf, sizeof (buf)), ==, 0); - - expect_sockets_closed (&data); - - data_clear (&data); -} - -/* Check that two pseudo-TCP sockets interact correctly even if FIN–ACK support - * is disabled on one of them. */ -static void -pseudotcp_compatibility (void) -{ - Data data = { 0, }; - guint8 buf[100]; - guint64 timeout; - - /* Establish a connection. Note the sequence numbers should start at 4 this - * time, rather than the 7 in other tests, because the FIN–ACK option should - * not be being sent. */ - create_sockets (&data, FALSE); - pseudo_tcp_socket_connect (data.left); - expect_segment (data.left, data.left_sent, 0, 0, 4, FLAG_SYN); - forward_segment_ltr (&data); - expect_segment (data.right, data.right_sent, 0, 4, 4, FLAG_SYN); - forward_segment_rtl (&data); - increment_time_both (&data, 110); - expect_ack (data.left, data.left_sent, 4, 4); - forward_segment_ltr (&data); - expect_sockets_connected (&data); - - /* Close it. Sending shouldn’t fail. */ - pseudo_tcp_socket_close (data.left, FALSE); - g_assert (!pseudo_tcp_socket_is_closed (data.left)); - - g_assert_cmpint (pseudo_tcp_socket_send (data.left, "foo", 3), ==, 3); - g_assert_cmpint (pseudo_tcp_socket_recv (data.left, (char *) buf, sizeof (buf)), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (data.left), ==, EWOULDBLOCK); - - expect_data (data.left, data.left_sent, 4, 4, 3); - forward_segment_ltr (&data); - - increment_time_both (&data, 100); - - expect_ack (data.right, data.right_sent, 4, 7); - forward_segment_rtl (&data); - - /* Advance the timers; now the LHS should be closed, as the RHS has ACKed all - * outstanding data. */ - increment_time_both (&data, 50); - - g_assert (!pseudo_tcp_socket_get_next_clock (data.left, &timeout)); - - /* Check the RHS can be closed after receiving the data just sent. */ - g_assert_cmpint (pseudo_tcp_socket_recv (data.right, (char *) buf, sizeof (buf)), ==, 3); - g_assert_cmpint (pseudo_tcp_socket_recv (data.right, (char *) buf, sizeof (buf)), ==, -1); - g_assert_cmpint (pseudo_tcp_socket_get_error (data.right), ==, EWOULDBLOCK); - - pseudo_tcp_socket_close (data.right, FALSE); - - g_assert (!pseudo_tcp_socket_get_next_clock (data.right, &timeout)); - - expect_sockets_closed (&data); - - data_clear (&data); -} - - -/* Check that after receiving a FIN, queued data can still be read */ -static void -pseudotcp_close_recv_queued (void) -{ - Data data = { 0, }; - guint8 buf[100]; - - /* Establish a connection. */ - establish_connection (&data); - - g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.left), ==, 0); - g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.right), ==, 0); - g_assert_cmpint (pseudo_tcp_socket_get_available_send_space (data.right), >, - 0); - g_assert_cmpint (pseudo_tcp_socket_get_available_send_space (data.left), >, - 0); - - g_assert_cmpint (pseudo_tcp_socket_send (data.left, "foo", 3), ==, 3); - expect_data (data.left, data.left_sent, 7, 7, 3); - forward_segment_ltr (&data); - - increment_time_both (&data, 100); /* Delayed ACK */ - expect_ack (data.right, data.right_sent, 7, 10); - forward_segment_rtl (&data); - - close_socket (data.left); - expect_fin (data.left, data.left_sent, 10, 7); - forward_segment_ltr (&data); - - expect_socket_state (data.left, PSEUDO_TCP_FIN_WAIT_1); - expect_socket_state (data.right, PSEUDO_TCP_CLOSE_WAIT); - - g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.left), ==, 0); - g_assert_cmpint (pseudo_tcp_socket_get_available_send_space (data.left), ==, - 0); - - expect_ack (data.right, data.right_sent, 7, 11); - forward_segment_rtl (&data); - - expect_socket_state (data.left, PSEUDO_TCP_FIN_WAIT_2); - - - g_assert_cmpint (pseudo_tcp_socket_get_available_bytes (data.right), ==, 3); - - g_assert_cmpint (pseudo_tcp_socket_get_available_send_space (data.right), >, - 0); - - /* Check that the data can be read */ - g_assert_cmpint (pseudo_tcp_socket_recv (data.right, (char *) buf, sizeof (buf)), ==, 3); - - /* Now the socket should be empty */ - g_assert_cmpint (pseudo_tcp_socket_recv (data.right, (char *) buf, sizeof (buf)), ==, 0); - - data_clear (&data); -} - -int -main (int argc, char *argv[]) -{ - setlocale (LC_ALL, ""); - g_test_init (&argc, &argv, NULL); - pseudo_tcp_set_debug_level (PSEUDO_TCP_DEBUG_VERBOSE); - - /* There are four possible scenarios for the FIN handshake, if the possibility - * of dropped or duplicated segments is ignored (but reordered segments are - * allowed: normal, simultaneous, and two types of skew. - * - * These can be generated by considering the events happening at a single peer - * during connection closure: sending the FIN (SF), receiving a FIN and - * sending a FIN-ACK (RF), receiving a FIN-ACK (RA). These have the following - * permutations: - * • SF, RF, RA - * • SF, RA, RF - * • RF, SF, RA - * Other permutations are disallowed because SF must come before RA. - * - * The permutations of one peer’s (1) behaviour with a second (2) can then be - * considered: - * • 1: SF, RF, RA; 2: SF, RF, RA (simultaneous) - * • 1: SF, RF, RA; 2: SF, RA, RF (skew 1) - * • 1: SF, RF, RA; 2: RF, SF, RA (skew 2) - * • 1: SF, RA, RF; 2: RF, SF, RA (normal) - * Other permutations are disallowed because SF on one peer must come before - * RF on the other; similarly RF on one must come before RA on the other. - * - * Thus, the following unit tests provably cover all possible scenarios where - * segments can be reordered but not dropped or duplicated. */ - g_test_add_func ("/pseudotcp/close/normal", - pseudotcp_close_normal); - g_test_add_func ("/pseudotcp/close/simultaneous", - pseudotcp_close_simultaneous); - g_test_add_func ("/pseudotcp/close/skew1", - pseudotcp_close_skew1); - g_test_add_func ("/pseudotcp/close/skew2", - pseudotcp_close_skew2); - - /* An arbitrary (less methodical) selection of unit tests for dropped and - * duplicated packets. */ - g_test_add_func ("/pseudotcp/close/normal/recovery1", - pseudotcp_close_normal_recovery1); - g_test_add_func ("/pseudotcp/close/normal/recovery2", - pseudotcp_close_normal_recovery2); - g_test_add_func ("/pseudotcp/close/normal/recovery3", - pseudotcp_close_normal_recovery3); - g_test_add_func ("/pseudotcp/close/normal/recovery4", - pseudotcp_close_normal_recovery4); - g_test_add_func ("/pseudotcp/close/normal/recovery-data", - pseudotcp_close_normal_recovery_data); - g_test_add_func ("/pseudotcp/close/simultaneous/recovery1", - pseudotcp_close_simultaneous_recovery1); - g_test_add_func ("/pseudotcp/close/simultaneous/recovery2", - pseudotcp_close_simultaneous_recovery2); - g_test_add_func ("/pseudotcp/close/duplicate-fin", - pseudotcp_close_duplicate_fin); - g_test_add_func ("/pseudotcp/close/duplicate-ack", - pseudotcp_close_duplicate_ack); - - g_test_add_func ("/pseudotcp/close/rst", - pseudotcp_close_rst); - g_test_add_func ("/pseudotcp/close/pending-received", - pseudotcp_close_pending_received); - g_test_add_func ("/pseudotcp/close/rst-afterwards", - pseudotcp_close_rst_afterwards); - - g_test_add_func ("/pseudotcp/close/recv-queued", - pseudotcp_close_recv_queued); - - g_test_add_func ("/pseudotcp/compatibility", - pseudotcp_compatibility); - - g_test_run (); - - return 0; -} diff --git a/tests/test-pseudotcp-fuzzy.c b/tests/test-pseudotcp-fuzzy.c deleted file mode 100644 index 3c41a9b..0000000 --- a/tests/test-pseudotcp-fuzzy.c +++ /dev/null @@ -1,468 +0,0 @@ -/* vim: et ts=2 sw=2 tw=80: */ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2010, 2014 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "pseudotcp.h" - - -/** - * A fuzzing test for the pseudotcp socket. This connects two sockets in a - * loopback arrangement, with the packet output from one being fed to the other, - * and vice-versa. Fuzzing happens on the packet interface between the two, - * mutating the packets slightly and seeing what happens. - * - * The input data to the left-most socket is read from a file. The output data - * from the loopback is written to another file, although this probably isn’t - * very useful. If no files are provided, a small amount of dummy data is sent - * through the sockets instead. This almost certainly won’t catch any bugs, and - * is just present to allow this test to be run as part of `make check` so it - * doesn’t bit rot. - * - * A good command to generate an input file is: - * dd if=/dev/urandom of=rand count=10000 ibs=1024 - * - * None of the data is validated, and the test results are effectively the 1-bit - * value of ‘did it crash?’. In particular, the output file is not validated, - * and the TCP packets emitted by both sockets are not checked for validity. - * - * It is suggested that this test is run under GDB and Valgrind. Any crashes or - * errors which are detected can be reproduced by providing the same input file - * and seed (using the --seed option). The seed is printed out at the beginning - * of each test run. - */ - - -PseudoTcpSocket *left; -PseudoTcpSocket *right; -GMainLoop *main_loop = NULL; -GRand *prng = NULL; -gint retval = 0; -FILE *in = NULL; -FILE *out = NULL; -int total_read = 0; -int total_wrote = 0; -guint left_clock = 0; -guint right_clock = 0; -gboolean left_closed = FALSE; -gboolean right_closed = FALSE; -gboolean reading_done = FALSE; - -/* Number of bytes of payload each socket has received so far. */ -guint32 left_stream_pos = 0; -guint32 right_stream_pos = 0; - -/* Configuration options. */ -gint64 seed = 0; -guint32 fuzz_start_pos = 1; /* bytes into stream payload; after the SYN-ACKs */ -guint n_changes_lambda = 1; /* lambda parameter for a Poisson distribution - * controlling the number of mutations made to each - * packet */ - - -static void -adjust_clock (PseudoTcpSocket *sock); - - -static void -write_to_sock (PseudoTcpSocket *sock) -{ - gchar buf[1024]; - gsize len; - gint wlen; - guint total = 0; - - while (TRUE) { - len = fread (buf, 1, sizeof(buf), in); - if (len == 0) { - g_debug ("Done reading data from file"); - g_assert (feof (in)); - reading_done = TRUE; - pseudo_tcp_socket_close (sock, FALSE); - break; - } else { - wlen = pseudo_tcp_socket_send (sock, buf, len); - g_debug ("Sending %" G_GSIZE_FORMAT " bytes : %d", len, wlen); - total += wlen; - total_read += wlen; - if (wlen < (gint) len) { - g_debug ("seeking %" G_GSIZE_FORMAT " from %lu", wlen - len, ftell (in)); - fseek (in, wlen - len, SEEK_CUR); - g_assert (!feof (in)); - g_debug ("Socket queue full after %d bytes written", total); - break; - } - } - } - adjust_clock (sock); -} - -static void -opened (PseudoTcpSocket *sock, gpointer data) -{ - g_debug ("Socket %p Opened", sock); - if (sock == left) { - if (in) - write_to_sock (sock); - else { - pseudo_tcp_socket_send (sock, "abcdefghijklmnopqrstuvwxyz", 26); - reading_done = TRUE; - pseudo_tcp_socket_close (sock, FALSE); - } - } -} - -static void -readable (PseudoTcpSocket *sock, gpointer data) -{ - gchar buf[1024]; - gint len; - g_debug ("Socket %p Readable", sock); - - do { - len = pseudo_tcp_socket_recv (sock, buf, sizeof(buf)); - - if (len > 0) { - g_debug ("Read %d bytes", len); - if (out) { - if (fwrite (buf, len, 1, out) == 0) - g_debug ("Error writing to output file"); - else { - total_wrote += len; - - g_assert_cmpint (total_wrote, <=, total_read); - g_debug ("Written %d bytes, need %d bytes", total_wrote, total_read); - if (total_wrote == total_read && feof (in)) { - g_assert (reading_done); - pseudo_tcp_socket_close (sock, FALSE); - } - } - } else { - pseudo_tcp_socket_close (sock, FALSE); - } - } else if (len == 0) { - pseudo_tcp_socket_close (sock, FALSE); - } - } while (len > 0); - - if (len == -1 && - pseudo_tcp_socket_get_error (sock) != EWOULDBLOCK) { - g_printerr ("Error reading from socket %p: %s.\n", - sock, g_strerror (pseudo_tcp_socket_get_error (sock))); - - retval = -1; - g_main_loop_quit (main_loop); - return; - } -} - -static void -writable (PseudoTcpSocket *sock, gpointer data) -{ - g_debug ("Socket %p Writable", sock); - if (in && sock == left) - write_to_sock (sock); -} - -static void -closed (PseudoTcpSocket *sock, guint32 err, gpointer data) -{ - /* Don’t treat this as an error, since we’re throwing rubbish into the - * socket and can hardly expect it to complete successfully. */ - g_debug ("Socket %p Closed: %s", sock, g_strerror (err)); - retval = 0; - g_main_loop_quit (main_loop); -} - -struct notify_data { - PseudoTcpSocket *sock; - guint32 len; - guint32 stream_pos; - guint8 buffer[]; -}; - -/** - * random_int_poisson: - * @lambda: Lambda parameter for the distribution function, which must be - * non-zero - * - * Generate a random variable from a Poisson distribution with parameter - * @lambda. This consumes one %gdouble’s worth of randomness from the global - * @prng. - * - * This is implemented using the inverse transform of the Poisson CDF, and is - * guaranteed to return in time linearly proportional to @lambda. - * - * Returns: Poisson-distributed pseudo-random variable - */ -static guint32 -random_int_poisson (guint lambda) -{ - gdouble U; - guint32 i; - gdouble p, F; - - g_return_val_if_fail (lambda > 0, 0); - - /* - * Reference: http://www.cs.bgu.ac.il/~mps042/invtransnote.htm, - * §Simulating a Poisson random variable. - */ - U = g_rand_double (prng); /* step 1 */ - i = 0; - p = exp (0.0 - (gdouble) lambda); - F = p; /* step 2 */ - - while (U >= F) { /* step 3 */ - p = (lambda * p) / (i + 1); - F += p; - i += 1; /* step 4 and 5 */ - } - - return i; -} - -static guint32 -fuzz_packet (guint8 *buf, guint32 len, guint32 stream_pos) -{ - guint32 i; - guint n_changes; -#define HEADER_LENGTH 24 /* bytes; or thereabouts (include some options) */ - - /* Do we want to fuzz this packet? */ - if (stream_pos < fuzz_start_pos) { - return len; - } - - /* Get fuzzing. Only bother fuzzing the header; fuzzing the payload is - * pointless. Weight the number of changes towards having only a few changes, - * since that makes them less likely to be summarily rejected. */ - n_changes = random_int_poisson (n_changes_lambda); - g_debug ("Making %u changes for bytes at stream position %u:", - n_changes, stream_pos); - - for (i = 0; i < n_changes; i++) { - guint32 pos = g_rand_int_range (prng, 0, MIN (len, HEADER_LENGTH)); - g_debug (" • Changing byte %u.", stream_pos + pos); - buf[pos] = g_rand_int_range (prng, 0, G_MAXUINT8 + 1); - } - - return len; -} - -static gboolean -notify_packet (gpointer user_data) -{ - struct notify_data *data = (struct notify_data*) user_data; - - /* Fuzz the packet. */ - data->len = fuzz_packet (data->buffer, data->len, data->stream_pos); - - pseudo_tcp_socket_notify_packet (data->sock, - (gchar *) data->buffer, data->len); - adjust_clock (data->sock); - - g_free (data); - return FALSE; -} - -static PseudoTcpWriteResult -write_packet (PseudoTcpSocket *sock, const gchar *buffer, guint32 len, - gpointer user_data) -{ - struct notify_data *data; - PseudoTcpState state; - g_object_get (sock, "state", &state, NULL); - - data = g_malloc (sizeof(struct notify_data) + len); - - g_debug ("Socket %p(%d) Writing : %d bytes", sock, state, len); - - memcpy (data->buffer, buffer, len); - data->len = len; - - if (sock == left) { - data->stream_pos = left_stream_pos; - left_stream_pos += len; - data->sock = right; - } else { - data->stream_pos = right_stream_pos; - right_stream_pos += len; - data->sock = left; - } - - g_idle_add (notify_packet, data); - - return WR_SUCCESS; -} - - -static gboolean notify_clock (gpointer data) -{ - PseudoTcpSocket *sock = (PseudoTcpSocket *)data; - //g_debug ("Socket %p: Notifying clock", sock); - pseudo_tcp_socket_notify_clock (sock); - adjust_clock (sock); - return FALSE; -} - -static void adjust_clock (PseudoTcpSocket *sock) -{ - guint64 timeout = 0; - - if (pseudo_tcp_socket_get_next_clock (sock, &timeout)) { - timeout -= g_get_monotonic_time () / 1000; - g_debug ("Socket %p: Adjusting clock to %" G_GUINT64_FORMAT " ms", sock, timeout); - if (sock == left) { - if (left_clock != 0) - g_source_remove (left_clock); - left_clock = g_timeout_add (timeout, notify_clock, sock); - } else { - if (right_clock != 0) - g_source_remove (right_clock); - right_clock = g_timeout_add (timeout, notify_clock, sock); - } - } else { - g_debug ("Socket %p should be destroyed, it's done", sock); - if (sock == left) - left_closed = TRUE; - else - right_closed = TRUE; - if (left_closed && right_closed) - g_main_loop_quit (main_loop); - } -} - -static GOptionEntry entries[] = { - { "seed", 's', 0, G_OPTION_ARG_INT64, &seed, "PRNG seed", "N" }, - { "fuzz-start-position", 'p', 0, G_OPTION_ARG_INT, &fuzz_start_pos, - "Number of bytes into the stream to start fuzzing after", "B" }, - { "fuzz-n-changes-lambda", 'l', 0, G_OPTION_ARG_INT, &n_changes_lambda, - "Lambda value for the Poisson distribution controlling the number of " - "changes made to each packet", "λ" }, - { NULL } -}; - -int main (int argc, char *argv[]) -{ - PseudoTcpCallbacks cbs = { - NULL, opened, readable, writable, closed, write_packet - }; - GOptionContext *context; - GError *error = NULL; - - setlocale (LC_ALL, ""); - - /* Configuration. */ - context = g_option_context_new ("— fuzz-test the pseudotcp socket"); - g_option_context_add_main_entries (context, entries, NULL); - - if (!g_option_context_parse (context, &argc, &argv, &error)) { - g_printerr ("Option parsing failed: %s\n", error->message); - goto context_error; - } - - if (n_changes_lambda == 0) { - g_printerr ("Option parsing failed: %s\n", - "Lambda values must be positive."); - goto context_error; - } - - g_option_context_free (context); - - /* Tweak the configuration. */ - if (seed == 0) { - seed = g_get_real_time (); - } - - /* Open the input and output files */ - if (argc >= 3) { - in = fopen (argv[1], "r"); - out = fopen (argv[2], "w"); - } - - /* Set up the main loop and sockets. */ - main_loop = g_main_loop_new (NULL, FALSE); - - g_print ("Using seed: %" G_GINT64_FORMAT ", start position: %u, λ: %u\n", - seed, fuzz_start_pos, n_changes_lambda); - prng = g_rand_new_with_seed (seed); - - pseudo_tcp_set_debug_level (PSEUDO_TCP_DEBUG_VERBOSE); - - left = pseudo_tcp_socket_new (0, &cbs); - right = pseudo_tcp_socket_new (0, &cbs); - g_debug ("Left: %p. Right: %p", left, right); - - pseudo_tcp_socket_notify_mtu (left, 1496); - pseudo_tcp_socket_notify_mtu (right, 1496); - - pseudo_tcp_socket_connect (left); - adjust_clock (left); - adjust_clock (right); - - /* Run the main loop. */ - g_main_loop_run (main_loop); - g_main_loop_unref (main_loop); - - g_object_unref (left); - g_object_unref (right); - - g_rand_free (prng); - - if (in != NULL) - fclose (in); - if (out != NULL) - fclose (out); - - return retval; - -context_error: - g_printerr ("\n%s\n", g_option_context_get_help (context, TRUE, NULL)); - g_option_context_free (context); - - return 1; -} diff --git a/tests/test-pseudotcp-random.sh b/tests/test-pseudotcp-random.sh deleted file mode 100755 index f98d12e..0000000 --- a/tests/test-pseudotcp-random.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -set -e - -if test -n "${BUILT_WITH_MESON}"; then - TEST_PSEUDOTCP=$1 -else - TEST_PSEUDOTCP=./test-pseudotcp -fi - -cleanup() { - rm -rf rand rand-copy -} - -trap cleanup EXIT - -dd if=/dev/urandom of=rand count=1024 ibs=1024 -"${TEST_PSEUDOTCP}" rand rand-copy -diff rand rand-copy diff --git a/tests/test-pseudotcp.c b/tests/test-pseudotcp.c deleted file mode 100644 index e975dd9..0000000 --- a/tests/test-pseudotcp.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2010 Collabora Ltd. - * Contact: Youness Alaoui - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Youness Alaoui, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "pseudotcp.h" - -PseudoTcpSocket *left; -PseudoTcpSocket *right; -GMainLoop *mainloop = NULL; -FILE *in = NULL; -FILE *out = NULL; -int total_read = 0; -int total_wrote = 0; -guint left_clock = 0; -guint right_clock = 0; -gboolean left_closed; -gboolean right_closed; - -gboolean reading_done = FALSE; - -static void adjust_clock (PseudoTcpSocket *sock); - -static void write_to_sock (PseudoTcpSocket *sock) -{ - gchar buf[1024]; - gsize len; - gint wlen; - guint total = 0; - - while (TRUE) { - len = fread (buf, 1, sizeof(buf), in); - if (len == 0) { - g_debug ("Done reading data from file"); - g_assert (feof (in)); - reading_done = TRUE; - pseudo_tcp_socket_close (sock, FALSE); - break; - } else { - wlen = pseudo_tcp_socket_send (sock, buf, len); - g_debug ("Sending %" G_GSIZE_FORMAT " bytes : %d", len, wlen); - total += wlen; - total_read += wlen; - if (wlen < (gint) len) { - g_debug ("seeking %" G_GSIZE_FORMAT " from %lu", wlen - len, - ftell (in)); - fseek (in, wlen - len, SEEK_CUR); - g_assert (!feof (in)); - g_debug ("Socket queue full after %d bytes written", total); - break; - } - } - } - adjust_clock (sock); -} - -static void opened (PseudoTcpSocket *sock, gpointer data) -{ - g_debug ("Socket %p Opened", sock); - if (sock == left) { - if (in) - write_to_sock (sock); - else { - pseudo_tcp_socket_send (sock, "abcdefghijklmnopqrstuvwxyz", 26); - reading_done = TRUE; - pseudo_tcp_socket_close (sock, FALSE); - } - } -} - -static void readable (PseudoTcpSocket *sock, gpointer data) -{ - gchar buf[1024]; - gint len; - g_debug ("Socket %p Readable", sock); - - do { - len = pseudo_tcp_socket_recv (sock, buf, sizeof(buf)); - - if (len > 0) { - g_debug ("Read %d bytes", len); - if (out) { - if (fwrite (buf, len, 1, out) == 0) - g_debug ("Error writing to output file"); - else { - total_wrote += len; - - g_assert_cmpint (total_wrote, <=, total_read); - g_debug ("Written %d bytes, need %d bytes", total_wrote, total_read); - if (total_wrote == total_read && feof (in)) { - g_assert (reading_done); - pseudo_tcp_socket_close (sock, FALSE); - } - } - } else { - if (len == 26 && strncmp (buf, "abcdefghijklmnopqrstuvwxyz", len) == 0) { - pseudo_tcp_socket_close (sock, FALSE); - } else { - g_debug ("Error reading data.. read %d bytes : %s", len, buf); - exit (-1); - } - } - } else if (len == 0) { - pseudo_tcp_socket_close (sock, FALSE); - } - } while (len > 0); - - if (len == -1 && - pseudo_tcp_socket_get_error (sock) != EWOULDBLOCK) { - g_debug ("Error reading from socket %p: %s", sock, - g_strerror (pseudo_tcp_socket_get_error (sock))); - exit (-1); - } -} - -static void writable (PseudoTcpSocket *sock, gpointer data) -{ - g_debug ("Socket %p Writable", sock); - if (in && sock == left) - write_to_sock (sock); -} - -static void closed (PseudoTcpSocket *sock, guint32 err, gpointer data) -{ - g_error ("Socket %p Closed : %d", sock, err); -} - -struct notify_data { - PseudoTcpSocket *sock; - guint32 len; - gchar buffer[]; -}; - -static gboolean notify_packet (gpointer user_data) -{ - struct notify_data *data = (struct notify_data*) user_data; - - pseudo_tcp_socket_notify_packet (data->sock, data->buffer, data->len); - adjust_clock (data->sock); - - g_free (data); - return FALSE; -} - -static PseudoTcpWriteResult write_packet (PseudoTcpSocket *sock, - const gchar *buffer, guint32 len, gpointer user_data) -{ - struct notify_data *data; - PseudoTcpState state; - int drop_rate = rand () % 100; - g_object_get (sock, "state", &state, NULL); - - if (drop_rate < 5) { - g_debug ("*********************Dropping packet (%d) from %p", drop_rate, - sock); - return WR_SUCCESS; - } - - data = g_malloc (sizeof(struct notify_data) + len); - - g_debug ("Socket %p(%d) Writing : %d bytes", sock, state, len); - - memcpy (data->buffer, buffer, len); - data->len = len; - - if (sock == left) - data->sock = right; - else - data->sock = left; - - g_idle_add (notify_packet, data); - - return WR_SUCCESS; -} - - -static gboolean notify_clock (gpointer data) -{ - PseudoTcpSocket *sock = (PseudoTcpSocket *)data; - //g_debug ("Socket %p: Notifying clock", sock); - pseudo_tcp_socket_notify_clock (sock); - adjust_clock (sock); - return FALSE; -} - -static void adjust_clock (PseudoTcpSocket *sock) -{ - guint64 timeout = 0; - - if (pseudo_tcp_socket_get_next_clock (sock, &timeout)) { - timeout -= g_get_monotonic_time () / 1000; - g_debug ("Socket %p: Adjusting clock to %" G_GUINT64_FORMAT " ms", sock, timeout); - if (sock == left) { - if (left_clock != 0) - g_source_remove (left_clock); - left_clock = g_timeout_add (timeout, notify_clock, sock); - } else { - if (right_clock != 0) - g_source_remove (right_clock); - right_clock = g_timeout_add (timeout, notify_clock, sock); - } - } else { - g_debug ("Socket %p should be destroyed, it's done", sock); - if (sock == left) - left_closed = TRUE; - else - right_closed = TRUE; - if (left_closed && right_closed) - g_main_loop_quit (mainloop); - } -} - - -int main (int argc, char *argv[]) -{ - PseudoTcpCallbacks cbs = { - NULL, opened, readable, writable, closed, write_packet - }; - - setlocale (LC_ALL, ""); - - mainloop = g_main_loop_new (NULL, FALSE); - - pseudo_tcp_set_debug_level (PSEUDO_TCP_DEBUG_VERBOSE); - - left_closed = right_closed = FALSE; - - left = pseudo_tcp_socket_new (0, &cbs); - right = pseudo_tcp_socket_new (0, &cbs); - g_debug ("Left: %p. Right: %p", left, right); - - pseudo_tcp_socket_notify_mtu (left, 1496); - pseudo_tcp_socket_notify_mtu (right, 1496); - - pseudo_tcp_socket_connect (left); - adjust_clock (left); - adjust_clock (right); - - if (argc == 3) { - in = fopen (argv[1], "r"); - out = fopen (argv[2], "w"); - } - - g_main_loop_run (mainloop); - - g_object_unref (left); - g_object_unref (right); - - if (in) - fclose (in); - if (out) - fclose (out); - - return 0; -} - diff --git a/tests/test-restart.c b/tests/test-restart.c deleted file mode 100644 index 064cd69..0000000 --- a/tests/test-restart.c +++ /dev/null @@ -1,495 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "agent-priv.h" /* for testing purposes */ - -#include -#include -#ifdef _WIN32 -#include -#endif - -static NiceComponentState global_lagent_state = NICE_COMPONENT_STATE_LAST; -static NiceComponentState global_ragent_state = NICE_COMPONENT_STATE_LAST; -static guint global_components_ready = 0; -static guint global_components_ready_exit = 0; -static guint global_components_failed = 0; -static guint global_components_failed_exit = 0; -static GMainLoop *global_mainloop = NULL; -static gboolean global_lagent_gathering_done = FALSE; -static gboolean global_ragent_gathering_done = FALSE; -static gboolean global_lagent_ibr_received = FALSE; -static gboolean global_ragent_ibr_received = FALSE; -static int global_lagent_cands = 0; -static int global_ragent_cands = 0; -static gint global_ragent_read = 0; -static gint global_ragent_read_exit = 0; - -static void priv_print_global_status (void) -{ - g_debug ("\tgathering_done=%d", global_lagent_gathering_done && global_ragent_gathering_done); - g_debug ("\tlstate=%d", global_lagent_state); - g_debug ("\trstate=%d", global_ragent_state); -} - -static gboolean timer_cb (gpointer pointer) -{ - g_debug ("test-restart:%s: %p", G_STRFUNC, pointer); - - /* signal status via a global variable */ - - /* note: should not be reached, abort */ - g_debug ("ERROR: test has got stuck, aborting..."); - exit (-1); - -} - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - g_debug ("test-restart:%s: %p", G_STRFUNC, user_data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)buf; - - if ((intptr_t)user_data == 2) { - global_ragent_read += len; - - if (global_ragent_read == global_ragent_read_exit) - g_main_loop_quit (global_mainloop); - } -} - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-restart:%s: %p", G_STRFUNC, data); - - if ((intptr_t)data == 1) - global_lagent_gathering_done = TRUE; - else if ((intptr_t)data == 2) - global_ragent_gathering_done = TRUE; - - if (global_lagent_gathering_done && - global_ragent_gathering_done) - g_main_loop_quit (global_mainloop); - - /* XXX: dear compiler, these are for you: */ - (void)agent; -} - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - g_debug ("test-restart:%s: %p", G_STRFUNC, data); - - if ((intptr_t)data == 1) - global_lagent_state = state; - else if ((intptr_t)data == 2) - global_ragent_state = state; - - if (state == NICE_COMPONENT_STATE_READY) - global_components_ready++; - if (state == NICE_COMPONENT_STATE_FAILED) - global_components_failed++; - - g_debug ("test-restart: READY %u exit at %u.", global_components_ready, global_components_ready_exit); - - /* signal status via a global variable */ - if (global_components_ready == global_components_ready_exit) { - g_main_loop_quit (global_mainloop); - return; - } - - /* signal status via a global variable */ - if (global_components_failed == global_components_failed_exit) { - g_main_loop_quit (global_mainloop); - return; - } - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; -} - -static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id, - gchar *lfoundation, gchar* rfoundation, gpointer data) -{ - g_debug ("test-restart:%s: %p", G_STRFUNC, data); - - if ((intptr_t)data == 1) - ++global_lagent_cands; - else if ((intptr_t)data == 2) - ++global_ragent_cands; - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)lfoundation; (void)rfoundation; -} - -static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, - gchar *foundation, gpointer data) -{ - g_debug ("test-restart:%s: %p", G_STRFUNC, data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; (void)foundation; -} - -static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-restart:%s: %p", G_STRFUNC, data); - - if ((intptr_t)data == 1) - global_lagent_ibr_received = TRUE; - else if ((intptr_t)data == 2) - global_ragent_ibr_received = TRUE; - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; -} - -static void priv_get_local_addr (NiceAgent *agent, guint stream_id, guint component_id, NiceAddress *dstaddr) -{ - GSList *cands, *i; - cands = nice_agent_get_local_candidates(agent, stream_id, component_id); - for (i = cands; i; i = i->next) { - NiceCandidate *cand = i->data; - if (cand) { - g_assert (dstaddr); - *dstaddr = cand->addr; - } - } - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); -} - -static int run_restart_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr) -{ - NiceAddress laddr, raddr, laddr_rtcp, raddr_rtcp; - NiceCandidate cdes; - GSList *cands; - guint ls_id, rs_id; - guint64 tie_breaker; - - /* XXX: dear compiler, these are for you: */ - (void)baseaddr; - - memset (&cdes, 0, sizeof(NiceCandidate)); - cdes.priority = 10000; - strcpy (cdes.foundation, "1"); - cdes.type = NICE_CANDIDATE_TYPE_HOST; - cdes.transport = NICE_CANDIDATE_TRANSPORT_UDP; - - /* step: initialize variables modified by the callbacks */ - global_components_ready = 0; - global_components_ready_exit = 4; - global_components_failed = 0; - global_components_failed_exit = 4; - global_lagent_gathering_done = FALSE; - global_ragent_gathering_done = FALSE; - global_lagent_ibr_received = - global_ragent_ibr_received = FALSE; - global_lagent_cands = - global_ragent_cands = 0; - global_ragent_read_exit = -1; - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - /* step: add one stream, with RTP+RTCP components, to each agent */ - ls_id = nice_agent_add_stream (lagent, 2); - rs_id = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - - nice_agent_gather_candidates (lagent, ls_id); - nice_agent_gather_candidates (ragent, rs_id); - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)1); - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)1); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)2); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, (gpointer)2); - - /* step: run mainloop until local candidates are ready - * (see timer_cb() above) */ - if (global_lagent_gathering_done != TRUE || - global_ragent_gathering_done != TRUE) { - g_debug ("test-restart: Added streams, running mainloop until 'candidate-gathering-done'..."); - g_main_loop_run (global_mainloop); - g_assert (global_lagent_gathering_done == TRUE); - g_assert (global_ragent_gathering_done == TRUE); - } - - /* step: find out the local candidates of each agent */ - - priv_get_local_addr (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, &raddr); - g_debug ("test-restart: local RTP port R %u", - nice_address_get_port (&raddr)); - - priv_get_local_addr (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, &laddr); - g_debug ("test-restart: local RTP port L %u", - nice_address_get_port (&laddr)); - - priv_get_local_addr (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, &raddr_rtcp); - g_debug ("test-restart: local RTCP port R %u", - nice_address_get_port (&raddr_rtcp)); - - priv_get_local_addr (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, &laddr_rtcp); - g_debug ("test-restart: local RTCP port L %u", - nice_address_get_port (&laddr_rtcp)); - - /* step: pass the remote candidates to agents */ - cands = g_slist_append (NULL, &cdes); - { - gchar *ufrag = NULL, *password = NULL; - nice_agent_get_local_credentials(lagent, ls_id, &ufrag, &password); - nice_agent_set_remote_credentials (ragent, - rs_id, ufrag, password); - g_free (ufrag); - g_free (password); - nice_agent_get_local_credentials(ragent, rs_id, &ufrag, &password); - nice_agent_set_remote_credentials (lagent, - ls_id, ufrag, password); - g_free (ufrag); - g_free (password); - } - cdes.component_id = NICE_COMPONENT_TYPE_RTP; - cdes.addr = raddr; - nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, cands); - cdes.addr = laddr; - nice_agent_set_remote_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, cands); - cdes.component_id = NICE_COMPONENT_TYPE_RTCP; - cdes.addr = raddr_rtcp; - nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, cands); - cdes.addr = laddr_rtcp; - nice_agent_set_remote_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, cands); - /* This role switch request will be effective after restart. We test - * here that the role cannot be externally modified after conncheck - * has started. */ - g_object_set (G_OBJECT (ragent), "controlling-mode", TRUE, NULL); - g_assert (ragent->controlling_mode == FALSE); - - g_debug ("test-restart: Set properties, next running mainloop until connectivity checks succeed..."); - - /* step: run the mainloop until connectivity checks succeed - * (see timer_cb() above) */ - g_main_loop_run (global_mainloop); - - /* note: verify that STUN binding requests were sent */ - g_assert (global_lagent_ibr_received == TRUE); - g_assert (global_ragent_ibr_received == TRUE); - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (global_lagent_cands, ==, 2); - g_assert_cmpint (global_ragent_cands, ==, 2); - /* note: verify that agents are in correct state */ - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, ==, NICE_COMPONENT_STATE_READY); - - /* step: next send a packet (should work during restart) and - * then request an ICE restart by resetting the remote - * candidates for agent R */ - - g_debug ("-------------------------------------------\n" - "test-restart: Requesting a RESTART..."); - - /* step: send a new test packet from L ot R */ - global_ragent_read = 0; - g_assert_cmpint (nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"), ==, 16); - - /* Both agent have a distinct role at the end of the conncheck */ - g_assert (lagent->controlling_mode == TRUE); - g_assert (ragent->controlling_mode == FALSE); - /* step: restart agents, exchange updated credentials */ - tie_breaker = ragent->tie_breaker; - nice_agent_restart (ragent); - g_assert (tie_breaker != ragent->tie_breaker); - /* This role switch of ragent should be done now, and both agents - * have now the same role, which should generate a role conflict - * resolution situation */ - g_assert (lagent->controlling_mode == TRUE); - g_assert (ragent->controlling_mode == TRUE); - nice_agent_restart (lagent); - { - gchar *ufrag = NULL, *password = NULL; - nice_agent_get_local_credentials(lagent, ls_id, &ufrag, &password); - nice_agent_set_remote_credentials (ragent, - rs_id, ufrag, password); - g_free (ufrag); - g_free (password); - nice_agent_get_local_credentials(ragent, rs_id, &ufrag, &password); - nice_agent_set_remote_credentials (lagent, - ls_id, ufrag, password); - g_free (ufrag); - g_free (password); - } - - /* send another packet after restart */ - g_assert_cmpint (nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"), ==, 16); - - /* step: reset state variables */ - global_lagent_ibr_received = FALSE; - global_ragent_ibr_received = FALSE; - global_components_ready = 0; - - /* step: exchange remote candidates */ - cdes.component_id = NICE_COMPONENT_TYPE_RTP; - cdes.addr = raddr; - nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, cands); - cdes.addr = laddr; - nice_agent_set_remote_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, cands); - cdes.component_id = NICE_COMPONENT_TYPE_RTCP; - cdes.addr = raddr_rtcp; - nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP, cands); - cdes.addr = laddr_rtcp; - nice_agent_set_remote_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP, cands); - - g_main_loop_run (global_mainloop); - - /* note: verify that payload was succesfully received */ - g_assert_cmpint (global_ragent_read, ==, 32); - /* note: verify binding requests were resent after restart */ - g_assert (global_lagent_ibr_received == TRUE); - g_assert (global_ragent_ibr_received == TRUE); - /* note: verify that a role switch occured for one of the agents */ - g_assert (ragent->controlling_mode != lagent->controlling_mode); - - g_debug ("test-restart: Ran mainloop, removing streams..."); - - /* step: clean up resources and exit */ - - g_slist_free (cands); - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - return 0; -} - -int main (void) -{ - NiceAgent *lagent, *ragent; /* agent's L and R */ - NiceAddress baseaddr; - int result; - guint timer_id; - const char *stun_server = NULL, *stun_server_port = NULL; - -#ifdef G_OS_WIN32 - WSADATA w; - - WSAStartup(0x0202, &w); -#endif - - global_mainloop = g_main_loop_new (NULL, FALSE); - - /* Note: impl limits ... - * - no multi-stream support - * - no IPv6 support - */ - - - /* step: create the agents L and R */ - lagent = nice_agent_new (g_main_loop_get_context (global_mainloop), NICE_COMPATIBILITY_RFC5245); - ragent = nice_agent_new (g_main_loop_get_context (global_mainloop), NICE_COMPATIBILITY_RFC5245); - g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL); - - g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); - - /* step: add a timer to catch state changes triggered by signals */ - timer_id = g_timeout_add (30000, timer_cb, NULL); - - /* step: specify which local interface to use */ - if (!nice_address_set_from_string (&baseaddr, "127.0.0.1")) - g_assert_not_reached (); - nice_agent_add_local_address (lagent, &baseaddr); - nice_agent_add_local_address (ragent, &baseaddr); - - g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), (gpointer)1); - g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), (gpointer)2); - g_signal_connect (G_OBJECT (lagent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), (gpointer)1); - g_signal_connect (G_OBJECT (ragent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), (gpointer)2); - g_signal_connect (G_OBJECT (lagent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), (gpointer)1); - g_signal_connect (G_OBJECT (ragent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), (gpointer)2); - g_signal_connect (G_OBJECT (lagent), "new-candidate", - G_CALLBACK (cb_new_candidate), (gpointer)1); - g_signal_connect (G_OBJECT (ragent), "new-candidate", - G_CALLBACK (cb_new_candidate), (gpointer)2); - g_signal_connect (G_OBJECT (lagent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), (gpointer)1); - g_signal_connect (G_OBJECT (ragent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), (gpointer)2); - - stun_server = getenv ("NICE_STUN_SERVER"); - stun_server_port = getenv ("NICE_STUN_SERVER_PORT"); - if (stun_server) { - g_object_set (G_OBJECT (lagent), "stun-server", stun_server, NULL); - g_object_set (G_OBJECT (lagent), "stun-server-port", atoi (stun_server_port), NULL); - g_object_set (G_OBJECT (ragent), "stun-server", stun_server, NULL); - g_object_set (G_OBJECT (ragent), "stun-server-port", atoi (stun_server_port), NULL); - } - - /* step: run test the first time */ - g_debug ("test-restart: TEST STARTS / restart test"); - result = run_restart_test (lagent, ragent, &baseaddr); - priv_print_global_status (); - g_assert_cmpint (result, ==, 0); - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, ==, NICE_COMPONENT_STATE_READY); - - g_object_unref (lagent); - g_object_unref (ragent); - - - g_main_loop_unref (global_mainloop); - global_mainloop = NULL; - - g_source_remove (timer_id); -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return result; -} diff --git a/tests/test-send-recv.c b/tests/test-send-recv.c deleted file mode 100644 index f696a9c..0000000 --- a/tests/test-send-recv.c +++ /dev/null @@ -1,1346 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2014 Collabora Ltd. - * Contact: Philip Withnall - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Philip Withnall, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ - -/** - * This is a comprehensive unit test for send() and recv() behaviour in libnice, - * covering all APIs except the old nice_agent_attach_recv() one. It aims to - * test the correctness of reliable and non-reliable I/O through libnice, using - * a variety of data and a variety of buffer sizes. - * - * Abnormal features like error handling, zero-length buffer handling, stream - * closure and cancellation are not tested. - * - * This is *not* a performance test, and would require significant work to be - * useful as one. It allocates all of its buffers dynamically, and walks over - * them frequently to set and check data. - * - * Several of the strategies in the test make use of random numbers. The seed - * values for these are deterministically set (in main()), but may be specified - * on the command line to allow fuzzing. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" -#include "test-io-stream-common.h" - -#include -#include -#ifndef G_OS_WIN32 -#include -#endif - -/* Maximum IP payload ((1 << 16) - 1), minus IP header, minus UDP header. */ -#define MAX_MESSAGE_SIZE (65535 - 20 - 8) /* bytes */ - -typedef enum { - STREAM_AGENT, /* nice_agent_[send|recv]() */ - STREAM_AGENT_NONBLOCKING, /* nice_agent_[send|recv]_nonblocking() */ - STREAM_GIO, /* Nice[Input|Output]Stream */ - STREAM_GSOURCE, /* GPollable[Input|Output]Stream */ -} StreamApi; -#define STREAM_API_N_ELEMENTS (STREAM_GSOURCE + 1) - -typedef enum { - BUFFER_SIZE_CONSTANT_LARGE, /* always 65535 bytes */ - BUFFER_SIZE_CONSTANT_SMALL, /* always 4096 bytes */ - BUFFER_SIZE_CONSTANT_TINY, /* always 1 byte */ - BUFFER_SIZE_ASCENDING, /* ascending powers of 2 */ - BUFFER_SIZE_RANDOM, /* random every time */ -} BufferSizeStrategy; -#define BUFFER_SIZE_STRATEGY_N_ELEMENTS (BUFFER_SIZE_RANDOM + 1) - -typedef enum { - BUFFER_COUNT_CONSTANT_ONE, /* always a single buffer */ - BUFFER_COUNT_CONSTANT_TWO, /* always two buffers */ - BUFFER_COUNT_RANDOM, /* random every time */ -} BufferCountStrategy; -#define BUFFER_COUNT_STRATEGY_N_ELEMENTS (BUFFER_COUNT_RANDOM + 1) - -typedef enum { - MESSAGE_COUNT_CONSTANT_ONE, /* always a single message */ - MESSAGE_COUNT_CONSTANT_TWO, /* always two messages */ - MESSAGE_COUNT_RANDOM, /* random every time */ -} MessageCountStrategy; -#define MESSAGE_COUNT_STRATEGY_N_ELEMENTS (MESSAGE_COUNT_RANDOM + 1) - -typedef enum { - BUFFER_DATA_CONSTANT, /* fill with 0xfe */ - BUFFER_DATA_ASCENDING, /* ascending values for each byte */ - BUFFER_DATA_PSEUDO_RANDOM, /* every byte is pseudo-random */ -} BufferDataStrategy; -#define BUFFER_DATA_STRATEGY_N_ELEMENTS (BUFFER_DATA_PSEUDO_RANDOM + 1) - -typedef struct { - /* Test configuration (immutable per test run). */ - gboolean reliable; - StreamApi stream_api; - struct { - BufferSizeStrategy buffer_size_strategy; - BufferCountStrategy buffer_count_strategy; - MessageCountStrategy message_count_strategy; - } transmit; - struct { - BufferSizeStrategy buffer_size_strategy; - BufferCountStrategy buffer_count_strategy; - MessageCountStrategy message_count_strategy; - } receive; - BufferDataStrategy buffer_data_strategy; - gsize n_bytes; - guint n_messages; - - /* Test state. */ - GRand *transmit_size_rand; - GRand *receive_size_rand; - gsize transmitted_bytes; - gsize received_bytes; - gsize *other_received_bytes; - guint transmitted_messages; - guint received_messages; - guint *other_received_messages; -} TestData; - -/* Whether @stream_api is blocking (vs. non-blocking). */ -static gboolean -stream_api_is_blocking (StreamApi stream_api) -{ - switch (stream_api) { - case STREAM_AGENT: - case STREAM_GIO: - return TRUE; - case STREAM_AGENT_NONBLOCKING: - case STREAM_GSOURCE: - return FALSE; - default: - g_assert_not_reached (); - } -} - -/* Whether @stream_api only works for reliable NiceAgents. */ -static gboolean -stream_api_is_reliable_only (StreamApi stream_api) -{ - switch (stream_api) { - case STREAM_GSOURCE: - case STREAM_GIO: - return TRUE; - case STREAM_AGENT: - case STREAM_AGENT_NONBLOCKING: - return FALSE; - default: - g_assert_not_reached (); - } -} - -/* Whether @stream_api supports vectored I/O (multiple buffers or messages). */ -static gboolean -stream_api_supports_vectored_io (StreamApi stream_api) -{ - switch (stream_api) { - case STREAM_AGENT: - case STREAM_AGENT_NONBLOCKING: - return TRUE; - case STREAM_GSOURCE: - case STREAM_GIO: - return FALSE; - default: - g_assert_not_reached (); - } -} - -/* Generate a size for the buffer containing the @buffer_offset-th byte. - * Guaranteed to be in the interval [1, 1 << 16). ((1 << 16) is the maximum - * message size.) */ -static gsize -generate_buffer_size (BufferSizeStrategy strategy, GRand *grand, - gsize buffer_offset) -{ - switch (strategy) { - case BUFFER_SIZE_CONSTANT_LARGE: - return (1 << 16) - 1; - - case BUFFER_SIZE_CONSTANT_SMALL: - return 4096; - - case BUFFER_SIZE_CONSTANT_TINY: - return 1; - - case BUFFER_SIZE_ASCENDING: - return CLAMP (1L << buffer_offset, 1, (1 << 16) - 1); - - case BUFFER_SIZE_RANDOM: - return g_rand_int_range (grand, 1, 1 << 16); - - default: - g_assert_not_reached (); - } -} - -/* Generate a number of buffers to allocate when receiving the @buffer_offset-th - * byte. Guaranteed to be in the interval [1, 100], where 100 was chosen - * arbitrarily.*/ -static guint -generate_buffer_count (BufferCountStrategy strategy, GRand *grand, - gsize buffer_offset) -{ - switch (strategy) { - case BUFFER_COUNT_CONSTANT_ONE: - return 1; - - case BUFFER_COUNT_CONSTANT_TWO: - return 2; - - case BUFFER_COUNT_RANDOM: - return g_rand_int_range (grand, 1, 100 + 1); - - default: - g_assert_not_reached (); - } -} - -/* Generate a number of messages to allocate and receive into when receiving the - * @buffer_offset-th byte. Guaranteed to be in the interval [1, 100], where 100 - * was chosen arbitrarily.*/ -static guint -generate_message_count (MessageCountStrategy strategy, GRand *grand, - guint buffer_index) -{ - switch (strategy) { - case MESSAGE_COUNT_CONSTANT_ONE: - return 1; - - case MESSAGE_COUNT_CONSTANT_TWO: - return 2; - - case MESSAGE_COUNT_RANDOM: - return g_rand_int_range (grand, 1, 100 + 1); - - default: - g_assert_not_reached (); - } -} - -/* Fill the given @buf with @buf_len bytes of generated data. The data is - * deterministically generated, so that: - * generate_buffer_data(_, I, buf, 2) - * and - * generate_buffer_data(_, I+1, buf+1, 1) - * generate the same buf[I+1] byte, for all I. - * - * The generation strategies are generally chosen to produce data which makes - * send/receive errors (insertions, swaps, elisions) obvious. */ -static void -generate_buffer_data (BufferDataStrategy strategy, gsize buffer_offset, - guint8 *buf, gsize buf_len) -{ - switch (strategy) { - case BUFFER_DATA_CONSTANT: - memset (buf, 0xfe, buf_len); - break; - - case BUFFER_DATA_ASCENDING: { - gsize i; - - for (i = 0; i < buf_len; i++) { - buf[i] = (i + buffer_offset) & 0xff; - } - - break; - } - - case BUFFER_DATA_PSEUDO_RANDOM: { - gsize i; - - /* This can’t use GRand, because then the number of calls to g_rand_*() - * methods would affect its output, and the bytes generated here have to be - * entirely deterministic on @buffer_offset. - * - * Instead, use something akin to a LCG, except without any feedback - * (because that would make it non-deterministic). The objective is to - * generate numbers which are sufficiently pseudo-random that it’s likely - * transpositions, elisions and insertions will be detected. - * - * The constants come from ‘ANSI C’ in: - * http://en.wikipedia.org/wiki/Linear_congruential_generator - */ - for (i = 0; i < buf_len; i++) { - buf[i] = (1103515245 * (buffer_offset + i) + 12345) & 0xff; - } - - break; - } - - default: - g_assert_not_reached (); - } -} - -/* Choose a size and allocate a receive buffer in @buf, ready to receive bytes - * starting at @buffer_offset into the stream. Fill the buffer with poison - * values to hopefully make incorrect writes/reads more obvious. - * - * @buf must be freed with g_free(). */ -static void -generate_buffer_to_receive (TestIOStreamThreadData *data, gsize buffer_offset, - guint8 **buf, gsize *buf_len) -{ - TestData *test_data = data->user_data; - - /* Allocate the buffer. */ - *buf_len = generate_buffer_size (test_data->receive.buffer_size_strategy, - test_data->receive_size_rand, buffer_offset); - *buf = g_malloc (*buf_len); - - /* Fill it with poison to try and detect incorrect writes. */ - memset (*buf, 0xaa, *buf_len); -} - -/* Similar to generate_buffer_to_receive(), but generate an entire message array - * with multiple buffers instead. - * - * @max_buffer_size may be used to limit the total size of all the buffers in - * all the messages, for example to avoid blocking on receiving data which will - * never be sent. This only applies for blocking, reliable stream APIs. - * - * @max_n_messages may be used to limit the number of messages generated, to - * avoid blocking on receiving messages which will never be sent. This only - * applies for blocking, non-reliable stream APIs. - * - * @messages must be freed with g_free(), as must all of the buffer arrays and - * the buffers themselves. */ -static void -generate_messages_to_receive (TestIOStreamThreadData *data, gsize buffer_offset, - NiceInputMessage **messages, guint *n_messages, gsize max_buffer_size, - guint max_n_messages) -{ - TestData *test_data = data->user_data; - guint i; - - /* Allocate the messages. */ - *n_messages = - generate_message_count (test_data->receive.message_count_strategy, - test_data->receive_size_rand, buffer_offset); - - if (!data->reliable) - *n_messages = MIN (*n_messages, max_n_messages); - - *messages = g_malloc_n (*n_messages, sizeof (NiceInputMessage)); - - for (i = 0; i < *n_messages; i++) { - NiceInputMessage *message = &((*messages)[i]); - guint j; - - message->n_buffers = - generate_buffer_count (test_data->receive.buffer_count_strategy, - test_data->receive_size_rand, buffer_offset); - message->buffers = g_malloc_n (message->n_buffers, sizeof (GInputVector)); - message->from = NULL; - message->length = 0; - - for (j = 0; j < (guint) message->n_buffers; j++) { - GInputVector *buffer = &message->buffers[j]; - gsize buf_len; - - buf_len = - generate_buffer_size (test_data->receive.buffer_size_strategy, - test_data->receive_size_rand, buffer_offset); - - /* Trim the buffer length if it would otherwise cause the API to block. */ - if (data->reliable) { - buf_len = MIN (buf_len, max_buffer_size); - max_buffer_size -= buf_len; - } - - buffer->size = buf_len; - buffer->buffer = g_malloc (buffer->size); - - /* Fill it with poison to try and detect incorrect writes. */ - memset (buffer->buffer, 0xaa, buffer->size); - - /* If we’ve hit the max_buffer_size, adjust the buffer and message counts - * and run away. */ - if (data->reliable && max_buffer_size == 0) { - message->n_buffers = j + 1; - *n_messages = i + 1; - return; - } - } - } -} - -/* Validate the length and data of a received buffer of length @buf_len, filled - * with @len valid bytes. Updates the internal state machine to mark the bytes - * as received. This consumes @buf. */ -static void -validate_received_buffer (TestIOStreamThreadData *data, gsize buffer_offset, - guint8 **buf, gsize buf_len, gssize len) -{ - TestData *test_data = data->user_data; - guint8 *expected_buf; - - g_assert_cmpint (len, <=, buf_len); - g_assert_cmpint (len, >=, 0); - - if (stream_api_is_blocking (test_data->stream_api) && data->reliable) - g_assert_cmpint (len, ==, buf_len); - - /* Validate the buffer contents. - * - * Note: Buffers can only be validated up to valid_len. The buffer may - * have been re-used internally (e.g. by receiving a STUN message, then - * overwriting it with a data packet), so we can’t guarantee that the - * bytes beyond valid_len have been untouched. */ - expected_buf = g_malloc (buf_len); - memset (expected_buf, 0xaa, buf_len); - generate_buffer_data (test_data->buffer_data_strategy, buffer_offset, - expected_buf, len); - g_assert_cmpmem (*buf, len, expected_buf, len); - g_free (expected_buf); - - test_data->received_bytes += len; - - g_free (*buf); -} - -/* Similar to validate_received_buffer(), except it validates a message array - * instead of a single buffer. This consumes @messages. */ -static void -validate_received_messages (TestIOStreamThreadData *data, gsize buffer_offset, - NiceInputMessage *messages, guint n_messages, gint n_valid_messages) -{ - TestData *test_data = data->user_data; - guint i; - gsize prev_message_len = G_MAXSIZE; - - g_assert_cmpint (n_valid_messages, <=, n_messages); - g_assert_cmpint (n_valid_messages, >=, 0); - - if (stream_api_is_blocking (test_data->stream_api)) - g_assert_cmpint (n_valid_messages, ==, n_messages); - - test_data->received_messages += n_valid_messages; - - /* Validate the message contents. */ - for (i = 0; i < (guint) n_valid_messages; i++) { - NiceInputMessage *message = &messages[i]; - guint j; - gsize total_buf_len = 0; - gsize message_len_remaining = message->length; - - g_assert_cmpint (message->n_buffers, >, 0); - - for (j = 0; j < (guint) message->n_buffers; j++) { - GInputVector *buffer = &message->buffers[j]; - gsize valid_len; - - /* See note above about valid_len. */ - total_buf_len += buffer->size; - valid_len = MIN (message_len_remaining, buffer->size); - - /* Only validate buffer content for reliable mode, anything could - * be received in UDP mode - */ - if (test_data->reliable) { - guint8 *expected_buf; - - expected_buf = g_malloc (buffer->size); - memset (expected_buf, 0xaa, buffer->size); - generate_buffer_data (test_data->buffer_data_strategy, buffer_offset, - expected_buf, valid_len); - g_assert_cmpmem (buffer->buffer, valid_len, expected_buf, valid_len); - g_free (expected_buf); - buffer_offset += valid_len; - message_len_remaining -= valid_len; - } - test_data->received_bytes += valid_len; - } - - g_assert_cmpuint (message->length, <=, total_buf_len); - g_assert_cmpuint (message->length, >=, 0); - - /* No non-empty messages can follow an empty message. */ - if (prev_message_len == 0) - g_assert_cmpuint (message->length, ==, 0); - prev_message_len = message->length; - - /* If the API was blocking, it should have completely filled the message. */ - if (stream_api_is_blocking (test_data->stream_api) && data->reliable) - g_assert_cmpuint (message->length, ==, total_buf_len); - - g_assert (message->from == NULL); - } - - /* Free all messages. */ - for (i = 0; i < (guint) n_messages; i++) { - NiceInputMessage *message = &messages[i]; - guint j; - - for (j = 0; j < (guint) message->n_buffers; j++) { - GInputVector *buffer = &message->buffers[j]; - - g_free (buffer->buffer); - } - - g_free (message->buffers); - } - - g_free (messages); -} - -/* Determine a size for the next transmit buffer, allocate it, and fill it with - * data to be transmitted. */ -static void -generate_buffer_to_transmit (TestIOStreamThreadData *data, gsize buffer_offset, - guint8 **buf, gsize *buf_len) -{ - TestData *test_data = data->user_data; - - /* Allocate the buffer. */ - *buf_len = generate_buffer_size (test_data->transmit.buffer_size_strategy, - test_data->transmit_size_rand, buffer_offset); - *buf_len = MIN (*buf_len, test_data->n_bytes - test_data->transmitted_bytes); - *buf = g_malloc (*buf_len); - - /* Fill it with data. */ - generate_buffer_data (test_data->buffer_data_strategy, buffer_offset, - *buf, *buf_len); -} - -/* Similar to generate_buffer_to_transmit(), except that it generates an array - * of NiceOutputMessages rather than a single buffer. */ -static void -generate_messages_to_transmit (TestIOStreamThreadData *data, - gsize buffer_offset, NiceOutputMessage **messages, guint *n_messages) -{ - TestData *test_data = data->user_data; - guint i; - gsize total_buf_len = 0; - - /* Determine the number of messages to send. */ - *n_messages = - generate_message_count (test_data->transmit.message_count_strategy, - test_data->transmit_size_rand, buffer_offset); - *n_messages = - MIN (*n_messages, - test_data->n_messages - test_data->transmitted_messages); - - *messages = g_malloc_n (*n_messages, sizeof (NiceOutputMessage)); - - for (i = 0; i < *n_messages; i++) { - NiceOutputMessage *message = &((*messages)[i]); - guint j; - gsize max_message_size; - gsize message_len = 0; - - message->n_buffers = - generate_buffer_count (test_data->transmit.buffer_count_strategy, - test_data->transmit_size_rand, buffer_offset); - message->buffers = g_malloc_n (message->n_buffers, sizeof (GOutputVector)); - - /* Limit the overall message size to the smaller of (n_bytes / n_messages) - * and MAX_MESSAGE_SIZE, to ensure each message is non-empty. */ - max_message_size = - MIN ((test_data->n_bytes / test_data->n_messages), MAX_MESSAGE_SIZE); - - for (j = 0; j < (guint) message->n_buffers; j++) { - GOutputVector *buffer = &message->buffers[j]; - gsize buf_len; - guint8 *buf; - - buf_len = - generate_buffer_size (test_data->transmit.buffer_size_strategy, - test_data->transmit_size_rand, buffer_offset); - buf_len = - MIN (buf_len, - test_data->n_bytes - test_data->transmitted_bytes - total_buf_len); - buf_len = MIN (buf_len, max_message_size - message_len); - - buffer->size = buf_len; - buf = g_malloc (buffer->size); - buffer->buffer = buf; - message_len += buf_len; - total_buf_len += buf_len; - - /* Fill it with data. */ - generate_buffer_data (test_data->buffer_data_strategy, buffer_offset, - buf, buf_len); - - buffer_offset += buf_len; - - /* Reached the maximum UDP payload size? */ - if (message_len >= max_message_size) { - message->n_buffers = j + 1; - break; - } - } - - g_assert_cmpuint (message_len, <=, max_message_size); - } -} - -/* Validate the number of bytes transmitted, and update the test’s internal - * state machine. Consumes @buf. */ -static void -notify_transmitted_buffer (TestIOStreamThreadData *data, gsize buffer_offset, - guint8 **buf, gsize buf_len, gssize len) -{ - TestData *test_data = data->user_data; - - g_assert_cmpint (len, <=, buf_len); - g_assert_cmpint (len, >=, 0); - - test_data->transmitted_bytes += len; - - g_free (*buf); -} - -static gsize -output_message_get_size (const NiceOutputMessage *message) -{ - guint i; - gsize message_len = 0; - - /* Find the total size of the message */ - for (i = 0; - (message->n_buffers >= 0 && i < (guint) message->n_buffers) || - (message->n_buffers < 0 && message->buffers[i].buffer != NULL); - i++) - message_len += message->buffers[i].size; - - return message_len; -} - -/* Similar to notify_transmitted_buffer(), except it operates on an array of - * messages from generate_messages_to_transmit(). */ -static void -notify_transmitted_messages (TestIOStreamThreadData *data, gsize buffer_offset, - NiceOutputMessage **messages, guint n_messages, gint n_sent_messages) -{ - TestData *test_data = data->user_data; - guint i; - - g_assert_cmpint (n_sent_messages, <=, n_messages); - g_assert_cmpint (n_sent_messages, >=, 0); - - test_data->transmitted_messages += n_sent_messages; - - for (i = 0; i < n_messages; i++) { - NiceOutputMessage *message = &((*messages)[i]); - guint j; - - if (i < (guint) n_sent_messages) - test_data->transmitted_bytes += output_message_get_size (message); - - for (j = 0; j < (guint) message->n_buffers; j++) { - GOutputVector *buffer = &message->buffers[j]; - - g_free ((guint8 *) buffer->buffer); - } - - g_free (message->buffers); - } - - g_free (*messages); -} - -/* - * Implementation using nice_agent_recv_messages() and nice_agent_send(). - */ -static void -read_thread_agent_cb (GInputStream *input_stream, TestIOStreamThreadData *data) -{ - TestData *test_data = data->user_data; - guint stream_id, component_id; - gpointer tmp; - - tmp = g_object_get_data (G_OBJECT (data->agent), "stream-id"); - stream_id = GPOINTER_TO_UINT (tmp); - component_id = 1; - - while (test_data->received_bytes < test_data->n_bytes) { - GError *error = NULL; - NiceInputMessage *messages; - guint n_messages; - gint n_valid_messages; - - /* Initialise an array of messages to receive into. */ - generate_messages_to_receive (data, test_data->received_bytes, &messages, - &n_messages, test_data->n_bytes - test_data->received_bytes, - test_data->n_messages - test_data->received_messages); - - /* Block on receiving some data. */ - n_valid_messages = nice_agent_recv_messages (data->agent, stream_id, - component_id, messages, n_messages, NULL, &error); - g_assert_no_error (error); - - /* Check the messages and update the test’s state machine. */ - validate_received_messages (data, test_data->received_bytes, messages, - n_messages, n_valid_messages); - } - - check_for_termination (data, &test_data->received_bytes, - test_data->other_received_bytes, &test_data->transmitted_bytes, - test_data->n_bytes); -} - -static void -write_thread_agent_cb (GOutputStream *output_stream, - TestIOStreamThreadData *data) -{ - TestData *test_data = data->user_data; - guint stream_id, component_id; - gpointer tmp; - - tmp = g_object_get_data (G_OBJECT (data->agent), "stream-id"); - stream_id = GPOINTER_TO_UINT (tmp); - component_id = 1; - - while (test_data->transmitted_bytes < test_data->n_bytes) { - GError *error = NULL; - NiceOutputMessage *messages; - guint n_messages; - gint n_sent_messages; - - /* Generate a buffer to transmit. */ - generate_messages_to_transmit (data, test_data->transmitted_bytes, - &messages, &n_messages); - - /* Busy loop on receiving some data. */ - do { - g_clear_error (&error); - n_sent_messages = nice_agent_send_messages_nonblocking (data->agent, - stream_id, component_id, messages, n_messages, NULL, &error); - } while (n_sent_messages == -1 && - g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)); - g_assert_no_error (error); - - /* Update the test’s buffer generation state machine. */ - notify_transmitted_messages (data, test_data->transmitted_bytes, &messages, - n_messages, n_sent_messages); - } -} - -/* - * Implementation using nice_agent_recv_nonblocking() and - * nice_agent_send_nonblocking(). - */ -static void -read_thread_agent_nonblocking_cb (GInputStream *input_stream, - TestIOStreamThreadData *data) -{ - TestData *test_data = data->user_data; - guint stream_id, component_id; - gpointer tmp; - - tmp = g_object_get_data (G_OBJECT (data->agent), "stream-id"); - stream_id = GPOINTER_TO_UINT (tmp); - component_id = 1; - - while (test_data->received_bytes < test_data->n_bytes) { - GError *error = NULL; - NiceInputMessage *messages; - guint n_messages; - gint n_valid_messages; - - /* Initialise an array of messages to receive into. */ - generate_messages_to_receive (data, test_data->received_bytes, &messages, - &n_messages, test_data->n_bytes - test_data->received_bytes, - test_data->n_messages - test_data->received_messages); - - /* Trim n_messages to avoid consuming the ‘done’ message. */ - n_messages = - MIN (n_messages, test_data->n_messages - test_data->received_messages); - - /* Busy loop on receiving some data. */ - do { - g_clear_error (&error); - n_valid_messages = nice_agent_recv_messages_nonblocking (data->agent, - stream_id, component_id, messages, n_messages, NULL, &error); - } while (n_valid_messages == -1 && - g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)); - g_assert_no_error (error); - - /* Check the messages and update the test’s state machine. */ - validate_received_messages (data, test_data->received_bytes, messages, - n_messages, n_valid_messages); - } - - check_for_termination (data, &test_data->received_bytes, - test_data->other_received_bytes, &test_data->transmitted_bytes, - test_data->n_bytes); -} - -static void -wait_transmission_cb (NiceAgent *agent) -{ - guint stream_id; - gpointer tmp; - guint8 buffer[1024]; - GInputVector v = { &buffer, sizeof (buffer) }; - NiceInputMessage message = { &v, 1, NULL, 0}; - - tmp = g_object_get_data (G_OBJECT (agent), "stream-id"); - stream_id = GPOINTER_TO_UINT (tmp); - - /* While waiting for write thread to finish sending, keep also receiving so - * that any STUN messages from the peer still get processed. */ - nice_agent_recv_messages_nonblocking (agent, stream_id, 1, &message, 1, NULL, - NULL); -} - -static void -write_thread_agent_nonblocking_cb (GOutputStream *output_stream, - TestIOStreamThreadData *data) -{ - /* FIXME: There is no nice_agent_send_nonblocking(); nice_agent_send() is - * non-blocking by default. */ - write_thread_agent_cb (output_stream, data); -} - -/* - * Implementation using NiceInputStream and NiceOutputStream. - */ -static void -read_thread_gio_cb (GInputStream *input_stream, TestIOStreamThreadData *data) -{ - TestData *test_data = data->user_data; - - while (test_data->received_bytes < test_data->n_bytes) { - GError *error = NULL; - guint8 *buf = NULL; - gsize buf_len = 0; - gssize len; - - /* Initialise a receive buffer. */ - generate_buffer_to_receive (data, test_data->received_bytes, &buf, - &buf_len); - - /* Trim the receive buffer to avoid blocking on bytes which will never - * appear. */ - buf_len = MIN (buf_len, test_data->n_bytes - test_data->received_bytes); - - /* Block on receiving some data. */ - len = g_input_stream_read (input_stream, buf, buf_len, NULL, &error); - g_assert_no_error (error); - - /* Check the buffer and update the test’s state machine. */ - validate_received_buffer (data, test_data->received_bytes, &buf, buf_len, - len); - } - - check_for_termination (data, &test_data->received_bytes, - test_data->other_received_bytes, &test_data->transmitted_bytes, - test_data->n_bytes); -} - -static void -write_thread_gio_cb (GOutputStream *output_stream, TestIOStreamThreadData *data) -{ - TestData *test_data = data->user_data; - - while (test_data->transmitted_bytes < test_data->n_bytes) { - GError *error = NULL; - guint8 *buf = NULL; - gsize buf_len = 0; - gssize len; - gsize total_len = 0; - - /* Generate a buffer to transmit. */ - generate_buffer_to_transmit (data, test_data->transmitted_bytes, &buf, - &buf_len); - - /* Transmit it. */ - do { - len = g_output_stream_write (output_stream, buf + total_len, - buf_len - total_len, NULL, &error); - g_assert_no_error (error); - total_len += len; - } while (total_len < buf_len); - - /* Update the test’s buffer generation state machine. */ - notify_transmitted_buffer (data, test_data->transmitted_bytes, &buf, - buf_len, total_len); - } -} - -/* - * Implementation using GPollableInputStream and GPollableOutputStream. - * - * GSourceData is effectively the closure for the ‘for’ loop in other stream API - * implementations. - */ -typedef struct { - TestIOStreamThreadData *data; - GMainLoop *main_loop; -} GSourceData; - -static gboolean -read_stream_cb (GObject *pollable_stream, gpointer _user_data) -{ - GSourceData *gsource_data = _user_data; - TestIOStreamThreadData *data = gsource_data->data; - TestData *test_data = data->user_data; - GError *error = NULL; - guint8 *buf = NULL; - gsize buf_len = 0; - gssize len; - - /* Initialise a receive buffer. */ - generate_buffer_to_receive (data, test_data->received_bytes, &buf, &buf_len); - - /* Trim the receive buffer to avoid consuming the ‘done’ message. */ - buf_len = MIN (buf_len, test_data->n_bytes - test_data->received_bytes); - - /* Try to receive some data. */ - len = g_pollable_input_stream_read_nonblocking ( - G_POLLABLE_INPUT_STREAM (pollable_stream), buf, buf_len, NULL, &error); - - if (len == -1) { - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK); - g_error_free (error); - g_free (buf); - return G_SOURCE_CONTINUE; - } - - g_assert_no_error (error); - - /* Check the buffer and update the test’s state machine. */ - validate_received_buffer (data, test_data->received_bytes, &buf, buf_len, - len); - - /* Termination time? */ - if (test_data->received_bytes == test_data->n_bytes) { - g_main_loop_quit (gsource_data->main_loop); - return G_SOURCE_REMOVE; - } - - return G_SOURCE_CONTINUE; -} - -static void -read_thread_gsource_cb (GInputStream *input_stream, - TestIOStreamThreadData *data) -{ - TestData *test_data = data->user_data; - GSourceData gsource_data; - GMainContext *main_context; - GMainLoop *main_loop; - GSource *stream_source; - - main_context = g_main_context_ref_thread_default (); - main_loop = g_main_loop_new (main_context, FALSE); - - gsource_data.data = data; - gsource_data.main_loop = main_loop; - - stream_source = - g_pollable_input_stream_create_source ( - G_POLLABLE_INPUT_STREAM (input_stream), NULL); - - g_source_set_callback (stream_source, G_SOURCE_FUNC (read_stream_cb), - &gsource_data, NULL); - g_source_attach (stream_source, main_context); - - /* Run the main loop. */ - g_main_loop_run (main_loop); - - g_source_destroy (stream_source); - g_source_unref (stream_source); - g_main_loop_unref (main_loop); - g_main_context_unref (main_context); - - /* Termination? */ - check_for_termination (data, &test_data->received_bytes, - test_data->other_received_bytes, &test_data->transmitted_bytes, - test_data->n_bytes); -} - -static gboolean -write_stream_cb (GObject *pollable_stream, gpointer _user_data) -{ - GSourceData *gsource_data = _user_data; - TestIOStreamThreadData *data = gsource_data->data; - TestData *test_data = data->user_data; - GError *error = NULL; - guint8 *buf = NULL; - gsize buf_len = 0; - gssize len; - for (;;) { - - /* Initialise a receive buffer. */ - generate_buffer_to_transmit (data, test_data->transmitted_bytes, &buf, - &buf_len); - - /* Try to transmit some data. */ - len = g_pollable_output_stream_write_nonblocking ( - G_POLLABLE_OUTPUT_STREAM (pollable_stream), buf, buf_len, NULL, &error); - - if (len == -1) { - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK); - g_free (buf); - return G_SOURCE_CONTINUE; - } - - g_assert_no_error (error); - - /* Update the test’s buffer generation state machine. */ - notify_transmitted_buffer (data, test_data->transmitted_bytes, &buf, buf_len, - len); - - /* Termination time? */ - if (test_data->transmitted_bytes == test_data->n_bytes) { - g_main_loop_quit (gsource_data->main_loop); - break; - } - } - - return G_SOURCE_REMOVE; -} - -static void -write_thread_gsource_cb (GOutputStream *output_stream, - TestIOStreamThreadData *data) -{ - GSourceData gsource_data; - GMainContext *main_context; - GMainLoop *main_loop; - GSource *stream_source; - - main_context = g_main_context_ref_thread_default (); - main_loop = g_main_loop_new (main_context, FALSE); - - gsource_data.data = data; - gsource_data.main_loop = main_loop; - - stream_source = - g_pollable_output_stream_create_source ( - G_POLLABLE_OUTPUT_STREAM (output_stream), NULL); - - g_source_set_callback (stream_source, G_SOURCE_FUNC (write_stream_cb), - &gsource_data, NULL); - g_source_attach (stream_source, main_context); - - /* Run the main loop. */ - g_main_loop_run (main_loop); - - g_source_destroy (stream_source); - g_source_unref (stream_source); - g_main_loop_unref (main_loop); - g_main_context_unref (main_context); -} - -static void -test_data_init (TestData *data, gboolean reliable, StreamApi stream_api, - gsize n_bytes, guint n_messages, - BufferSizeStrategy transmit_buffer_size_strategy, - BufferCountStrategy transmit_buffer_count_strategy, - MessageCountStrategy transmit_message_count_strategy, - BufferSizeStrategy receive_buffer_size_strategy, - BufferCountStrategy receive_buffer_count_strategy, - MessageCountStrategy receive_message_count_strategy, - BufferDataStrategy buffer_data_strategy, guint32 transmit_seed, - guint32 receive_seed, gsize *other_received_bytes, - guint *other_received_messages) -{ - data->reliable = reliable; - data->stream_api = stream_api; - data->n_bytes = n_bytes; - data->n_messages = n_messages; - data->transmit.buffer_size_strategy = transmit_buffer_size_strategy; - data->transmit.buffer_count_strategy = transmit_buffer_count_strategy; - data->transmit.message_count_strategy = transmit_message_count_strategy; - data->receive.buffer_size_strategy = receive_buffer_size_strategy; - data->receive.buffer_count_strategy = receive_buffer_count_strategy; - data->receive.message_count_strategy = receive_message_count_strategy; - data->buffer_data_strategy = buffer_data_strategy; - data->transmit_size_rand = g_rand_new_with_seed (transmit_seed); - data->receive_size_rand = g_rand_new_with_seed (receive_seed); - data->transmitted_bytes = 0; - data->received_bytes = 0; - data->other_received_bytes = other_received_bytes; - data->transmitted_messages = 0; - data->received_messages = 0; - data->other_received_messages = other_received_messages; -} - -/* - * Test closures. - */ -static void -test_data_clear (TestData *data) -{ - g_rand_free (data->receive_size_rand); - g_rand_free (data->transmit_size_rand); -} - -static void -test (gboolean reliable, StreamApi stream_api, gsize n_bytes, guint n_messages, - BufferSizeStrategy transmit_buffer_size_strategy, - BufferCountStrategy transmit_buffer_count_strategy, - MessageCountStrategy transmit_message_count_strategy, - BufferSizeStrategy receive_buffer_size_strategy, - BufferCountStrategy receive_buffer_count_strategy, - MessageCountStrategy receive_message_count_strategy, - BufferDataStrategy buffer_data_strategy, - guint32 transmit_seed, guint32 receive_seed, - guint deadlock_timeout) -{ - TestData l_data, r_data; - - /* Indexed by StreamApi. */ - const TestIOStreamCallbacks callbacks[] = { - { read_thread_agent_cb, - write_thread_agent_cb, NULL, NULL, wait_transmission_cb }, /* STREAM_AGENT */ - { read_thread_agent_nonblocking_cb, write_thread_agent_nonblocking_cb, - NULL, NULL, wait_transmission_cb }, /* STREAM_AGENT_NONBLOCKING */ - { read_thread_gio_cb, write_thread_gio_cb, NULL, NULL, NULL}, /* STREAM_GIO */ - { read_thread_gsource_cb, write_thread_gsource_cb, - NULL, NULL, NULL }, /* STREAM_GSOURCE */ - }; - - test_data_init (&l_data, reliable, stream_api, n_bytes, n_messages, - transmit_buffer_size_strategy, transmit_buffer_count_strategy, - transmit_message_count_strategy, receive_buffer_size_strategy, - receive_buffer_count_strategy, receive_message_count_strategy, - buffer_data_strategy, transmit_seed, receive_seed, - &r_data.received_bytes, &r_data.received_messages); - test_data_init (&r_data, reliable, stream_api, n_bytes, n_messages, - transmit_buffer_size_strategy, transmit_buffer_count_strategy, - transmit_message_count_strategy, receive_buffer_size_strategy, - receive_buffer_count_strategy, receive_message_count_strategy, - buffer_data_strategy, transmit_seed, receive_seed, - &l_data.received_bytes, &l_data.received_messages); - - run_io_stream_test (deadlock_timeout, reliable, &callbacks[stream_api], - &l_data, NULL, &r_data, NULL); - - test_data_clear (&r_data); - test_data_clear (&l_data); -} - -/* Options with default values. */ -guint32 option_transmit_seed = 0; -guint32 option_receive_seed = 0; -gsize option_n_bytes = 10000; -guint option_n_messages = 50; -guint option_timeout = 150; /* seconds */ -gboolean option_long_mode = FALSE; - -static GOptionEntry entries[] = { - { "transmit-seed", 0, 0, G_OPTION_ARG_INT, &option_transmit_seed, - "Seed for transmission RNG", "S" }, - { "receive-seed", 0, 0, G_OPTION_ARG_INT, &option_receive_seed, - "Seed for reception RNG", "S" }, - { "n-bytes", 'n', 0, G_OPTION_ARG_INT64, &option_n_bytes, - "Number of bytes to send in each test (default 10000)", "N" }, - { "n-messages", 'm', 0, G_OPTION_ARG_INT64, &option_n_messages, - "Number of messages to send in each test (default 50)", "M" }, - { "timeout", 't', 0, G_OPTION_ARG_INT, &option_timeout, - "Deadlock detection timeout length, in seconds (default: 15)", "S" }, - { "long-mode", 'l', 0, G_OPTION_ARG_NONE, &option_long_mode, - "Enable all tests, rather than a fast subset", NULL }, - { NULL }, -}; - -int -main (int argc, char *argv[]) -{ - gboolean reliable; - StreamApi stream_api; - BufferSizeStrategy transmit_buffer_size_strategy; - BufferCountStrategy transmit_buffer_count_strategy; - MessageCountStrategy transmit_message_count_strategy; - BufferSizeStrategy receive_buffer_size_strategy; - BufferCountStrategy receive_buffer_count_strategy; - MessageCountStrategy receive_message_count_strategy; - BufferDataStrategy buffer_data_strategy; - guint32 transmit_seed; - guint32 receive_seed; - gsize n_bytes; - guint n_messages; - guint deadlock_timeout; - gboolean long_mode; - GOptionContext *context; - GError *error = NULL; - - /* Argument parsing. Allow some of the test parameters to be specified on the - * command line. */ - context = g_option_context_new ("— test send()/recv() correctness"); - g_option_context_add_main_entries (context, entries, NULL); - - if (!g_option_context_parse (context, &argc, &argv, &error)) { - g_printerr ("Option parsing failed: %s\n", error->message); - g_error_free (error); - g_option_context_free (context); - exit (1); - } - - /* Set up the defaults. */ - transmit_seed = option_transmit_seed; - receive_seed = option_receive_seed; - n_bytes = option_n_bytes; - n_messages = option_n_messages; - deadlock_timeout = option_timeout; - long_mode = option_long_mode; - -#ifdef G_OS_WIN32 - WSADATA w; - WSAStartup (0x0202, &w); -#endif - - if (!long_mode) { - /* Quick mode. Just test each of the stream APIs in reliable and - * non-reliable mode, with a single pair of buffer strategies, and a single - * data strategy. */ - - /* Reliability. */ - for (reliable = 0; reliable < 2; reliable++) { - /* Stream API. */ - for (stream_api = 0; - (guint) stream_api < STREAM_API_N_ELEMENTS; - stream_api++) { - /* GIO streams must always be reliable. */ - if (!reliable && stream_api_is_reliable_only (stream_api)) - continue; - - /* Non-reliable socket receives require large buffers. */ - if (reliable) { - receive_buffer_size_strategy = BUFFER_SIZE_RANDOM; - } else { - receive_buffer_size_strategy = BUFFER_SIZE_CONSTANT_LARGE; - } - - transmit_buffer_size_strategy = BUFFER_SIZE_RANDOM; - buffer_data_strategy = BUFFER_DATA_PSEUDO_RANDOM; - - if (stream_api_supports_vectored_io (stream_api)) { - transmit_buffer_count_strategy = BUFFER_COUNT_RANDOM; - transmit_message_count_strategy = MESSAGE_COUNT_RANDOM; - receive_buffer_count_strategy = BUFFER_COUNT_RANDOM; - receive_message_count_strategy = MESSAGE_COUNT_RANDOM; - } else { - transmit_buffer_count_strategy = BUFFER_COUNT_CONSTANT_ONE; - transmit_message_count_strategy = MESSAGE_COUNT_CONSTANT_ONE; - receive_buffer_count_strategy = BUFFER_COUNT_CONSTANT_ONE; - receive_message_count_strategy = MESSAGE_COUNT_CONSTANT_ONE; - } - - g_debug ("Running test (%u, %u, %" G_GSIZE_FORMAT ", %u, %u, " - "%u, %u, %u, %u)…", - reliable, stream_api, n_bytes, n_messages, - transmit_buffer_size_strategy, - receive_buffer_size_strategy, buffer_data_strategy, - transmit_seed, receive_seed); - test (reliable, stream_api, n_bytes, n_messages, - transmit_buffer_size_strategy, - transmit_buffer_count_strategy, transmit_message_count_strategy, - receive_buffer_size_strategy, receive_buffer_count_strategy, - receive_message_count_strategy, buffer_data_strategy, - transmit_seed, receive_seed, - deadlock_timeout); - } - } - - goto done; - } - -#define STRATEGY_LOOP(V, L) for (V = 0; (guint) V < L##_N_ELEMENTS; V++) - STRATEGY_LOOP(transmit_buffer_size_strategy, BUFFER_SIZE_STRATEGY) - STRATEGY_LOOP(transmit_buffer_count_strategy, BUFFER_COUNT_STRATEGY) - STRATEGY_LOOP(transmit_message_count_strategy, MESSAGE_COUNT_STRATEGY) - STRATEGY_LOOP(receive_buffer_size_strategy, BUFFER_SIZE_STRATEGY) - STRATEGY_LOOP(receive_buffer_count_strategy, BUFFER_COUNT_STRATEGY) - STRATEGY_LOOP(receive_message_count_strategy, MESSAGE_COUNT_STRATEGY) - STRATEGY_LOOP(buffer_data_strategy, BUFFER_DATA_STRATEGY) - /* Reliability. */ - for (reliable = 0; reliable < 2; reliable++) { - /* Stream API. */ - for (stream_api = 0; - (guint) stream_api < STREAM_API_N_ELEMENTS; - stream_api++) { - /* GIO streams must always be reliable. */ - if (!reliable && stream_api_is_reliable_only (stream_api)) - continue; - - /* Non-reliable socket receives require large buffers. We don’t claim to - * support using them with small (< 65536B) buffers, so don’t test - * them. */ - if (!reliable && - receive_buffer_size_strategy != BUFFER_SIZE_CONSTANT_LARGE) - continue; - - /* Non-reliable socket transmits will always block with huge buffers. */ - if (!reliable && - transmit_buffer_size_strategy == BUFFER_SIZE_CONSTANT_LARGE) - continue; - - /* Stream APIs which don’t support vectored I/O must not be passed - * I/O vectors. */ - if (!stream_api_supports_vectored_io (stream_api) && - (transmit_buffer_count_strategy != BUFFER_COUNT_CONSTANT_ONE || - transmit_message_count_strategy != MESSAGE_COUNT_CONSTANT_ONE || - receive_buffer_count_strategy != BUFFER_COUNT_CONSTANT_ONE || - receive_message_count_strategy != MESSAGE_COUNT_CONSTANT_ONE)) - continue; - - g_debug ("Running test (%u, %u, %" G_GSIZE_FORMAT ", %u, %u, " - "%u, %u, %u, %u, %u, %u, %u, %u)…", - reliable, stream_api, n_bytes, n_messages, - transmit_buffer_size_strategy, - transmit_buffer_count_strategy, transmit_message_count_strategy, - receive_buffer_size_strategy, receive_buffer_count_strategy, - receive_message_count_strategy, buffer_data_strategy, - transmit_seed, receive_seed); - test (reliable, stream_api, n_bytes, n_messages, - transmit_buffer_size_strategy, - transmit_buffer_count_strategy, transmit_message_count_strategy, - receive_buffer_size_strategy, receive_buffer_count_strategy, - receive_message_count_strategy, buffer_data_strategy, - transmit_seed, receive_seed, - deadlock_timeout); - } - } - -done: - g_option_context_free (context); - -#ifdef G_OS_WIN32 - WSACleanup (); -#endif - - return 0; -} diff --git a/tests/test-socket-is-based-on.c b/tests/test-socket-is-based-on.c deleted file mode 100644 index db48924..0000000 --- a/tests/test-socket-is-based-on.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2016 Jakub Adam - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include - -#include "socket.h" - -static NiceSocket *udp_bsd; -static NiceSocket *tcp_active; -static NiceSocket *pseudossl; -static NiceSocket *udp_turn_over_tcp; - -static void -socket_base_udp_bsd (void) -{ - g_assert (nice_socket_is_based_on (udp_bsd, udp_bsd)); - g_assert (!nice_socket_is_based_on (udp_bsd, tcp_active)); - g_assert (!nice_socket_is_based_on (udp_bsd, pseudossl)); - g_assert (!nice_socket_is_based_on (udp_bsd, udp_turn_over_tcp)); -} - -static void -socket_base_tcp_active (void) -{ - g_assert (!nice_socket_is_based_on (tcp_active, udp_bsd)); - g_assert (nice_socket_is_based_on (tcp_active, tcp_active)); - g_assert (!nice_socket_is_based_on (tcp_active, pseudossl)); - g_assert (!nice_socket_is_based_on (tcp_active, udp_turn_over_tcp)); -} - -static void -socket_base_pseudossl (void) -{ - g_assert (!nice_socket_is_based_on (pseudossl, udp_bsd)); - g_assert (nice_socket_is_based_on (pseudossl, tcp_active)); - g_assert (nice_socket_is_based_on (pseudossl, pseudossl)); - g_assert (!nice_socket_is_based_on (pseudossl, udp_turn_over_tcp)); -} - -static void -socket_base_udp_turn_over_tcp (void) -{ - g_assert (!nice_socket_is_based_on (udp_turn_over_tcp, udp_bsd)); - g_assert (nice_socket_is_based_on (udp_turn_over_tcp, tcp_active)); - g_assert (nice_socket_is_based_on (udp_turn_over_tcp, pseudossl)); - g_assert (nice_socket_is_based_on (udp_turn_over_tcp, udp_turn_over_tcp)); -} - -int -main (int argc, char *argv[]) -{ - GMainLoop *mainloop = NULL; - - NiceAddress addr; - - g_networking_init (); - - setlocale (LC_ALL, ""); - g_test_init (&argc, &argv, NULL); - - mainloop = g_main_loop_new (NULL, TRUE); - - nice_address_set_from_string (&addr, "127.0.0.1"); - - /* Standalone socket */ - udp_bsd = nice_udp_bsd_socket_new (&addr); - - /* tcp_passive -> pseudossl -> udp_turn_over_tcp */ - tcp_active = nice_tcp_active_socket_new (g_main_loop_get_context (mainloop), - &addr); - pseudossl = nice_pseudossl_socket_new (tcp_active, - NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE); - udp_turn_over_tcp = nice_udp_turn_over_tcp_socket_new (pseudossl, - NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE); - - g_test_add_func ("/socket/is-base-of/udp-bsd", - socket_base_udp_bsd); - g_test_add_func ("/socket/is-base-of/tcp-active", - socket_base_tcp_active); - g_test_add_func ("/socket/is-base-of/pseudossl", - socket_base_pseudossl); - g_test_add_func ("/socket/is-base-of/udp-turn-over-tcp", - socket_base_udp_turn_over_tcp); - - g_test_run (); - - nice_socket_free (udp_bsd); - nice_socket_free (udp_turn_over_tcp); - - g_main_loop_unref (mainloop); - - return 0; -} diff --git a/tests/test-tcp.c b/tests/test-tcp.c deleted file mode 100644 index 243203c..0000000 --- a/tests/test-tcp.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2012 Collabora Ltd. - * Contact: George Kiagiadakis - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * George Kiagiadakis, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include - -#include "socket.h" - -GMainLoop *mainloop = NULL; -NiceSocket *active_sock, *client; -NiceSocket *passive_sock, *server; -NiceAddress tmp; -gchar buf[5]; - -static gboolean -on_server_connection_available (gpointer user_data) -{ - server = nice_tcp_passive_socket_accept (passive_sock); - g_assert (server); - - g_main_loop_quit (mainloop); - - return FALSE; -} - -static gboolean -on_server_input_available (gpointer user_data) -{ - g_assert_cmpint (5, ==, nice_socket_recv (server, &tmp, 5, buf)); - g_assert (nice_address_equal (&tmp, &client->addr)); - - g_main_loop_quit (mainloop); - - return FALSE; -} - -static gboolean -on_client_input_available (gpointer user_data) -{ - g_assert_cmpint (5, ==, nice_socket_recv (client, &tmp, 5, buf)); - g_assert (nice_address_equal (&tmp, &server->addr)); - - g_main_loop_quit (mainloop); - - return FALSE; -} - -int -main (void) -{ - NiceAddress active_bind_addr, passive_bind_addr; - GSource *srv_listen_source, *srv_input_source, *cli_input_source; - - g_networking_init (); - - mainloop = g_main_loop_new (NULL, FALSE); - - nice_address_init (&active_bind_addr); - g_assert (nice_address_set_from_string (&active_bind_addr, "::1")); - - nice_address_init (&passive_bind_addr); - g_assert (nice_address_set_from_string (&passive_bind_addr, "127.0.0.1")); - nice_address_set_port (&passive_bind_addr, 0); - - nice_address_init (&tmp); - - passive_sock = nice_tcp_passive_socket_new (g_main_loop_get_context (mainloop), - &passive_bind_addr); - g_assert (passive_sock); - - srv_listen_source = g_socket_create_source (passive_sock->fileno, - G_IO_IN, NULL); - g_source_set_callback (srv_listen_source, - on_server_connection_available, NULL, NULL); - g_source_attach (srv_listen_source, g_main_loop_get_context (mainloop)); - - active_sock = nice_tcp_active_socket_new (g_main_loop_get_context (mainloop), - &active_bind_addr); - g_assert (active_sock); - - client = nice_tcp_active_socket_connect (active_sock, &passive_sock->addr); - g_assert (client); - nice_socket_free (active_sock); - active_sock = NULL; - - g_main_loop_run (mainloop); /* -> on_server_connection_available */ - g_assert (server); - - srv_input_source = g_socket_create_source (server->fileno, G_IO_IN, NULL); - g_source_set_callback (srv_input_source, - on_server_input_available, NULL, NULL); - g_source_attach (srv_input_source, g_main_loop_get_context (mainloop)); - - cli_input_source = g_socket_create_source (client->fileno, G_IO_IN, NULL); - g_source_set_callback (cli_input_source, - on_client_input_available, NULL, NULL); - g_source_attach (cli_input_source, g_main_loop_get_context (mainloop)); - - g_assert (nice_address_get_port (&client->addr) != 0); - - g_assert (nice_address_set_from_string (&tmp, "127.0.0.1")); - nice_address_set_port (&tmp, nice_address_get_port (&server->addr)); - g_assert (nice_address_get_port (&tmp) != 0); - - - g_assert_cmpint (5, ==, nice_socket_send (client, &tmp, 5, "hello")); - g_main_loop_run (mainloop); /* -> on_server_input_available */ - g_assert (0 == strncmp (buf, "hello", 5)); - - g_assert_cmpint (5, ==, nice_socket_send (server, &tmp, 5, "uryyb")); - g_main_loop_run (mainloop); /* -> on_client_input_available */ - g_assert (0 == strncmp (buf, "uryyb", 5)); - - nice_socket_free (client); - nice_socket_free (server); - nice_socket_free (passive_sock); - - g_source_unref (srv_listen_source); - g_source_unref (srv_input_source); - g_source_unref (cli_input_source); - g_main_loop_unref (mainloop); - - return 0; -} diff --git a/tests/test-thread.c b/tests/test-thread.c deleted file mode 100644 index fe5f0f1..0000000 --- a/tests/test-thread.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * Unit test for ICE full-mode related features. - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" - -#include -#include -#ifndef G_OS_WIN32 -#include -#endif - -volatile gint global_lagent_cands = 0; -volatile gint global_ragent_cands = 0; - -GMutex buffers_mutex; -GCond buffers_cond; -gint global_lagent_buffers = 0; -gint global_ragent_buffers = 0; - -/* Waits about 10 seconds for @var to be NULL/FALSE */ -#define WAIT_UNTIL_UNSET(var, context) \ - if (var) \ - { \ - int _i; \ - \ - for (_i = 0; _i < 13 && (var); _i++) \ - { \ - g_usleep (1000 * (1 << _i)); \ - g_main_context_iteration (context, FALSE); \ - } \ - \ - g_assert (!(var)); \ - } - -static gpointer -mainloop_thread (gpointer data) -{ - GMainLoop *loop = data; - - g_main_loop_run (loop); - - return NULL; -} - - -static void -cb_new_selected_pair(NiceAgent *agent, - guint stream_id, - guint component_id, - gchar *lfoundation, - gchar* rfoundation, - gpointer data) -{ - g_debug ("test-thread:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - g_atomic_int_inc (&global_lagent_cands); - else if (GPOINTER_TO_UINT (data) == 2) - g_atomic_int_inc (&global_ragent_cands); -} - - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - NiceAgent *other = g_object_get_data (G_OBJECT (agent), "other-agent"); - gchar *ufrag = NULL, *password = NULL; - GSList *cands, *i; - guint id, other_id; - gpointer tmp; - - g_debug ("test-thread:%s", G_STRFUNC); - - tmp = g_object_get_data (G_OBJECT (agent), "id"); - id = GPOINTER_TO_UINT (tmp); - tmp = g_object_get_data (G_OBJECT (other), "id"); - other_id = GPOINTER_TO_UINT (tmp); - - nice_agent_get_local_credentials(agent, id, &ufrag, &password); - nice_agent_set_remote_credentials (other, - other_id, ufrag, password); - g_free (ufrag); - g_free (password); - - cands = nice_agent_get_local_candidates(agent, id, 1); - g_assert (cands != NULL); - - nice_agent_set_remote_candidates (other, other_id, 1, cands); - - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); -} - - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - gchar data[10]; - gint *count = NULL; - - g_debug ("Agent %p Stream %d Component: %d Received %u bytes", agent, - stream_id, component_id, len); - - g_mutex_lock (&buffers_mutex); - if (GPOINTER_TO_UINT (user_data) == 1) - count = &global_lagent_buffers; - else if (GPOINTER_TO_UINT (user_data) == 2) - count = &global_ragent_buffers; - else - g_error ("Invalid agent ?"); - - if (*count == 10) - return; - - - memset (data, *count + '1', 10); - - g_assert_cmpmem (buf, len, data, 10); - g_assert_cmpuint (len, ==, 10); - - (*count)++; - - g_cond_signal (&buffers_cond); - g_mutex_unlock (&buffers_mutex); -} - - -static void cb_component_state_changed (NiceAgent *agent, - guint stream_id, - guint component_id, - guint state, - gpointer user_data) -{ - int i; - gchar data[10]; - - g_debug("Agent %p Stream %d Component %d state %s", agent, stream_id, - component_id, nice_component_state_to_string (state)); - - if (state != NICE_COMPONENT_STATE_READY) - return; - - for (i=0; i<10; i++) - { - memset (data, i+'1', 10); - - g_debug ("Agent %p Stream: %d Component: %d Sending 10 bytes", agent, stream_id, - component_id); - - nice_agent_send (agent, stream_id, component_id, 10, data); - } -} - - -int main (void) -{ - NiceAgent *lagent, *ragent; /* agent's L and R */ - NiceAddress baseaddr; - const char *stun_server = NULL, *stun_server_port = NULL; - GMainContext *lmainctx, *rmainctx; - GMainLoop *lmainloop, *rmainloop; - GThread *lthread, *rthread; - guint ls_id, rs_id; - GMainContext *ldmainctx, *rdmainctx; - GMainLoop *ldmainloop, *rdmainloop; - GThread *ldthread, *rdthread; - -#ifdef G_OS_WIN32 - WSADATA w; - WSAStartup(0x0202, &w); -#endif - - lmainctx = g_main_context_new (); - rmainctx = g_main_context_new (); - lmainloop = g_main_loop_new (lmainctx, FALSE); - rmainloop = g_main_loop_new (rmainctx, FALSE); - - ldmainctx = g_main_context_new (); - rdmainctx = g_main_context_new (); - ldmainloop = g_main_loop_new (ldmainctx, FALSE); - rdmainloop = g_main_loop_new (rdmainctx, FALSE); - - /* step: create the agents L and R */ - lagent = nice_agent_new (lmainctx, NICE_COMPATIBILITY_MSN); - ragent = nice_agent_new (rmainctx, NICE_COMPATIBILITY_MSN); - - g_object_set_data (G_OBJECT (lagent), "other-agent", ragent); - g_object_set_data (G_OBJECT (ragent), "other-agent", lagent); - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); - - /* step: specify which local interface to use */ - if (!nice_address_set_from_string (&baseaddr, "127.0.0.1")) - g_assert_not_reached (); - nice_agent_add_local_address (lagent, &baseaddr); - nice_agent_add_local_address (ragent, &baseaddr); - - g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(2)); - g_signal_connect (G_OBJECT (lagent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER(2)); - g_signal_connect (G_OBJECT (lagent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(2)); - - stun_server = getenv ("NICE_STUN_SERVER"); - stun_server_port = getenv ("NICE_STUN_SERVER_PORT"); - if (stun_server) { - g_object_set (G_OBJECT (lagent), "stun-server", stun_server, NULL); - g_object_set (G_OBJECT (lagent), "stun-server-port", atoi (stun_server_port), NULL); - g_object_set (G_OBJECT (ragent), "stun-server", stun_server, NULL); - g_object_set (G_OBJECT (ragent), "stun-server-port", atoi (stun_server_port), NULL); - } - - /* step: test setter/getter functions for properties */ - { - guint max_checks = 0; - gchar *string = NULL; - guint port = 0; - gboolean mode = FALSE; - g_object_get (G_OBJECT (lagent), "stun-server", &string, NULL); - g_assert (stun_server == NULL || strcmp (string, stun_server) == 0); - g_free (string); - g_object_get (G_OBJECT (lagent), "stun-server-port", &port, NULL); - g_assert (stun_server_port == NULL || port == (guint)atoi (stun_server_port)); - g_object_get (G_OBJECT (lagent), "controlling-mode", &mode, NULL); - g_assert (mode == TRUE); - g_object_set (G_OBJECT (lagent), "max-connectivity-checks", 300, NULL); - g_object_get (G_OBJECT (lagent), "max-connectivity-checks", &max_checks, NULL); - g_assert_cmpuint (max_checks, ==, 300); - } - - /* step: run test the first time */ - g_debug ("test-thread: TEST STARTS / running test for the 1st time"); - - lthread = g_thread_new ("lthread libnice", mainloop_thread, lmainloop); - rthread = g_thread_new ("rthread libnice", mainloop_thread, rmainloop); - - g_assert (lthread); - g_assert (rthread); - - ls_id = nice_agent_add_stream (lagent, 2); - rs_id = nice_agent_add_stream (ragent, 2); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - - g_object_set_data (G_OBJECT (lagent), "id", GUINT_TO_POINTER (ls_id)); - g_object_set_data (G_OBJECT (ragent), "id", GUINT_TO_POINTER (rs_id)); - - nice_agent_gather_candidates (lagent, ls_id); - nice_agent_gather_candidates (ragent, rs_id); - - nice_agent_attach_recv (lagent, ls_id, 1, ldmainctx, cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (ragent, rs_id, 1, rdmainctx, cb_nice_recv, - GUINT_TO_POINTER (2)); - - ldthread = g_thread_new ("ldthread libnice", mainloop_thread, ldmainloop); - rdthread = g_thread_new ("rdthread libnice", mainloop_thread, rdmainloop); - - g_assert (ldthread); - g_assert (rdthread); - - g_debug ("ragent_buffers: %d lagent_buffers: %d", global_lagent_buffers, - global_ragent_buffers); - g_mutex_lock (&buffers_mutex); - while (global_ragent_buffers < 10 || - global_lagent_buffers < 10) { - g_cond_wait (&buffers_cond, &buffers_mutex); - g_debug ("ragent_buffers: %d lagent_buffers: %d", global_lagent_buffers, - global_ragent_buffers); - } - g_mutex_unlock (&buffers_mutex); - - - while (!g_main_loop_is_running (ldmainloop)); - while (g_main_loop_is_running (ldmainloop)) - g_main_loop_quit (ldmainloop); - while (!g_main_loop_is_running (rdmainloop)); - while (g_main_loop_is_running (rdmainloop)) - g_main_loop_quit (rdmainloop); - while (!g_main_loop_is_running (lmainloop)); - while (g_main_loop_is_running (lmainloop)) - g_main_loop_quit (lmainloop); - while (!g_main_loop_is_running (rmainloop)); - while (g_main_loop_is_running (rmainloop)) - g_main_loop_quit (rmainloop); - - g_thread_join (ldthread); - g_thread_join (rdthread); - g_thread_join (lthread); - g_thread_join (rthread); - - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (g_atomic_int_get (&global_lagent_cands), ==, 1); - g_assert_cmpint (g_atomic_int_get (&global_ragent_cands), ==, 1); - - g_object_add_weak_pointer (G_OBJECT (lagent), (gpointer *) &lagent); - g_object_add_weak_pointer (G_OBJECT (ragent), (gpointer *) &ragent); - - g_object_unref (lagent); - g_object_unref (ragent); - - WAIT_UNTIL_UNSET (lagent, lmainctx); - WAIT_UNTIL_UNSET (ragent, rmainctx); - - g_main_loop_unref (lmainloop); - g_main_loop_unref (rmainloop); - g_main_loop_unref (ldmainloop); - g_main_loop_unref (rdmainloop); - -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return 0; -} diff --git a/tests/test-trickle.c b/tests/test-trickle.c deleted file mode 100644 index cb386ac..0000000 --- a/tests/test-trickle.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * Unit test for ICE in trickle mode (adding remote candidates while the - * machine is running). - * - * (C) 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Kai Vehmanen, Nokia - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "agent.h" - -#include -#include - - -static NiceComponentState global_lagent_state = NICE_COMPONENT_STATE_LAST; -static NiceComponentState global_ragent_state = NICE_COMPONENT_STATE_LAST; -static guint global_components_ready = 0; -static guint global_components_ready_exit = 0; -static guint global_components_failed = 0; -static guint global_components_failed_exit = 0; -static GMainLoop *global_mainloop = NULL; -static gboolean global_lagent_gathering_done = FALSE; -static gboolean global_ragent_gathering_done = FALSE; -static gboolean global_lagent_ibr_received = FALSE; -static gboolean global_ragent_ibr_received = FALSE; -static int global_lagent_cands = 0; -static int global_ragent_cands = 0; -static gint global_ragent_read = 0; - -static void priv_print_global_status (void) -{ - g_debug ("\tgathering_done=%d", global_lagent_gathering_done && global_ragent_gathering_done); - g_debug ("\tlstate=%d", global_lagent_state); - g_debug ("\trstate=%d", global_ragent_state); - g_debug ("\tL cands=%d R cands=%d", global_lagent_cands, global_ragent_cands); -} - -static gboolean timer_cb (gpointer pointer) -{ - g_debug ("test-trickle:%s: %p", G_STRFUNC, pointer); - - /* signal status via a global variable */ - - /* note: should not be reached, abort */ - g_error ("ERROR: test has got stuck, aborting..."); - - return FALSE; -} - -static gboolean quit_loop_cb (gpointer pointer) -{ - g_debug ("test-trickle:%s: %p", G_STRFUNC, pointer); - - g_main_loop_quit (global_mainloop); - return FALSE; -} - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - g_debug ("test-trickle:%s: %p", G_STRFUNC, user_data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)buf; - - /* - * Lets ignore stun packets that got through - */ - if (len < 8) - return; - if (strncmp ("12345678", buf, 8)) - return; - - if (GPOINTER_TO_UINT (user_data) == 2) { - global_ragent_read = len; - g_main_loop_quit (global_mainloop); - } -} - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-trickle:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - global_lagent_gathering_done = TRUE; - else if (GPOINTER_TO_UINT (data) == 2) - global_ragent_gathering_done = TRUE; - - if (global_lagent_gathering_done && - global_ragent_gathering_done) - g_main_loop_quit (global_mainloop); - - /* XXX: dear compiler, these are for you: */ - (void)agent; -} - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - gboolean ready_to_connected = FALSE; - g_debug ("test-trickle:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) { - if (global_lagent_state == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_lagent_state = state; - } else if (GPOINTER_TO_UINT (data) == 2) { - if (global_ragent_state == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_ragent_state = state; - } - - if (state == NICE_COMPONENT_STATE_READY) - global_components_ready++; - else if (state == NICE_COMPONENT_STATE_CONNECTED && ready_to_connected) - global_components_ready--; - if (state == NICE_COMPONENT_STATE_FAILED) - global_components_failed++; - - g_debug ("test-trickle: checks READY/EXIT-AT %u/%u.", global_components_ready, global_components_ready_exit); - g_debug ("test-trickle: checks FAILED/EXIT-AT %u/%u.", global_components_failed, global_components_failed_exit); - - /* signal status via a global variable */ - if (global_components_ready == global_components_ready_exit && - global_components_failed == global_components_failed_exit) { - g_main_loop_quit (global_mainloop); - return; - } - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; -} - -static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id, - gchar *lfoundation, gchar* rfoundation, gpointer data) -{ - g_debug ("test-trickle:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - ++global_lagent_cands; - else if (GPOINTER_TO_UINT (data) == 2) - ++global_ragent_cands; - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)lfoundation; (void)rfoundation; -} - -static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, - gchar *foundation, gpointer data) -{ - g_debug ("test-trickle:%s: %p", G_STRFUNC, data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; (void)component_id; (void)foundation; -} - -static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-trickle:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - global_lagent_ibr_received = TRUE; - else if (GPOINTER_TO_UINT (data) == 2) - global_ragent_ibr_received = TRUE; - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)data; -} - - -int main (void) -{ - NiceAgent *lagent, *ragent; /* agent's L and R */ - NiceAddress baseaddr; - guint timer_id; - GSList *cands, *i; - guint ls_id, rs_id; - -#ifdef G_OS_WIN32 - WSADATA w; - - WSAStartup(0x0202, &w); -#endif - - global_mainloop = g_main_loop_new (NULL, FALSE); - - /* step: create the agents L and R */ - lagent = nice_agent_new (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY_GOOGLE); - ragent = nice_agent_new (g_main_loop_get_context (global_mainloop), - NICE_COMPATIBILITY_GOOGLE); - - if (!nice_address_set_from_string (&baseaddr, "127.0.0.1")) - g_assert_not_reached (); - nice_agent_add_local_address (lagent, &baseaddr); - nice_agent_add_local_address (ragent, &baseaddr); - - /* step: add a timer to catch state changes triggered by signals */ - timer_id = g_timeout_add (30000, timer_cb, NULL); - - g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "new-candidate", - G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "new-candidate", - G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), - GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "initial-binding-request-received", - G_CALLBACK (cb_initial_binding_request_received), - GUINT_TO_POINTER (2)); - - /* step: run test */ - g_debug ("test-trickle: running test"); - - /* step: initialize variables modified by the callbacks */ - global_components_ready = 0; - global_components_ready_exit = 2; - global_components_failed = 0; - global_components_failed_exit = 0; - global_lagent_gathering_done = FALSE; - global_ragent_gathering_done = FALSE; - global_lagent_ibr_received = - global_ragent_ibr_received = FALSE; - global_lagent_cands = - global_ragent_cands = 0; - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - g_object_set (G_OBJECT (lagent), "ice-trickle", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "ice-trickle", TRUE, NULL); - - /* An application using more than one NiceAgent instance may crash due to - * a race in gUPnP. - * - * UPnP can be re-enabled here and in other libnice tests once gUPnP - * 1.1.2 / 1.0.4 is released. - * - * See https://gitlab.gnome.org/GNOME/gupnp/commit/0123e574595e0a547ce26422633df72d63d3d0e0 - */ - g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); - - /* step: add one stream, with RTP+RTCP components, to each agent */ - ls_id = nice_agent_add_stream (lagent, 1); - - rs_id = nice_agent_add_stream (ragent, 1); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - - - nice_agent_gather_candidates (lagent, ls_id); - nice_agent_gather_candidates (ragent, rs_id); - - /* step: attach to mainloop (needed to register the fds) */ - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (1)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (global_mainloop), cb_nice_recv, - GUINT_TO_POINTER (2)); - - /* step: run mainloop until local candidates are ready - * (see timer_cb() above) */ - if (global_lagent_gathering_done != TRUE || - global_ragent_gathering_done != TRUE) { - g_debug ("test-trickle: Added streams, running mainloop until 'candidate-gathering-done'..."); - g_main_loop_run (global_mainloop); - g_assert (global_lagent_gathering_done == TRUE); - g_assert (global_ragent_gathering_done == TRUE); - } - - { - gchar *ufrag = NULL, *password = NULL; - nice_agent_get_local_credentials(lagent, ls_id, &ufrag, &password); - nice_agent_set_remote_credentials (ragent, - rs_id, ufrag, password); - g_free (ufrag); - g_free (password); - nice_agent_get_local_credentials(ragent, rs_id, &ufrag, &password); - nice_agent_set_remote_credentials (lagent, - ls_id, ufrag, password); - g_free (ufrag); - g_free (password); - } - cands = nice_agent_get_local_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTP); - nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, cands); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - cands = nice_agent_get_local_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTP); - nice_agent_set_remote_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, cands); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - nice_agent_peer_candidate_gathering_done (lagent, ls_id); - nice_agent_peer_candidate_gathering_done (ragent, rs_id); - - g_debug ("test-trickle: Set properties, next running mainloop until connectivity checks succeed..."); - - /* step: run the mainloop until connectivity checks succeed - * (see timer_cb() above) */ - g_main_loop_run (global_mainloop); - - /* note: verify that STUN binding requests were sent */ - g_assert (global_lagent_ibr_received == TRUE); - g_assert_cmpint (global_ragent_ibr_received, ==, TRUE); - - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, ==, NICE_COMPONENT_STATE_READY); - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (global_lagent_cands, ==, 1); - g_assert_cmpint (global_ragent_cands, ==, 1); - - g_debug ("test-trickle: agents are ready.. now adding new buggy candidate"); - - g_timeout_add (500, quit_loop_cb, NULL); - g_main_loop_run (global_mainloop); - - //global_components_ready--; - - cands = nice_agent_get_local_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTP); - nice_address_set_port(&((NiceCandidate *) cands->data)->addr, 80); - nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, cands); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_CONNECTED); - g_main_loop_run (global_mainloop); - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - - /* - g_debug ("test-trickle: buggy candidate worked, testing lower priority cand"); - - cands = nice_agent_get_local_candidates (ragent, rs_id, NICE_COMPONENT_TYPE_RTP); - nice_address_set_port(&((NiceCandidate *) cands->data)->addr, 80); - ((NiceCandidate *) cands->data)->priority -= 100; - nice_agent_set_remote_candidates (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, cands); - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); - - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY);*/ - - /* note: test payload send and receive */ - global_ragent_read = 0; - g_assert_cmpint (nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678"), ==, 16); - g_main_loop_run (global_mainloop); - g_assert_cmpint (global_ragent_read, ==, 16); - - g_debug ("test-trickle: Ran mainloop, removing streams..."); - - /* step: clean up resources and exit */ - - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - priv_print_global_status (); - g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state, >=, NICE_COMPONENT_STATE_CONNECTED); - /* note: verify that correct number of local candidates were reported */ - g_assert_cmpint (global_lagent_cands, ==, 1); - g_assert_cmpint (global_ragent_cands, ==, 1); - - - g_object_unref (lagent); - g_object_unref (ragent); - - g_main_loop_unref (global_mainloop); - global_mainloop = NULL; - - g_source_remove (timer_id); - -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return 0; -} diff --git a/tests/test-turn.c b/tests/test-turn.c deleted file mode 100644 index e373790..0000000 --- a/tests/test-turn.c +++ /dev/null @@ -1,400 +0,0 @@ -#include -#include -#include - -#include -#include - -static NiceComponentState global_lagent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST }; -static NiceComponentState global_ragent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST }; -static guint global_components_ready = 0; -static gboolean global_lagent_gathering_done = FALSE; -static gboolean global_ragent_gathering_done = FALSE; -static int global_lagent_cands = 0; -static int global_ragent_cands = 0; - -#define TURN_USER "toto" -#define TURN_PASS "password" - -static gboolean timer_cb (gpointer pointer) -{ - g_debug ("test-turn:%s: %p", G_STRFUNC, pointer); - - /* signal status via a global variable */ - - /* note: should not be reached, abort */ - g_error ("ERROR: test has got stuck, aborting..."); - - return FALSE; -} - -static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) -{ - g_debug ("test-fullmode:%s: %p", G_STRFUNC, user_data); - - /* XXX: dear compiler, these are for you: */ - (void)agent; (void)stream_id; (void)component_id; (void)buf; - - /* - * Lets ignore stun packets that got through - */ - if (len < 8) - return; - if (strncmp ("12345678", buf, 8)) - return; - - if (component_id != 1) - return; - -#if 0 - if (GPOINTER_TO_UINT (user_data) == 2) { - global_ragent_read += len; - } -#endif -} - -static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) -{ - g_debug ("test-fullmode:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - global_lagent_gathering_done = TRUE; - else if (GPOINTER_TO_UINT (data) == 2) - global_ragent_gathering_done = TRUE; -} - - -static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data) -{ - gboolean ready_to_connected = FALSE; - g_debug ("test-fullmode:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) { - if (global_lagent_state[component_id - 1] == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_lagent_state[component_id - 1] = state; - } else if (GPOINTER_TO_UINT (data) == 2) { - if (global_ragent_state[component_id - 1] == NICE_COMPONENT_STATE_READY && - state == NICE_COMPONENT_STATE_CONNECTED) - ready_to_connected = TRUE; - global_ragent_state[component_id - 1] = state; - } - - if (state == NICE_COMPONENT_STATE_READY) - global_components_ready++; - else if (state == NICE_COMPONENT_STATE_CONNECTED && ready_to_connected) - global_components_ready--; - g_assert (state != NICE_COMPONENT_STATE_FAILED); - - g_debug ("test-turn: checks READY %u.", global_components_ready); -} - -static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, - guint component_id, gchar *lfoundation, gchar* rfoundation, gpointer data) -{ - g_debug ("test-turn:%s: %p", G_STRFUNC, data); - - if (GPOINTER_TO_UINT (data) == 1) - ++global_lagent_cands; - else if (GPOINTER_TO_UINT (data) == 2) - ++global_ragent_cands; -} - -static void cb_closed (GObject *src, GAsyncResult *res, gpointer data) -{ - NiceAgent *agent = NICE_AGENT (src); - g_debug ("test-turn:%s: %p", G_STRFUNC, agent); - - *((gboolean *)data) = TRUE; -} - -static void set_candidates (NiceAgent *from, guint from_stream, - NiceAgent *to, guint to_stream, guint component, gboolean remove_non_relay, - gboolean force_relay) -{ - GSList *cands = NULL, *i; - - cands = nice_agent_get_local_candidates (from, from_stream, component); - if (remove_non_relay) { - restart: - for (i = cands; i; i = i->next) { - NiceCandidate *cand = i->data; - if (force_relay) - g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_RELAYED); - if (cand->type != NICE_CANDIDATE_TYPE_RELAYED) { - cands = g_slist_remove (cands, cand); - nice_candidate_free (cand); - goto restart; - } - } - } - nice_agent_set_remote_candidates (to, to_stream, component, cands); - - for (i = cands; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (cands); -} - -static void set_credentials (NiceAgent *lagent, guint lstream, - NiceAgent *ragent, guint rstream) -{ - gchar *ufrag = NULL, *password = NULL; - - nice_agent_get_local_credentials(lagent, lstream, &ufrag, &password); - nice_agent_set_remote_credentials (ragent, rstream, ufrag, password); - g_free (ufrag); - g_free (password); - nice_agent_get_local_credentials(ragent, rstream, &ufrag, &password); - nice_agent_set_remote_credentials (lagent, lstream, ufrag, password); - g_free (ufrag); - g_free (password); -} - -static void -run_test(guint turn_port, gboolean is_ipv6, - gboolean ice_udp, gboolean ice_tcp, gboolean force_relay, - gboolean remove_non_relay, - NiceRelayType turn_type) -{ - NiceAgent *lagent, *ragent; /* agent's L and R */ - const gchar *localhost; - NiceAddress localaddr; - guint ls_id, rs_id; - gulong timer_id; - gboolean lagent_closed = FALSE; - gboolean ragent_closed = FALSE; - - if (is_ipv6) - localhost = "::1"; - else - localhost = "127.0.0.1"; - - /* step: initialize variables modified by the callbacks */ - global_components_ready = 0; - global_lagent_gathering_done = FALSE; - global_ragent_gathering_done = FALSE; - global_lagent_cands = global_ragent_cands = 0; - - lagent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); - ragent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); - - g_object_set (G_OBJECT (lagent), "ice-tcp", ice_tcp, "ice-udp", ice_udp, - "force-relay", force_relay, NULL); - g_object_set (G_OBJECT (ragent), "ice-tcp", ice_tcp, "ice-udp", ice_udp, - "force-relay", force_relay, NULL); - - g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); - g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); - nice_agent_set_software (lagent, "Test-turn, Left Agent"); - nice_agent_set_software (ragent, "Test-turn, Right Agent"); - - timer_id = g_timeout_add (30000, timer_cb, NULL); - - - if (!nice_address_set_from_string (&localaddr, localhost)) - g_assert_not_reached (); - nice_agent_add_local_address (lagent, &localaddr); - nice_agent_add_local_address (ragent, &localaddr); - - g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", - G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1)); - g_signal_connect (G_OBJECT (ragent), "component-state-changed", - G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2)); - g_signal_connect (G_OBJECT (lagent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1)); - g_signal_connect (G_OBJECT (ragent), "new-selected-pair", - G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2)); - - g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); - g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); - - ls_id = nice_agent_add_stream (lagent, 1); - rs_id = nice_agent_add_stream (ragent, 1); - g_assert_cmpuint (ls_id, >, 0); - g_assert_cmpuint (rs_id, >, 0); - nice_agent_set_relay_info(lagent, ls_id, 1, - localhost, turn_port, TURN_USER, TURN_PASS, turn_type); - nice_agent_set_relay_info(ragent, rs_id, 1, - localhost, turn_port, TURN_USER, TURN_PASS, turn_type); - - g_assert (global_lagent_gathering_done == FALSE); - g_assert (global_ragent_gathering_done == FALSE); - g_debug ("test-turn: Added streams, running context until 'candidate-gathering-done'..."); - - /* Gather candidates and test nice_agent_set_port_range */ - g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE); - g_assert (nice_agent_gather_candidates (ragent, rs_id) == TRUE); - - nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - g_main_context_default (), cb_nice_recv, GUINT_TO_POINTER (1)); - nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - g_main_context_default (), cb_nice_recv, GUINT_TO_POINTER (2)); - - while (!global_lagent_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_assert (global_lagent_gathering_done == TRUE); - while (!global_ragent_gathering_done) - g_main_context_iteration (NULL, TRUE); - g_assert (global_ragent_gathering_done == TRUE); - - set_credentials (lagent, ls_id, ragent, rs_id); - - set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP, - remove_non_relay, force_relay); - set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP, - remove_non_relay, force_relay); - - while (global_lagent_state[0] != NICE_COMPONENT_STATE_READY || - global_ragent_state[0] != NICE_COMPONENT_STATE_READY) - g_main_context_iteration (NULL, TRUE); - g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY); - g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY); - - nice_agent_remove_stream (lagent, ls_id); - nice_agent_remove_stream (ragent, rs_id); - - nice_agent_close_async (lagent, cb_closed, &lagent_closed); - nice_agent_close_async (ragent, cb_closed, &ragent_closed); - - g_clear_object(&lagent); - g_clear_object(&ragent); - - while (!lagent_closed || !ragent_closed) { - g_main_context_iteration (NULL, TRUE); - } - - g_source_remove (timer_id); - -} - -guint global_turn_port; - -static void -udp_no_force_no_remove_udp (void) -{ - run_test(global_turn_port, FALSE /* is_ipv6 */, - TRUE /* ice_udp */, - FALSE /* ice_tcp */, - FALSE /* force_relay */, - FALSE /* remove_non_relay */, - NICE_RELAY_TYPE_TURN_UDP); -} - -static void -udp_no_force_remove_udp (void) -{ - run_test(global_turn_port, FALSE /* is_ipv6 */, - TRUE /* ice_udp */, - FALSE /* ice_tcp */, - FALSE /* force_relay */, - TRUE /* remove_non_relay */, - NICE_RELAY_TYPE_TURN_UDP); -} - -static void -udp_force_no_remove_udp (void) -{ - run_test(global_turn_port, FALSE /* is_ipv6 */, - TRUE /* ice_udp */, - FALSE /* ice_tcp */, - TRUE /* force_relay */, - FALSE /* remove_non_relay */, - NICE_RELAY_TYPE_TURN_UDP); -} - -static void -udp_no_force_no_remove_tcp (void) -{ - run_test(global_turn_port, FALSE /* is_ipv6 */, - TRUE /* ice_udp */, - FALSE /* ice_tcp */, - FALSE /* force_relay */, - FALSE /* remove_non_relay */, - NICE_RELAY_TYPE_TURN_TCP); -} - -static void -udp_no_force_remove_tcp (void) -{ - run_test(global_turn_port, FALSE /* is_ipv6 */, - TRUE /* ice_udp */, - FALSE /* ice_tcp */, - FALSE /* force_relay */, - TRUE /* remove_non_relay */, - NICE_RELAY_TYPE_TURN_TCP); -} - -static void -udp_force_no_remove_tcp (void) -{ - run_test(global_turn_port, FALSE /* is_ipv6 */, - TRUE /* ice_udp */, - FALSE /* ice_tcp */, - TRUE /* force_relay */, - FALSE /* remove_non_relay */, - NICE_RELAY_TYPE_TURN_TCP); -} - - - - - -int -main (int argc, char **argv) -{ - GSubprocess *sp; - GError *error = NULL; - gchar portstr[10]; - int ret; - gchar *out_str = NULL; - gchar *err_str = NULL; - - g_test_init (&argc, &argv, NULL); - - global_turn_port = g_random_int_range (10000, 60000); - snprintf(portstr, 9, "%u", global_turn_port); - - if (g_spawn_command_line_sync ("turnserver --help", &out_str, &err_str, NULL, - NULL) && err_str) { - if (!strstr(err_str, "--user")) { - g_print ("rfc5766-turn-server not installed, skipping turn test\n"); - return 0; - } - } else { - g_print ("rfc5766-turn-server not installed, skipping turn test\n"); - return 0; - } - g_free (err_str); - g_free (out_str); - - sp = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE, &error, - "turnserver", - "--user", "toto:0xaae440b3348d50265b63703117c7bfd5", - "--realm", "realm", - "--listening-port", portstr, - NULL); - - g_test_add_func ("/nice/turn/udp", udp_no_force_no_remove_udp); - g_test_add_func ("/nice/turn/udp/remove_non_turn", - udp_no_force_remove_udp); - g_test_add_func ("/nice/turn/udp/force_relay", - udp_force_no_remove_udp); - g_test_add_func ("/nice/turn/udp/over-tcp", udp_no_force_no_remove_tcp); - g_test_add_func ("/nice/turn/udp/over-tcp/remove_non_turn", - udp_no_force_remove_tcp); - g_test_add_func ("/nice/turn/udp/over-tcp/force_relay", - udp_force_no_remove_tcp); - - ret = g_test_run (); - - g_subprocess_force_exit (sp); - g_subprocess_wait (sp, NULL, NULL); - g_clear_object (&sp); - - return ret; -} diff --git a/tests/test-udp-turn-fragmentation.c b/tests/test-udp-turn-fragmentation.c deleted file mode 100644 index 99337a2..0000000 --- a/tests/test-udp-turn-fragmentation.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2018 Jakub Adam - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "agent-priv.h" -#include "socket.h" - -static GRand *randg; - -static GSList * -generate_test_messages(void) -{ - guint i; - GSList *result = NULL; - - for (i = 0; i != 100; ++i) { - GInputVector *msg_data = g_new (GInputVector, 1); - gsize msg_size = g_rand_int_range (randg, 0, G_MAXUINT16); - gsize j; - - msg_data->size = msg_size + sizeof (guint16); - msg_data->buffer = g_malloc (msg_data->size); - *(guint16 *)(msg_data->buffer) = htons (msg_size); - - for (j = 2; j != msg_data->size; ++j) { - ((guint8 *)msg_data->buffer)[j] = g_rand_int(randg); - } - - result = g_slist_append(result, msg_data); - } - - return result; -} - -typedef struct { - GSList *msg_data; - GSList *current_msg; - gsize offset; - guint8 send_buffer[G_MAXUINT16 + sizeof (guint16)]; -} TestSocketPriv; - -static gint -test_socket_recv_messages (NiceSocket *sock, NiceInputMessage *recv_messages, - guint n_recv_messages) { - TestSocketPriv *priv = sock->priv; - guint i; - - for (i = 0; priv->current_msg && i != n_recv_messages; ++i) { - gsize msg_size = g_rand_int_range (randg, 0, G_MAXUINT16) + sizeof (guint16); - gsize j; - - j = sizeof (guint16); - while (priv->current_msg && j < msg_size) { - GInputVector *msg = priv->current_msg->data; - gsize cpylen = MIN (msg->size - priv->offset, msg_size - j); - memcpy (priv->send_buffer + j, (guint8 *)msg->buffer + priv->offset, - cpylen); - priv->offset += cpylen; - j += cpylen; - - if (priv->offset == msg->size) { - priv->current_msg = priv->current_msg->next; - priv->offset = 0; - } - } - - msg_size = j; - *(guint16 *)(priv->send_buffer) = htons (msg_size - sizeof (guint16)); - - memcpy_buffer_to_input_message (&recv_messages[i], priv->send_buffer, msg_size); - nice_address_set_from_string (recv_messages[i].from, "127.0.0.1"); - } - - return i; -} - -static gboolean -test_socket_is_reliable (NiceSocket *sock) { - return TRUE; -} - -static void -test_socket_close (NiceSocket *sock) { - g_free (sock->priv); -} - -static NiceSocket * -test_socket_new (GSList *msg_data) -{ - NiceSocket *sock = g_slice_new0 (NiceSocket); - TestSocketPriv *priv = g_new0 (TestSocketPriv, 1); - priv->msg_data = msg_data; - priv->current_msg = msg_data; - priv->offset = 0; - - sock->type = NICE_SOCKET_TYPE_UDP_TURN_OVER_TCP; - sock->recv_messages = test_socket_recv_messages; - sock->is_reliable = test_socket_is_reliable; - sock->close = test_socket_close; - sock->priv = (void *) priv; - - return sock; -} - -#define N_RECV_MESSAGES 7 - -static void -tcp_turn_fragmentation (void) -{ - /* Generate some RFC4571-framed test messages. A dummy base socket will split - * them randomly into TCP-TURN messages. Test that tcp-turn socket can - * correctly extract and reassemble the original test data out of the TURN - * messages. */ - GSList *test_messages = generate_test_messages (); - NiceAddress addr; - NiceSocket *turnsock; - NiceSocket *testsock; - - NiceInputMessage recv_messages[N_RECV_MESSAGES]; - GInputVector recv_vectors[N_RECV_MESSAGES]; - NiceAddress recv_addr[N_RECV_MESSAGES]; - guint8 recv_buffers[N_RECV_MESSAGES][G_MAXUINT16 + sizeof (guint16)]; - - gint n_messages; - guint i; - GSList *li; - - for (i = 0; i != N_RECV_MESSAGES; ++i) { - recv_messages[i].buffers = &recv_vectors[i]; - recv_messages[i].from = &recv_addr[i]; - recv_messages[i].n_buffers = 1; - recv_messages[i].length = 0; - recv_vectors[i].buffer = &recv_buffers[i]; - recv_vectors[i].size = sizeof (recv_buffers[i]); - } - - nice_address_set_from_string (&addr, "127.0.0.1"); - - testsock = test_socket_new (test_messages); - - turnsock = nice_udp_turn_socket_new (NULL, &addr, - testsock, &addr, "", "", - NICE_TURN_SOCKET_COMPATIBILITY_OC2007); - - li = test_messages; - while (li) { - n_messages = nice_socket_recv_messages (turnsock, recv_messages, - N_RECV_MESSAGES); - - for (i = 0; i != (guint)n_messages; ++i) { - NiceInputMessage *message = &recv_messages[i]; - GInputVector *vec = li->data; - if (message->length == 0) { - continue; - } - g_assert_cmpint (message->length, ==, vec->size); - g_assert_cmpmem (message->buffers->buffer, message->length, - vec->buffer, message->length); - - li = li->next; - } - } - - for (li = test_messages; li; li = li->next) { - GInputVector *v = li->data; - g_free (v->buffer); - g_free (v); - } - g_slist_free (test_messages); - - nice_socket_free (turnsock); - nice_socket_free (testsock); -} - -int -main (int argc, char *argv[]) -{ - GMainLoop *mainloop; - - g_networking_init (); - - randg = g_rand_new(); - g_test_init (&argc, &argv, NULL); - - mainloop = g_main_loop_new (NULL, TRUE); - - g_test_add_func ("/udp-turn/tcp-fragmentation", tcp_turn_fragmentation); - - g_test_run (); - - g_rand_free(randg); - - g_main_loop_unref (mainloop); - - return 0; -} diff --git a/tests/test.c b/tests/test.c deleted file mode 100644 index b937c79..0000000 --- a/tests/test.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 Nokia Corporation. All rights reserved. - * Contact: Kai Vehmanen - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Nice GLib ICE library. - * - * The Initial Developers of the Original Code are Collabora Ltd and Nokia - * Corporation. All Rights Reserved. - * - * Contributors: - * Dafydd Harries, Collabora Ltd. - * - * Alternatively, the contents of this file may be used under the terms of the - * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which - * case the provisions of LGPL are applicable instead of those above. If you - * wish to allow use of your version of this file only under the terms of the - * LGPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replace - * them with the notice and other provisions required by the LGPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the LGPL. - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "agent.h" -#include "agent-priv.h" - -/* Waits about 10 seconds for @var to be NULL/FALSE */ -#define WAIT_UNTIL_UNSET(var, context) \ - if (var) \ - { \ - int _i; \ - \ - for (_i = 0; _i < 13 && (var); _i++) \ - { \ - g_usleep (1000 * (1 << _i)); \ - g_main_context_iteration (context, FALSE); \ - } \ - \ - g_assert (!(var)); \ - } - -gint -main (void) -{ - NiceAgent *agent; - NiceAddress addr_local, addr_remote; - NiceCandidate *candidate; - GSList *candidates, *i; - guint stream_id; - -#ifdef G_OS_WIN32 - WSADATA w; - - WSAStartup(0x0202, &w); -#endif - - nice_address_init (&addr_local); - nice_address_init (&addr_remote); - - g_assert (nice_address_set_from_string (&addr_local, "127.0.0.1")); - g_assert (nice_address_set_from_string (&addr_remote, "127.0.0.1")); - nice_address_set_port (&addr_remote, 2345); - - agent = nice_agent_new ( NULL, NICE_COMPATIBILITY_RFC5245); - g_object_set (G_OBJECT (agent), "ice-tcp", FALSE, NULL); - - g_assert (agent->local_addresses == NULL); - - /* add one local address */ - nice_agent_add_local_address (agent, &addr_local); - - g_assert (agent->local_addresses != NULL); - g_assert_cmpuint (g_slist_length (agent->local_addresses), ==, 1); - g_assert (nice_address_equal (agent->local_addresses->data, &addr_local)); - - /* add a stream */ - stream_id = nice_agent_add_stream (agent, 1); - nice_agent_gather_candidates (agent, stream_id); - - /* adding a stream should cause host candidates to be generated */ - candidates = nice_agent_get_local_candidates (agent, stream_id, 1); - g_assert_cmpuint (g_slist_length (candidates), ==, 1); - candidate = candidates->data; - /* socket manager uses random port number */ - nice_address_set_port (&addr_local, 1); - nice_address_set_port (&(candidate->addr), 1); - g_assert (nice_address_equal (&(candidate->addr), &addr_local)); - g_assert (strncmp (candidate->foundation, "1", 1) == 0); - for (i = candidates; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (candidates); - - /* clean up */ - nice_agent_remove_stream (agent, stream_id); - - g_object_add_weak_pointer (G_OBJECT (agent), (gpointer *) &agent); - g_object_unref (agent); - WAIT_UNTIL_UNSET (agent, NULL); - -#ifdef G_OS_WIN32 - WSACleanup(); -#endif - return 0; -} - -- 2.7.4