From: Sangchul Lee Date: Thu, 17 Feb 2022 04:05:23 +0000 (+0900) Subject: Initialize git X-Git-Tag: upstream/0.1.18~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=251d751518b214655c12d8d1b6ce370a75854af9;p=platform%2Fupstream%2Flibnice.git Initialize git Signed-off-by: Sangchul Lee --- 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 ba23739..0000000 Binary files a/docs/reference/libnice/states.png and /dev/null differ 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; -} -