+++ /dev/null
-*.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/
+++ /dev/null
-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/
+++ /dev/null
-Dafydd Harries <dafydd.harries@collabora.co.uk>
-Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
-Kai Vehmanen <kai.vehmanen@nokia.com>
-Youness Alaoui <youness.alaoui@collabora.co.uk>
+++ /dev/null
-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.
+++ /dev/null
-
- 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.
-\f
- 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.
-\f
- 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.
-\f
- 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.
-\f
- 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.
-\f
- 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.
-\f
- 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.
-\f
- 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.
-\f
- 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
-\f
- 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.
-
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
-
-
+++ /dev/null
- 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.]
-
+++ /dev/null
-#
-# 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
+++ /dev/null
-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.
+++ /dev/null
-
-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
-
-
+++ /dev/null
-- 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.
+++ /dev/null
-#
-# 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 <glib-object.h>\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 <config.h>\n#include <glib-object.h>\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
+++ /dev/null
-/*
- * 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 <string.h>
-
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#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);
- }
-}
+++ /dev/null
-/*
- * 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 <glib.h>
-
-#ifdef G_OS_WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#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
- *
- <note>
- <para>
- This function will reset the port to 0, so make sure you call it before
- nice_address_set_port()
- </para>
- </note>
- */
-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
- *
- <note>
- <para>
- This function will reset the port to 0, so make sure you call it before
- nice_address_set_port()
- </para>
- </note>
- */
-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__ */
-
+++ /dev/null
-/*
- * 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 <config.h>
-#else
-#define NICEAPI_EXPORT
-#endif
-
-#include <glib.h>
-
-#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 <libgupnp-igd/gupnp-simple-igd-thread.h>
-#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 */
+++ /dev/null
-/*
- * 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 <config.h>
-#else
-#define NICEAPI_EXPORT
-#endif
-
-#include <glib.h>
-#include <gobject/gvaluecollector.h>
-
-#include <string.h>
-#include <errno.h>
-
-#ifndef G_OS_WIN32
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#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.
- * <para> See also: #NiceCompatibility</para>
- */
- 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.
- * <para> See also: #NiceNominationMode </para>
- *
- * 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.
- * <para>
- * This option should be set before gathering candidates and should not be
- * modified afterwards.
- * </para>
- * 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.
- * <para>
- * This option should be set before gathering candidates and should not be
- * modified afterwards.
- * </para>
- * 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.
- * <note>
- <para>
- ICE-TCP is only supported for %NICE_COMPATIBILITY_RFC5245,
- %NICE_COMPATIBILITY_OC2007 and %NICE_COMPATIBILITY_OC2007R2 compatibility
- modes.
- </para>
- * </note>
- *
- * 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.
- * <para>
- * In reliable mode, this property will always return %TRUE in the
- * %NICE_COMPATIBILITY_GOOGLE compatibility mode.
- * </para>
- * 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.
- * <para>
- * This property is currently read-only, and will become read/write once
- * bytestream mode will be supported.
- * </para>
- *
- * 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/*<NiceAgent>*/ 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;
-}
+++ /dev/null
-/*
- * 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.
- *
- * <example>
- * <title>Simple example on how to use libnice</title>
- * <programlisting>
- * 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);
- *
- * </programlisting>
- * </example>
- *
- * Refer to the examples in the examples/ subdirectory of the libnice source for
- * more complete examples.
- *
- */
-
-
-#include <glib-object.h>
-#include <gio/gio.h>
-
-/**
- * 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.
- * <para> See also: #NiceAgent::component-state-changed </para>
- */
-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>
- <title>Example of use.</title>
- <programlisting>
- nice_agent_send (agent, stream_id, NICE_COMPONENT_TYPE_RTP, len, buf);
- </programlisting>
- </example>
- */
-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()
- *
- * <warning>@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 </warning>
- <note>
- <para>
- 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.
- </para>
- </note>
- *
- */
-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.
- * <para> See also: #NiceAgent:proxy-type </para>
- *
- * 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()
- * <para> See also: #NiceAgent::reliable-transport-writable </para>
- *
- * 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()
- * <para> See also: #NiceNominationMode and #NiceAgentOption</para>
- *
- * 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.
- * <para>
- * Since 0.0.5, if this method is not called, libnice will automatically
- * discover the local addresses available
- * </para>
- *
- * 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.
- * <para>
- * If a local host candidate cannot be created on that port
- * range, then the nice_agent_gather_candidates() call will fail.
- * </para>
- * <para>
- * This MUST be called before nice_agent_gather_candidates()
- * </para>
- *
- */
-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.
- *
- * <para>See also: nice_agent_add_local_address()</para>
- * <para>See also: nice_agent_set_port_range()</para>
- *
- * Returns: %FALSE if the stream ID is invalid or if a host candidate couldn't
- * be allocated on the requested interfaces/ports; %TRUE otherwise
- *
- <note>
- <para>
- Local addresses can be previously set with nice_agent_add_local_address()
- </para>
- <para>
- 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()
- </para>
- </note>
- */
-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.
- *
- <note>
- <para>
- Stream credentials do not override per-candidate credentials if set
- </para>
- <para>
- 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.
- </para>
- </note>
- *
- * 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.
- *
- <note>
- <para>
- This is only effective before ICE negotiation has started.
- </para>
- </note>
- *
- * 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.
- *
- <note>
- <para>
- NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute maximum limit
- for remote candidates.
- </para>
- <para>
- You must first call nice_agent_gather_candidates() and wait for the
- #NiceAgent::candidate-gathering-done signale before
- calling nice_agent_set_remote_candidates()
- </para>
- <para>
- 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.
- </para>
- </note>
- *
- * 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.
- *
- <note>
- <para>
- 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
- </para>
- <para>
- 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.
- </para>
- <para>
- 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.
- </para>
- <para>
- In both reliable and non-reliable mode, a -1 error code could also mean that
- the stream_id and/or component_id are invalid.
- </para>
-</note>
- *
- * 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
- *
- <note>
- <para>
- 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.
- </para>
- </note>
- *
- * 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
- *
- <note>
- <para>
- The caller owns the returned GSList as well as the candidates contained
- within it.
- </para>
- <para>
- 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.
- </para>
- </note>
- *
- * 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.
- * <para>
- * The SOFTWARE attribute will only be added in the #NICE_COMPATIBILITY_RFC5245
- * and #NICE_COMPATIBILITY_WLM2009 compatibility modes.
- *
- * </para>
- * <note>
- <para>
- The @software argument will be appended with the libnice version before
- being sent.
- </para>
- <para>
- The @software argument must be in UTF-8 encoding and only the first
- 128 characters will be sent.
- </para>
- </note>
- *
- * 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.
- *
- * <para>See also: nice_agent_generate_local_sdp()</para>
- * <para>See also: nice_agent_parse_remote_sdp()</para>
- * <para>See also: nice_agent_get_stream_name()</para>
- *
- * 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.
-
- * <para>See also: nice_agent_set_stream_name()</para>
- *
- * 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.
- * <note>
- <para>
- This function is only useful in order to manually generate the
- local SDP
- </para>
- * </note>
- *
- * 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.
- *
- <note>
- <para>
- The SDP will not contain any codec lines and the 'm' line will not list
- any payload types.
- </para>
- <para>
- 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.
- </para>
- <para>
- The default candidate in the SDP will be selected based on the lowest
- priority candidate for the first component.
- </para>
- </note>
- *
- * <para>See also: nice_agent_set_stream_name() </para>
- * <para>See also: nice_agent_parse_remote_sdp() </para>
- * <para>See also: nice_agent_generate_local_stream_sdp() </para>
- * <para>See also: nice_agent_generate_local_candidate_sdp() </para>
- * <para>See also: nice_agent_get_default_local_candidate() </para>
- *
- * 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.
- *
- <note>
- <para>
- The SDP will not contain any codec lines and the 'm' line will not list
- any payload types.
- </para>
- <para>
- 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.
- </para>
- <para>
- The default candidate in the SDP will be selected based on the lowest
- priority candidate.
- </para>
- </note>
- *
- * <para>See also: nice_agent_set_stream_name() </para>
- * <para>See also: nice_agent_parse_remote_stream_sdp() </para>
- * <para>See also: nice_agent_generate_local_sdp() </para>
- * <para>See also: nice_agent_generate_local_candidate_sdp() </para>
- * <para>See also: nice_agent_get_default_local_candidate() </para>
- *
- * 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.
- *
- * <para>See also: nice_agent_parse_remote_candidate_sdp() </para>
- * <para>See also: nice_agent_generate_local_sdp() </para>
- * <para>See also: nice_agent_generate_local_stream_sdp() </para>
- *
- * 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.
- *
- * <para>See also: nice_agent_set_stream_name() </para>
- * <para>See also: nice_agent_generate_local_sdp() </para>
- * <para>See also: nice_agent_parse_remote_stream_sdp() </para>
- * <para>See also: nice_agent_parse_remote_candidate_sdp() </para>
- *
- * 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.
- *
- * <para>See also: nice_agent_generate_local_stream_sdp() </para>
- * <para>See also: nice_agent_parse_remote_sdp() </para>
- * <para>See also: nice_agent_parse_remote_candidate_sdp() </para>
- *
- * 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.
- *
- * <para>See also: nice_agent_generate_local_candidate_sdp() </para>
- * <para>See also: nice_agent_parse_remote_sdp() </para>
- * <para>See also: nice_agent_parse_remote_stream_sdp() </para>
- *
- * 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__ */
+++ /dev/null
-/*
- * 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 <config.h>
-#else
-#define NICEAPI_EXPORT
-#endif
-
-#include <string.h>
-
-#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: <unused>
- * 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/*<owned gchar*>*/ *ips = NULL;
- GList/*<unowned gchar*>*/ *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));
-}
+++ /dev/null
-/*
- * 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 <glib.h>
-#include <glib-object.h>
-
-
-/**
- * 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 <emphasis> see note </emphasis>
- * @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
- <note>
- <para>
- 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.
- </para>
- </note>
- */
-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__ */
-
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <string.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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 <glib.h>
-
-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 */
-
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <errno.h>
-#include <string.h>
-
-#include <glib.h>
-
-#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;
- }
-}
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <string.h>
-
-#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
+++ /dev/null
-/*
- * 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
- *
- * <para>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.</para>
- *
- * <para>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.</para>
- *
- * <para>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.</para>
- * <para> The currently available flags are "nice", "stun", "pseudotcp",
- * "pseudotcp-verbose" or "all" to enable all debug messages.</para>
- * <para> 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.</para>
- *
- *
- * <para>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.</para>
- */
-
-
-#include <glib.h>
-
-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__ */
-
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <glib.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#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);
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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 <errno.h>
-
-#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/*<NiceAgent>*/ 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;
- }
- }
-}
+++ /dev/null
-/*
- * 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 <glib-object.h>
-#include <gio/gio.h>
-#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__ */
+++ /dev/null
-/*
- * interfaces.c - Source for interface discovery code
- *
- * Copyright (C) 2006 Youness Alaoui <kakaroto@kakaroto.homelinux.net>
- * Copyright (C) 2007 Collabora, Nokia
- * Contact: Youness Alaoui
- * Copyright (C) 2008 Haakon Sporsheim <haakon.sporsheim@tandberg.com>
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-
-#ifdef __sun
-#include <sys/sockio.h>
-#endif
-
-#ifdef HAVE_GETIFADDRS
- #include <ifaddrs.h>
-#endif
-
-#include <net/if.h>
-#include <arpa/inet.h>
-
-#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 <winsock2.h>
-#include <iphlpapi.h>
-
-// 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 */
+++ /dev/null
-/*
- * interfaces.h - Source for interface discovery code
- *
- * Farsight Helper functions
- * Copyright (C) 2006 Youness Alaoui <kakaroto@kakaroto.homelinux.net>
- * 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 <glib.h>
-
-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__ */
+++ /dev/null
-/*
- * 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/*<NiceAgent>*/ 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;
- }
- }
-}
+++ /dev/null
-/*
- * 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 <glib-object.h>
-#include <gio/gio.h>
-
-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__ */
+++ /dev/null
-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 <config.h>\n#include <glib-object.h>\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 <glib-object.h>\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)
+++ /dev/null
-/*
- * 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 <errno.h>
-
-#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/*<NiceAgent>*/ 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;
- }
- }
-}
+++ /dev/null
-/*
- * 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 <glib-object.h>
-#include <gio/gio.h>
-#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__ */
+++ /dev/null
-/*
- * 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 <stdlib.h>
-#include <errno.h>
-#include <string.h>
-
-#include <glib.h>
-
-#ifndef G_OS_WIN32
-# include <arpa/inet.h>
-#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 <CONV=%u><FLG=%u><SEQ=%u:%u><ACK=%u>"
- "<WND=%u><TS=%u><TSR=%u><LEN=%u>",
- 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 <CONV=%u><FLG=%u><SEQ=%u:%u><ACK=%u>"
- "<WND=%u><TS=%u><TSR=%u><LEN=%u>",
- 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);
-}
+++ /dev/null
-/*
- * 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 <glib-object.h>
-
-#ifndef __GTK_DOC_IGNORE__
-#ifdef G_OS_WIN32
-# include <winsock2.h>
-
-#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.
- * <para> See also: #PseudoTcpSocket:state </para>
- *
- * 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.
- * <para> See also: %PseudoTcpCallbacks:WritePacket </para>
- *
- * 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.
- * <para> See also: #PseudoTcpWriteResult </para>
- *
- * 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
- *
- <note>
- <para>
- The @callbacks must be non-NULL, in order to get notified of packets the
- socket needs to send.
- </para>
- <para>
- If the @callbacks structure was dynamicly allocated, it can be freed
- after the call @pseudo_tcp_socket_new
- </para>
- </note>
- *
- * 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)
- * <para> See also: pseudo_tcp_socket_get_error() </para>
- *
- * 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.
- *
- <note>
- <para>
- Only call this on the %PseudoTcpCallbacks:PseudoTcpReadable callback.
- </para>
- <para>
- 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.
- </para>
- </note>
- *
- * Returns: The number of bytes received or -1 in case of error
- * <para> See also: pseudo_tcp_socket_get_error() </para>
- *
- * 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.
- *
- <note>
- <para>
- 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.
- </para>
- </note>
- *
- * Returns: The number of bytes sent or -1 in case of error
- * <para> See also: pseudo_tcp_socket_get_error() </para>
- *
- * 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.
- *
- <note>
- <para>
- 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.
- </para>
- </note>
- *
- * <para> See also: pseudo_tcp_socket_get_next_clock() </para>
- *
- * 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.
- *
- <note>
- <para>
- The return value can be :
- <para>
- EINVAL (for pseudo_tcp_socket_connect()).
- </para>
- <para>
- EWOULDBLOCK or ENOTCONN (for pseudo_tcp_socket_recv() and
- pseudo_tcp_socket_send()).
- </para>
- </para>
- </note>
- *
- * Returns: The error code
- * <para> See also: pseudo_tcp_socket_connect() </para>
- * <para> See also: pseudo_tcp_socket_recv() </para>
- * <para> See also: pseudo_tcp_socket_send() </para>
- *
- * 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.
- *
- * <para> See also: pseudo_tcp_socket_notify_clock() </para>
- *
- * 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.
- *
- * <para> See also: pseudo_tcp_socket_get_next_clock() </para>
- *
- * 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__ */
-
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <string.h>
-
-#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);
-}
+++ /dev/null
-/*
- * 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 <glib.h>
-
-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 */
-
+++ /dev/null
-#!/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
+++ /dev/null
-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
+++ /dev/null
-
-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
-
+++ /dev/null
-
-SUBDIRS = reference
-
-EXTRA_DIST = design.txt
+++ /dev/null
-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.
+++ /dev/null
-
-SUBDIRS = libnice
+++ /dev/null
-## 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
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
-<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
- <bookinfo>
- <title>libnice Reference Manual</title>
- <releaseinfo>
- The latest version of this documentation can be found on-line at
- <ulink role="online-location" url="http://nice.freedesktop.org/libnice/index.html">http://nice.freedesktop.org/libnice/</ulink>.
- </releaseinfo>
- </bookinfo>
-
-
- <part>
- <title>ICE Library</title>
- <chapter>
- <xi:include href="xml/agent.xml"/>
- <xi:include href="xml/address.xml"/>
- <xi:include href="xml/candidate.xml"/>
- </chapter>
- <chapter>
- <title>Libnice helper functions</title>
- <xi:include href="xml/debug.xml"/>
- <xi:include href="xml/interfaces.xml"/>
- </chapter>
- </part>
- <part>
- <title>STUN Library</title>
- <chapter>
- <xi:include href="xml/stunagent.xml"/>
- <xi:include href="xml/stunmessage.xml"/>
- <xi:include href="xml/stunconstants.xml"/>
- </chapter>
- <chapter>
- <title>STUN usages</title>
- <xi:include href="xml/bind.xml"/>
- <xi:include href="xml/ice.xml"/>
- <xi:include href="xml/turn.xml"/>
- <xi:include href="xml/timer.xml"/>
- </chapter>
- </part>
-
- <part>
- <title>Pseudo TCP Socket implementation</title>
- <chapter>
- <xi:include href="xml/pseudotcp.xml"/>
- </chapter>
- </part>
-
- <para>The libnice library contains the ICE library and the
- STUN library as well as a Pseudo TCP socket implementation.
- </para>
-
- <part>
- <title>Appendices</title>
- <index id="api-index-full">
- <title>API Index</title>
- <xi:include href="xml/api-index-full.xml"><xi:fallback/></xi:include>
- </index>
- <index id="api-index-deprecated">
- <title>Index of deprecated symbols</title>
- <xi:include href="xml/api-index-deprecated.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.0.4">
- <title>Index of new symbols in 0.0.4</title>
- <xi:include href="xml/api-index-0.0.4.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.0.6">
- <title>Index of new symbols in 0.0.6</title>
- <xi:include href="xml/api-index-0.0.6.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.0.7">
- <title>Index of new symbols in 0.0.7</title>
- <xi:include href="xml/api-index-0.0.7.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.0.9">
- <title>Index of new symbols in 0.0.9</title>
- <xi:include href="xml/api-index-0.0.9.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.0.10">
- <title>Index of new symbols in 0.0.10</title>
- <xi:include href="xml/api-index-0.0.10.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.0.11">
- <title>Index of new symbols in 0.0.11</title>
- <xi:include href="xml/api-index-0.0.11.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.1.4">
- <title>Index of new symbols in 0.1.4</title>
- <xi:include href="xml/api-index-0.1.4.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.1.5">
- <title>Index of new symbols in 0.1.5</title>
- <xi:include href="xml/api-index-0.1.5.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.1.6">
- <title>Index of new symbols in 0.1.6</title>
- <xi:include href="xml/api-index-0.1.6.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.1.8">
- <title>Index of new symbols in 0.1.8</title>
- <xi:include href="xml/api-index-0.1.8.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.1.14">
- <title>Index of new symbols in 0.1.14</title>
- <xi:include href="xml/api-index-0.1.14.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.1.15">
- <title>Index of new symbols in 0.1.15</title>
- <xi:include href="xml/api-index-0.1.15.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.1.16">
- <title>Index of new symbols in 0.1.16</title>
- <xi:include href="xml/api-index-0.1.16.xml"><xi:fallback/></xi:include>
- </index>
- <index role="0.1.17">
- <title>Index of new symbols in 0.1.17</title>
- <xi:include href="xml/api-index-0.1.17.xml"><xi:fallback/></xi:include>
- </index>
- <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
- </part>
-</book>
+++ /dev/null
-<SECTION>
-<FILE>agent</FILE>
-<TITLE>NiceAgent</TITLE>
-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
-<SUBSECTION Standard>
-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
-<SUBSECTION Private>
-NiceAgentClass
-</SECTION>
-
-<SECTION>
-<FILE>candidate</FILE>
-<TITLE>NiceCandidate</TITLE>
-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
-<SUBSECTION Standard>
-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
-<SUBSECTION Private>
-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
-</SECTION>
-
-<SECTION>
-<FILE>address</FILE>
-<TITLE>NiceAddress</TITLE>
-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
-</SECTION>
-
-
-<SECTION>
-<FILE>debug</FILE>
-<TITLE>Debug messages</TITLE>
-nice_debug_enable
-nice_debug_disable
-</SECTION>
-
-<SECTION>
-<FILE>interfaces</FILE>
-<TITLE>Network interfaces discovery</TITLE>
-nice_interfaces_get_ip_for_interface
-nice_interfaces_get_local_interfaces
-nice_interfaces_get_local_ips
-</SECTION>
-
-<SECTION>
-<FILE>stunagent</FILE>
-<TITLE>StunAgent</TITLE>
-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
-<SUBSECTION Private>
-StunAgentSavedIds
-stun_debug
-stun_debug_bytes
-stun_agent_t
-</SECTION>
-
-
-<SECTION>
-<FILE>stunmessage</FILE>
-<TITLE>StunMessage</TITLE>
-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
-</SECTION>
-
-<SECTION>
-<FILE>stunconstants</FILE>
-<TITLE>STUN Constants</TITLE>
-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
-</SECTION>
-
-<SECTION>
-<FILE>turn</FILE>
-<TITLE>TURN</TITLE>
-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
-</SECTION>
-
-<SECTION>
-<FILE>ice</FILE>
-<TITLE>ICE</TITLE>
-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
-</SECTION>
-
-<SECTION>
-<FILE>timer</FILE>
-<TITLE>Timer</TITLE>
-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
-<SUBSECTION Private>
-stun_timer_s
-</SECTION>
-
-<SECTION>
-<FILE>bind</FILE>
-<TITLE>Bind</TITLE>
-StunUsageBindReturn
-stun_usage_bind_create
-stun_usage_bind_process
-stun_usage_bind_keepalive
-stun_usage_bind_run
-</SECTION>
-
-<SECTION>
-<FILE>pseudotcp</FILE>
-<TITLE>Pseudo TCP Socket</TITLE>
-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
-<SUBSECTION Standard>
-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
-<SUBSECTION Private>
-PseudoTcpSocketPrivate
-ECONNRESET
-EMSGSIZE
-ENOTCONN
-ETIMEDOUT
-EWOULDBLOCK
-</SECTION>
+++ /dev/null
-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')])
+++ /dev/null
-/* 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 ];
-}
+++ /dev/null
-#
-# 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
+++ /dev/null
-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
+++ /dev/null
-/*
- * 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-
-#include <agent.h>
-
-#include <gio/gnetworking.h>
-
-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);
-}
+++ /dev/null
-/*
- * 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-
-#include <agent.h>
-
-#include <gio/gnetworking.h>
-
-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;
-}
+++ /dev/null
-/*
- * 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-
-#include <agent.h>
-
-#include <gio/gnetworking.h>
-
-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;
-}
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
- * 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/");
-
+++ /dev/null
-/*
- * 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"
-
+++ /dev/null
-
-/*
- * 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 <dafydd.harries@collabora.co.uk>");
-
-
- 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 <tim@centricular.com>
- * 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;
-}
+++ /dev/null
-/*
- * 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 <gst/gst.h>
-#include <gst/base/gstbasesink.h>
-
-#include <nice/nice.h>
-
-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
+++ /dev/null
-/*
- * 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 <string.h>
-
-#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 <dafydd.harries@collabora.co.uk>");
-
- 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;
-}
-
-
+++ /dev/null
-/*
- * 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 <gst/gst.h>
-#include <gst/base/gstpushsrc.h>
-
-#include <nice/nice.h>
-
-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
-
+++ /dev/null
-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
+++ /dev/null
-dnl as-compiler-flag.m4 0.1.0
-
-dnl autostars m4 macro for detection of compiler flags
-
-dnl David Schleef <ds@schleef.org>
-dnl Tim-Philipp Müller <tim centricular net>
-
-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])
-])
-
+++ /dev/null
-# ===========================================================================
-# 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 <openssl/hmac.h>
-#
-# LICENSE
-#
-# Copyright (c) 2009,2010 Zmanda Inc. <http://www.zmanda.com/>
-# Copyright (c) 2009,2010 Dustin J. Mitchell <dustin@zmanda.com>
-#
-# 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 <openssl/foo.h>, 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 <openssl/ssl.h>], [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])
-])
+++ /dev/null
-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])
-])
+++ /dev/null
-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)
+++ /dev/null
-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')
+++ /dev/null
-#
-# 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
-
+++ /dev/null
-#!/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()
+++ /dev/null
-#!/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()
+++ /dev/null
-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
+++ /dev/null
-
-libnice {
-global:
- nice_*;
-};
-
-HIDDEN {
-local:
- *;
-};
-
+++ /dev/null
-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)])
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-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}
+++ /dev/null
-#!/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
+++ /dev/null
-#
-# 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
+++ /dev/null
-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
+++ /dev/null
-/*
- * 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;
-}
-
+++ /dev/null
-/*
- * 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 <glib.h>
-
-#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 */
-
+++ /dev/null
-/*
- * 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 <string.h>
-
-#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))];
-}
-
+++ /dev/null
-/*
- * 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 <glib.h>
-
-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
-
+++ /dev/null
-/*
- * 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 <string.h>
-
-#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;
-}
-
+++ /dev/null
-#!/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
-
+++ /dev/null
-
-# 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
-
+++ /dev/null
-#!/bin/sh
-make -f scripts/lcov.mk lcov-clean && \
-make -f scripts/lcov.mk lcov-build && \
-make -f scripts/lcov.mk lcov-report
+++ /dev/null
-#!/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
+++ /dev/null
-#! /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 <http://www.gnu.org/licenses/>.
-
-# 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 <bug-automake@gnu.org> or send patches to
-# <automake-patches@gnu.org>.
-
-# 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 <<END
-Usage:
- test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
- [--expect-failure={yes|no}] [--color-tests={yes|no}]
- [--enable-hard-errors={yes|no}] [--]
- TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
-The '--test-name', '--log-file' and '--trs-file' options are mandatory.
-END
-}
-
-test_name= # Used for reporting.
-log_file= # Where to save the output of the test script.
-trs_file= # Where to save the metadata of the test run.
-expect_failure=no
-color_tests=no
-enable_hard_errors=yes
-while test $# -gt 0; do
- case $1 in
- --help) print_usage; exit $?;;
- --version) echo "test-driver $scriptversion"; exit $?;;
- --test-name) test_name=$2; shift;;
- --log-file) log_file=$2; shift;;
- --trs-file) trs_file=$2; shift;;
- --color-tests) color_tests=$2; shift;;
- --expect-failure) expect_failure=$2; shift;;
- --enable-hard-errors) enable_hard_errors=$2; shift;;
- --) shift; break;;
- -*) usage_error "invalid option: '$1'";;
- *) break;;
- esac
- shift
-done
-
-missing_opts=
-test x"$test_name" = x && missing_opts="$missing_opts --test-name"
-test x"$log_file" = x && missing_opts="$missing_opts --log-file"
-test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
-if test x"$missing_opts" != x; then
- usage_error "the following mandatory options are missing:$missing_opts"
-fi
-
-if test $# -eq 0; then
- usage_error "missing argument"
-fi
-
-if test $color_tests = yes; then
- # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
- red='\e[0;31m' # Red.
- grn='\e[0;32m' # Green.
- lgn='\e[1;32m' # Light green.
- blu='\e[1;34m' # Blue.
- mgn='\e[0;35m' # Magenta.
- std='\e[m' # No color.
-else
- red= grn= lgn= blu= mgn= std=
-fi
-
-do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
-trap "st=129; $do_exit" 1
-trap "st=130; $do_exit" 2
-trap "st=141; $do_exit" 13
-trap "st=143; $do_exit" 15
-
-# Test script is run here.
-top_srcdir="`dirname $0`/.."
-tests_dir="${top_srcdir}/tests"
-
-USE_VALGRIND="`printenv USE_VALGRIND`"
-
-if test "x${USE_VALGRIND}" = "x1"; then
- ${top_srcdir}/libtool --mode=execute valgrind \
- --leak-check=full \
- --show-reachable=no \
- --error-exitcode=1 \
- --suppressions=$tests_dir/libnice.supp \
- --num-callers=30 "$@" >$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:
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
- * 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 <string.h>
-#include <stdlib.h>
-
-
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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));
-}
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-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)
+++ /dev/null
-/*
- * 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 <string.h>
-
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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));
-}
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-/*
- * 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 <glib.h>
-
-#include "socket.h"
-#include "socket-priv.h"
-#include "agent-priv.h"
-
-#include <string.h>
-
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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);
-}
+++ /dev/null
-/*
- * 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 <gio/gio.h>
-
-#ifdef G_OS_WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#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 */
-
+++ /dev/null
-/*
- * 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 <string.h>
-
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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));
-}
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-/*
- * 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 <string.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-/*
- * 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 <string.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-/*
- * 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 <string.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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);
-}
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-/*
- * 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 <string.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include "udp-bsd.h"
-#include "agent-priv.h"
-
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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)
-{
-}
-
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-/*
- * 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 <string.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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));
-}
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-/*
- * 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 <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-
-#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);
- }
-}
+++ /dev/null
-/*
- * 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 */
-
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#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;
-}
-
+++ /dev/null
-/*
- * 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 <stddef.h>
-#include <stdarg.h>
-
-#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 */
+++ /dev/null
-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
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "rand.h"
-
-
-#ifdef _WIN32
-
-#include <windows.h>
-#include <wincrypt.h>
-
-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 <openssl/rand.h>
-
-void nice_RAND_nonce (uint8_t *dst, int len)
-{
- RAND_bytes (dst, len);
-}
-
-#else
-
-#include <sys/types.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/crypto.h>
-
-void nice_RAND_nonce (uint8_t *dst, int len)
-{
- gnutls_rnd (GNUTLS_RND_NONCE, dst, len);
-}
-
-#endif /* HAVE_OPENSSL */
-
-#endif /* _WIN32 */
+++ /dev/null
-/*
- * 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 <stdint.h>
-#endif
-
-void nice_RAND_nonce (uint8_t *dst, int len);
-
-#endif /* RAND_H */
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <sys/socket.h>
-#include <netinet/in.h> /* htons() */
-#endif
-
-#include <string.h>
-#include <stdlib.h>
-
-#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);
-}
+++ /dev/null
-/*
- * 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 <stdint.h>
-# include <stdbool.h>
-#endif
-# include <sys/types.h>
-
-#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 <b>host</b> 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 */
-
+++ /dev/null
-/*
- * 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 "stunmessage.h"
-#include "stunagent.h"
-#include "stunhmac.h"
-#include "stun5389.h"
-#include "utils.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-
-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;
-}
+++ /dev/null
-/*
- * 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 <stdint.h>
-#endif
-
-#include <stdbool.h>
-#include <sys/types.h>
-
-/**
- * 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
- *
- * <warning>@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.</warning>
- */
-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.
- * <para> See also: stun_agent_init() </para>
- * <para> See also: stun_agent_validate() </para>
- */
-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.
- * <para> See also: stun_agent_default_validater() </para>
- */
-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.
- * <para> See also: stun_agent_validate() </para>
- * 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
- * <para> See also: stun_agent_validate() </para>
- * 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.
- *
- <note>
- <para>
- The @known_attributes data must exist in memory as long as the @agent is used
- </para>
- <para>
- 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
- </para>
- <para>
- 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
- </para>
- </note>
- */
-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.
- * <para> See also: stun_agent_default_validater() </para>
- * Returns: A #StunValidationStatus
- <note>
- <para>
- 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.
- </para>
- </note>
- */
-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.
- * <para>See also: stun_agent_forget_transaction()</para>
- * Returns: The final size of the message built or 0 if an error occured
- * <note>
- <para>
- 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.
- </para>
- <para>
- 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()
- </para>
- </note>
- */
-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.
- * <para>
- * 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.
- * </para>
- * 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.
- * <para>
- * Calling this function will automatically enable the addition of the SOFTWARE
- * attribute for RFC5389 and MSICE2 compatibility modes.
- *
- * </para>
- * <note>
- <para>
- The @software argument must be in UTF-8 encoding and only the first
- 128 characters will be sent.
- </para>
- <para>
- The value of the @software argument must stay valid throughout the life of
- the StunAgent's life. Do not free its content.
- </para>
- </note>
- *
- * Since: 0.0.10
- *
- */
-void stun_agent_set_software (StunAgent *agent, const char *software);
-
-#endif /* _STUN_AGENT_H */
+++ /dev/null
-/*
- * 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 <config.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <stdint.h>
-#endif
-
-#include <stdbool.h>
-#include <stdlib.h>
-
-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 */
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "rand.h"
-
-#include "stunmessage.h"
-#include "stunhmac.h"
-
-#include <string.h>
-#include <assert.h>
-
-#ifdef HAVE_OPENSSL
-#include <openssl/hmac.h>
-#include <openssl/sha.h>
-#else
-#include <gnutls/gnutls.h>
-#include <gnutls/crypto.h>
-#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);
-}
+++ /dev/null
-/*
- * 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 <b>host</b> 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 */
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "stunmessage.h"
-#include "utils.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#endif
-
-
-#include <string.h>
-#include <stdlib.h>
-
-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;
-}
+++ /dev/null
-/*
- * 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 <stdint.h>
-#include <stdbool.h>
-#endif
-
-#include <sys/types.h>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#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
- *
- <note>
- <para>
- The string will be nul-terminated.
- </para>
- </note>
- *
- */
-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.
- * <para> See also: #STUN_MESSAGE_BUFFER_INCOMPLETE </para>
- * <para> See also: #STUN_MESSAGE_BUFFER_INVALID </para>
- */
-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
- * <para> See also: #STUN_MESSAGE_BUFFER_INCOMPLETE </para>
- * <para> See also: #STUN_MESSAGE_BUFFER_INVALID </para>
- *
- * 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 */
+++ /dev/null
-#
-# 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
+++ /dev/null
-#! /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
+++ /dev/null
-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
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <sys/types.h>
-#include "stun/stunagent.h"
-#include "stun/usages/bind.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-
-#define MSG_DONTWAIT 0
-
-#define alarm(...)
-#define close closesocket
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <netdb.h>
-#endif
-
-#undef NDEBUG /* ensure assertions are built-in */
-#include <assert.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <sys/types.h>
-#include "stun/stunagent.h"
-#include "stun/usages/ice.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#define MSG_DONTWAIT 0
-#define MSG_NOSIGNAL 0
-
-#define alarm(...)
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#endif
-
-#undef NDEBUG /* ensure assertions are built-in */
-#include <assert.h>
-
-
-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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <sys/types.h>
-
-#include "stun/stunagent.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <assert.h>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include <stun/stunhmac.h>
-
-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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "stun/stunagent.h"
-#include "stun/stunhmac.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <io.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <sys/types.h>
-#include "stun/stunagent.h"
-#include "stun/usages/turn.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-
-#define MSG_DONTWAIT 0
-#define MSG_NOSIGNAL 0
-
-#define alarm(...)
-#define close closesocket
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <errno.h>
-#endif
-
-#undef NDEBUG /* ensure assertions are built-in */
-#include <assert.h>
-
-
-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;
-}
+++ /dev/null
-#
-# 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
+++ /dev/null
-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)
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#ifdef _WIN32
-# include <winsock2.h>
-#else
-# include <sys/socket.h>
-# include <netdb.h>
-#endif
-
-#include <sys/types.h>
-#include "stun/stunagent.h"
-#include "stun/usages/bind.h"
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-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] <server> [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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#ifdef __sun
-#define _XPG4_2 1
-#endif
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <signal.h>
-
-#include <sys/types.h>
-
-#ifdef _WIN32
-#include <WinSock2.h>
-#else
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#endif
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#else
-# define close(fd) _close(fd)
-#endif
-
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-
-#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;
-}
-
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include "win32_common.h"
-#define close closesocket
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#endif
-
-
-#ifdef HAVE_POLL
-# include <poll.h>
-#endif
-
-
-#include "bind.h"
-#include "stun/stunagent.h"
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include <errno.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <stdbool.h>
-# include <stdint.h>
-#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
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <string.h>
-#include <assert.h>
-#include <stdlib.h>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#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);
-}
-
+++ /dev/null
-
-/*
- * 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
- *
- * <warning>@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.</warning>
- */
-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
- * <para> See also stun_usage_ice_conncheck_priority() and
- * stun_usage_ice_conncheck_use_candidate() </para>
- * 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.
- <note>
- <para>
- 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.
- </para>
- </note>
- * 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
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#else
-#include <unistd.h>
-#endif
-
-#include "timer.h"
-
-#include <stdlib.h> /* 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;
-}
+++ /dev/null
-/*
- * 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.
- *
- *
- <example>
- <title>Simple example on how to use the timer usage</title>
- <programlisting>
- 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
- }
-
- </programlisting>
- </example>
- */
-
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-# include <sys/types.h>
-# include <sys/time.h>
-# include <time.h>
-#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.
- * <para>
- * To determine the total timeout value, one can use the following equation :
- <programlisting>
- total_timeout = initial_timeout * (2^(max_retransmissions + 1) - 1);
- </programlisting>
- * </para>
- *
- * 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 */
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#endif
-
-#include "stun/stunagent.h"
-#include "turn.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
-
-
-#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;
-
-}
+++ /dev/null
-/*
- * 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 <stdbool.h>
-# include <stdint.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#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
- * <para>See #StunUsageTurnRequestPorts </para>
- * @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
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#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;
- }
-}
+++ /dev/null
-/*
- * 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 <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#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 */
+++ /dev/null
-/*
- * 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 <stdint.h>
- * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
- *
- * THIS SOFTWARE IS NOT COPYRIGHTED
- *
- * Contributor: Danny Smith <danny_r_smith_2001@yahoo.co.nz>
- *
- * 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 <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-/* On MSVC, ssize_t is SSIZE_T */
-#ifdef _MSC_VER
-#include <BaseTsd.h>
-#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 */
+++ /dev/null
-[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
+++ /dev/null
-#
-# 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
+++ /dev/null
-#! /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}
+++ /dev/null
-# 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
+++ /dev/null
-# 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
+++ /dev/null
-{
- 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
-
-{
- <tls>
- Memcheck:Leak
- ...
- fun:_dl_allocate_tls
- fun:pthread_create@@*
-}
-
-{
- <tls>
- Memcheck:Leak
- ...
- fun:_dl_allocate_tls
-}
+++ /dev/null
-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)
+++ /dev/null
-/*
- * 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 "agent.h"
-#include "agent-priv.h"
-#include <string.h>
-
-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;
-}
-
+++ /dev/null
-/*
- * 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 <string.h>
-#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;
-}
-
+++ /dev/null
-/*
- * 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 <string.h>
-
-#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;
-}
-
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <string.h>
-
-#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;
-}
-
+++ /dev/null
-/*
- * This file is part of the Nice GLib ICE library.
- *
- * (C) 2015 Rohan Garg <rohan@garg.io>
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" 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 "agent.h"
-#include "agent-priv.h"
-#include <string.h>
-#include <stdio.h>
-
-#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;
-}
+++ /dev/null
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "agent.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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 <olivier.crete@collabora.com>
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" 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 <config.h>
-#endif
-
-#include "agent.h"
-
-#include "socket/socket.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-
-
-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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-#include "agent-priv.h" /* for testing purposes */
-
-#include <stdlib.h>
-#include <string.h>
-#ifdef _WIN32
-#include <io.h>
-#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;
-}
+++ /dev/null
-#include <gio/gio.h>
-
-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 <stund path> <test fullmode path>\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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-
-#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;
-}
+++ /dev/null
-/*
- * 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 <gst/check/gstcheck.h>
-#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)
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-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;
-}
+++ /dev/null
-/*
- * This file is part of the Nice GLib ICE library.
- *
- * (C) 2020 Fabrice Bellet <fabrice@bellet.info>
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" 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 <string.h>
-#include <address.h>
-#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;
-}
-
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-#include "test-io-stream-common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-#include "test-io-stream-common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-#include "test-io-stream-common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-#include "test-io-stream-common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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);
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-
-#include <stdlib.h>
-#include <string.h>
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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);
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-#include "test-io-stream-common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-#include "test-io-stream-common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <glib.h>
-#include <glib-object.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h>
-
-#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;
-}
+++ /dev/null
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <gio/gio.h>
-#include <gio/gnetworking.h>
-#include <agent.h>
-
-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;
-}
+++ /dev/null
-/*
- * 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 "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;
-}
-
+++ /dev/null
-/*
- * 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 <locale.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <arpa/inet.h>
-
-#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/*<owned GBytes>*/ *left_sent; /* owned */
- GQueue/*<owned GBytes>*/ *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=%u><ACK=%u><CTL=%s>", 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/*<owned GBytes>*/ *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/*<owned GBytes>*/ *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/*<owned GBytes>*/ *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/*<owned GBytes>*/ *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/*<owned GBytes>*/ *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/*<owned GBytes>*/ *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/*<owned GBytes>*/ *queue,
- guint32 seq, guint32 ack)
-{
- expect_segment (socket, queue, seq, ack, 0, FLAG_FIN);
-}
-
-static void
-expect_rst (PseudoTcpSocket *socket, GQueue/*<owned GBytes>*/ *queue,
- guint32 seq, guint32 ack)
-{
- expect_segment (socket, queue, seq, ack, 0, FLAG_RST);
-}
-
-static void
-expect_ack (PseudoTcpSocket *socket, GQueue/*<owned GBytes>*/ *queue,
- guint32 seq, guint32 ack)
-{
- expect_segment (socket, queue, seq, ack, 0, FLAG_NONE);
-}
-
-static void
-expect_data (PseudoTcpSocket *socket, GQueue/*<owned GBytes>*/ *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;
-}
+++ /dev/null
-/* 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 <locale.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <math.h>
-
-#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;
-}
+++ /dev/null
-#!/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
+++ /dev/null
-/*
- * 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 <locale.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#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;
-}
-
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-#include "agent-priv.h" /* for testing purposes */
-
-#include <stdlib.h>
-#include <string.h>
-#ifdef _WIN32
-#include <io.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-#include "test-io-stream-common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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;
-}
+++ /dev/null
-/*
- * This file is part of the Nice GLib ICE library.
- *
- * (C) 2016 Jakub Adam <jakub.adam@ktknet.cz>
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" 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 <locale.h>
-#include <gio/gnetworking.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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 <string.h>
-#include <stdio.h>
-#include <gio/gnetworking.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-
-#include <stdlib.h>
-#include <string.h>
-#ifndef G_OS_WIN32
-#include <unistd.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include "agent.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-
-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;
-}
+++ /dev/null
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <gio/gio.h>
-#include <agent.h>
-
-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;
-}
+++ /dev/null
-/*
- * This file is part of the Nice GLib ICE library.
- *
- * (C) 2018 Jakub Adam <jakub.adam@ktknet.cz>
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" 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 <gio/gnetworking.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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 <string.h>
-
-#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;
-}
-